package tirateima.controlador; import java.awt.Point; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Stack; import tirateima.Par; import tirateima.gui.variaveis.Mostrador; import tirateima.gui.variaveis.Seta; import tirateima.gui.variaveis.VarArray; import tirateima.gui.variaveis.VarBoolean; import tirateima.gui.variaveis.VarChar; import tirateima.gui.variaveis.VarInteger; import tirateima.gui.variaveis.VarMatriz; import tirateima.gui.variaveis.VarPointer; import tirateima.gui.variaveis.VarReal; import tirateima.gui.variaveis.VarRecord; import tirateima.gui.variaveis.VarString; import tirateima.gui.variaveis.Variavel; /** * Uma abstração que modela um comando do Tira-Teima. * * @author Luciano Santos */ public abstract class Command { /** * Executa esse comando, alterarndo os estados dos componentes. * * @param c O gerador de estados. * @param steps A lista de estados sendo gerada. * * @throws TiraTeimaLanguageException * @throws ExecutionException */ public abstract void execute(Controlador c) throws TiraTeimaLanguageException, ExecutionException; /** * Reverte o comando executado, quando for necessário para manter * a consistência da visualização. * @param c * @throws TiraTeimaLanguageException * @throws ExecutionException */ public abstract void revert(Controlador c) throws TiraTeimaLanguageException, ExecutionException; /** * Cria uma nova exceção com a mensagem especificada. * * @param msg * * @return A exceção criada. */ protected void gerarErro(String msg) throws TiraTeimaLanguageException { throw new TiraTeimaLanguageException(msg, 0, 0); } /** * Cria uma nova variável, dada uma VarDefinition. * * @param g O gerador. * @param var_def A definição da variável. * * @return A variável criada. * * @throws TiraTeimaLanguageException */ protected Variavel newVar(Controlador c, VarDefinition var_def) throws TiraTeimaLanguageException { Variavel v = null; Index i; /** Cria uma nova variável de acordo com seu tipo */ Type t = var_def.getType(); switch (t.getId()) { case INTEGER: v = new VarInteger(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case REAL: v = new VarReal(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case CHAR: v = new VarChar(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case STRING: v = new VarString(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case BOOLEAN: v = new VarBoolean(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case POINTER: v = new VarPointer(var_def.getName(), var_def.getColor(), var_def.getDimension(), var_def.getPosicao(), var_def.getMostraNome()); break; case RECORD: if (!c.declared_records.containsKey(t.getName())) gerarErro("Tipo '" + t.getName() + "' não foi declarado!"); RecordDefinition def = c.declared_records.get(t.getName()).clone(); v = new VarRecord(t.getName(), var_def.getName(), def.fields, var_def.getColor(), var_def.getcorExterna(), var_def.getDimension(), var_def.getPosicao(),var_def.getMostraNome()); break; } /** Se for uma variável composta (array ou registro) entra */ if ((i = var_def.getIndex()) != null) { try { if (i.isMatrix) { v = new VarMatriz( var_def.getName(), i.first, i.second, v, var_def.getColor(), var_def.getcorExterna(), var_def.getDimension(), var_def.getPosicao()); } else { v = new VarArray(var_def.getName(), i.first, v, var_def.getColor(), var_def.getcorExterna(), var_def.getDimension(), var_def.getPosicao(),var_def.getMostraNome()); } } catch (Exception e) { gerarErro("Falha ao criar variável '" + var_def.getName() + "'."); } } /** Retorna a nova variável formatada. */ return v; } /** * Pega o valor de uma variável no mostrador, incluindo-se índices de * arrays e matrizes e campos de records. * * @param g * @param var_stack * @return */ @SuppressWarnings("unchecked") static public Object getValue(Controlador c, List<Object> var) { Object aux, value; ListIterator<Object> i = var.listIterator(); value = c.mostrador.getCopiaVariavel((String) i.next()).getValor(); while(i.hasNext()) { aux = i.next(); if (aux instanceof String) { Map<String, Object> map = (Map<String, Object>) value; value = map.get((String) aux); } else { Index index = (Index) aux; Object values[] = (Object[]) value; if (index.isMatrix) { value = values[index.first - 1]; } else { value = values[index.first - 1]; } } } return value; } /** * Insere uma seta na variavel de pilha para representar um ponteiro. * Possui direcao e tamanho especificados. * @param mostrador * @param var_stack * @param direcao * @param tamanho */ protected void criarSeta(Mostrador mostrador, Stack<Object> var_stack, Point posicaoApontada) throws TiraTeimaLanguageException{ //Pilha auxiliar para armazenar temporariamente os valores da pilha. Stack<Object> pilhaAux = new Stack<Object>(); Object parent; parent = var_stack.pop(); pilhaAux.push(parent); String nome_var = (String) parent; if (!mostrador.hasVariavel(nome_var)) gerarErro("Variavel '" + nome_var + "' não foi declarada!"); mostrador.adicionarSeta(nome_var,new Seta(nome_var,posicaoApontada)); mostrador.modificarVariavel(nome_var, ""); restaurarPilha(var_stack,pilhaAux); } /** * Insere uma seta na variavel de pilha para representar um ponteiro. * Possui direcao e tamanho especificados. * @param mostrador * @param var_stack * @param direcao * @param tamanho */ protected void removerSeta(Mostrador mostrador, Stack<Object> var_stack) throws TiraTeimaLanguageException{ //Pilha auxiliar para armazenar temporariamente os valores da pilha. Stack<Object> pilhaAux = new Stack<Object>(); Object parent; parent = var_stack.pop(); pilhaAux.push(parent); String nome_var = (String) parent; /*if (!mostrador.hasSeta(nome_var)) gerarErro("Variavel '" + nome_var + "' não foi declarada!");*/ mostrador.removerSeta(nome_var); restaurarPilha(var_stack,pilhaAux); } /** * Seta o valor de uma variável no mostrador, respeitando o escopo. * * @param mostrador * @param var_stack * @param value * * @throws TiraTeimaLanguageException */ protected void setValue(Mostrador mostrador, Stack<Object> var_stack, Object value) throws TiraTeimaLanguageException { //pilha que armazenará temporariamente os valores desempilhados para posterior restauração Stack<Object> pilhaAux = new Stack<Object>(); Object child, parent; parent = child = var_stack.pop(); pilhaAux.push(parent); while (!var_stack.empty()) { parent = var_stack.pop(); pilhaAux.push(parent); if (child instanceof Index) { Index i = (Index) child; if (i.isMatrix) { Map<Par<Integer, Integer>, Object> map = new HashMap<Par<Integer, Integer>, Object>(); map.put( new Par<Integer, Integer>(i.first - 1, i.second - 1), value); value = map; } else { Map<Integer, Object> map = new HashMap<Integer, Object>(); map.put(i.first - 1, value); value = map; } } else { Map<String, Object> map = new HashMap<String, Object>(); map.put((String) child, value); value = map; } child = parent; } String nome_var = (String) parent; if (!mostrador.hasVariavel(nome_var)) gerarErro("Variavel '" + nome_var + "' não foi declarada!"); try { mostrador.modificarVariavel(nome_var, value); mostrador.removerSeta(nome_var); } catch (ClassCastException e) { gerarErro("Atribuição inválida!"); } restaurarPilha(var_stack,pilhaAux); } /** * Restaura uma pilha a partira de um a pilha axiliar. * @param var_stack - pilha a ser restaurada * @param pilhaAux - pilha usada para armazernar temporariamente os valores. */ public void restaurarPilha(Stack<Object> var_stack, Stack<Object> pilhaAux) { while(!pilhaAux.empty()){ var_stack.push(pilhaAux.pop()); } } }