private VisitorGeracaoCodigo geraInicializacaoVariaveisGlobais() throws ExcecaoVisitaASA {
      boolean excluiConstantes = true;
      List<NoDeclaracaoInicializavel> variaveisGlobais =
          getVariaveisGlobaisDeclaradas(asa, excluiConstantes);

      if (variaveisGlobais
          .isEmpty()) // não sobrescreve o método de inicialização se não houverem variáveis globais
      // que não são constantes
      {
        return this;
      }

      saida.append(Utils.geraIdentacao(nivelEscopo)).append("@Override").println();

      saida.append(Utils.geraIdentacao(nivelEscopo));
      saida
          .format("protected void inicializar() throws ErroExecucao, InterruptedException {")
          .println();

      inicializaVariaveisGlobaisNaoPassadasPorReferencia(variaveisGlobais);

      inicializaVariaveisGlobaisQueSaoPassadasPorReferencia();

      saida.append(Utils.geraIdentacao(nivelEscopo));
      saida.append("}").println();
      return this;
    }
 private void geraCodigoInspecao(NoPara noPara) throws ExcecaoVisitaASA {
   NoExpressao incremento = noPara.getIncremento();
   if (incremento != null) {
     NoOperacaoAtribuicao atribuicao = (NoOperacaoAtribuicao) incremento;
     if (atribuicao.getOperandoEsquerdo() instanceof NoReferenciaVariavel) {
       NoReferenciaVariavel referencia = (NoReferenciaVariavel) atribuicao.getOperandoEsquerdo();
       NoDeclaracao origem = referencia.getOrigemDaReferencia();
       if (origem instanceof NoDeclaracaoVariavel) {
         Utils.geraCodigoParaInspecao((NoDeclaracaoVariavel) origem, saida, nivelEscopo, false);
       } else if (origem instanceof NoDeclaracaoParametro) {
         Utils.geraCodigoParaInspecao((NoDeclaracaoParametro) origem, saida, nivelEscopo);
       }
     }
   }
 }
    public VisitorGeracaoCodigo geraAtributosParaAsVariaveisPassadasPorReferencia(
        Map<TipoDado, List<NoDeclaracaoVariavel>> variaveis) {
      if (variaveis.isEmpty()) {
        return this;
      }

      String identacao = Utils.geraIdentacao(nivelEscopo);

      // declara os arrays (separados por tipo) que armazenam todas as referências
      // gera os arrays nessa sequência de tipos
      TipoDado tipos[] = {
        TipoDado.INTEIRO, TipoDado.REAL, TipoDado.LOGICO, TipoDado.CARACTER, TipoDado.CADEIA
      };

      for (TipoDado tipo : tipos) {
        if (variaveis.containsKey(tipo)) {
          String nomeTipo = Utils.getNomeTipoJava(tipo);
          int numeroVariaveis = variaveis.get(tipo).size();
          saida
              .append(identacao)
              .format(
                  "private final %s[] REFS_%s = new %s[%d];",
                  nomeTipo, nomeTipo.toUpperCase(), nomeTipo, numeroVariaveis)
              .println();
        }
      }

      saida.println(); // pula uma linha antes de declarar as variáveis de cada tipo

      for (TipoDado tipo : tipos) {
        if (variaveis.containsKey(tipo)) {
          for (NoDeclaracaoVariavel variavel : variaveis.get(tipo)) {
            saida
                .append(identacao)
                .append("private final int ")
                .append(Utils.geraStringIndice(variavel))
                .append(" = ")
                .append(String.valueOf(variavel.getIndiceReferencia()))
                .append(";")
                .println();
          }

          saida.println(); // separa as declarações para cada tipo
        }
      }

      return this;
    }
 private void inicializaVariaveisGlobaisQueSaoPassadasPorReferencia() throws ExcecaoVisitaASA {
   List<NoDeclaracao> declaracoes = asa.getListaDeclaracoesGlobais();
   for (NoDeclaracao declaracao : declaracoes) {
     if (declaracao instanceof NoDeclaracaoVariavel) {
       NoDeclaracaoVariavel variavel = (NoDeclaracaoVariavel) declaracao;
       if (variavel.ehPassadaPorReferencia() && variavel.temInicializacao()) {
         String nomeTipo = Utils.getNomeTipoJava(variavel.getTipoDado());
         saida.append(Utils.geraIdentacao(nivelEscopo));
         saida.format(
             "REFS_%s[%s] = ", nomeTipo.toUpperCase(), Utils.geraStringIndice(variavel));
         variavel.getInicializacao().aceitar(this);
         saida.append(";").println(); // o ponto e vírgula depois da inicialização
       }
     }
   }
 }
    @Override
    public Void visitar(NoFacaEnquanto no) throws ExcecaoVisitaASA {
      String identacao = Utils.geraIdentacao(nivelEscopo);

      saida.append("do").println();
      saida.append(identacao).append("{").println();

      geraVerificacaoThreadInterrompida();

      List<NoBloco> blocos = no.getBlocos();
      if (blocos != null) {
        visitarBlocos(blocos);
        saida.println();
      }

      saida.append(identacao).append("}").println();

      saida.append(identacao).append("while(");

      no.getCondicao().aceitar(this);

      saida.append(");").println();

      return null;
    }
    @Override
    public Void visitar(NoSe no) throws ExcecaoVisitaASA {
      saida.append("if(");

      no.getCondicao().aceitar(this);

      saida.append(")").println();

      String identacao = Utils.geraIdentacao(nivelEscopo);

      saida.append(identacao).append("{").println();

      List<NoBloco> blocosVerdadeiros = no.getBlocosVerdadeiros();
      if (blocosVerdadeiros != null) {
        visitarBlocos(blocosVerdadeiros);
        saida.println();
      }

      saida.append(identacao).append("}").println();

      List<NoBloco> blocosFalsos = no.getBlocosFalsos();
      if (blocosFalsos != null) {
        saida.append(identacao).append("else").println();
        saida.append(identacao).append("{").println();

        visitarBlocos(blocosFalsos);

        saida.println();

        saida.append(identacao).append("}").println();
      }

      return null;
    }
 @Override
 public Void visitar(NoCadeia noCadeia) throws ExcecaoVisitaASA {
   String valor = Utils.preservaCaracteresEspeciais(noCadeia.getValor());
   valor = '\"' + valor + '\"';
   saida.append(valor);
   return null;
 }
 private void geraVerificacaoThreadInterrompida() {
   if (gerandoCodigoParaInterrupcaoDeThread) {
     nivelEscopo++;
     Utils.geraVerificacaoThreadInterrompida(saida, nivelEscopo);
     nivelEscopo--;
   }
 }
    private void inicializaVariaveisGlobaisNaoPassadasPorReferencia(
        List<NoDeclaracaoInicializavel> variaveisGlobais) throws ExcecaoVisitaASA {
      for (NoDeclaracaoInicializavel variavel : variaveisGlobais) {
        if (variavel instanceof NoDeclaracaoVariavel) {
          if (((NoDeclaracaoVariavel) variavel).ehPassadaPorReferencia()) {
            continue; // variáveis globais que são passadas como referência não são declaradas como
            // atributo no código Java
          }
        }

        boolean ehVetor = variavel instanceof NoDeclaracaoVetor;
        boolean ehMatriz = variavel instanceof NoDeclaracaoMatriz;
        boolean variavelInicializada = variavel.temInicializacao();

        if (ehVetor || ehMatriz || variavelInicializada) {
          saida.append(Utils.geraIdentacao(nivelEscopo + 1));
          saida.format("%s = ", variavel.getNome());
          if (variavelInicializada) {
            variavel.getInicializacao().aceitar(this);
          } else // vetores e matrizes não inicializados precisam ser instanciados
          {
            if (ehVetor) {
              NoExpressao tamanho = ((NoDeclaracaoVetor) variavel).getTamanho();
              if (tamanho != null) {
                String nomeTipo = Utils.getNomeTipoJava(variavel.getTipoDado());
                saida.format("new %s[", nomeTipo);
                tamanho.aceitar(this);
                saida.append("]");
              }
            } else // é uma matriz
            {
              NoExpressao linhas = ((NoDeclaracaoMatriz) variavel).getNumeroLinhas();
              NoExpressao colunas = ((NoDeclaracaoMatriz) variavel).getNumeroColunas();
              if (linhas != null && colunas != null) {
                String nomeTipo = Utils.getNomeTipoJava(variavel.getTipoDado());
                saida.format("new %s[", nomeTipo);
                linhas.aceitar(this);
                saida.append("][");
                colunas.aceitar(this);
                saida.append("]");
              }
            }
          }
          saida.append(";").println();
        }
      }
    }
    private VisitorGeracaoCodigo geraConstrutor(
        String nomeDaClasseJava,
        int variaveisDeclaradas,
        int vetoresDeclarados,
        int matrizesDeclaradas)
        throws ExcecaoVisitaASA {
      String identacao = Utils.geraIdentacao(nivelEscopo);
      saida
          .append(identacao)
          .append("public ")
          .append(nomeDaClasseJava)
          .append("() throws ErroExecucao, InterruptedException {")
          .println();

      nivelEscopo++;

      if (gerandoCodigoParaInspecaoDeSimbolos) {
        String identacaoInterna = Utils.geraIdentacao(nivelEscopo);
        saida
            .append(identacaoInterna)
            .format("variaveisInspecionadas = new Object[%d];", variaveisDeclaradas)
            .println();

        saida
            .append(identacaoInterna)
            .format("vetoresInspecionados = new Vetor[%d];", vetoresDeclarados)
            .println();

        saida
            .append(identacaoInterna)
            .format("matrizesInspecionadas = new Matriz[%d];", matrizesDeclaradas)
            .println();
      }

      nivelEscopo--;

      saida.append(identacao).append("}").println();

      return this;
    }
    @Override
    public Void visitar(NoReferenciaVariavel no) throws ExcecaoVisitaASA {
      String nome = no.getNome();
      if (no.getEscopo() != null) {
        saida.append(no.getEscopo()).append(".");
      }

      NoDeclaracao declaracao = no.getOrigemDaReferencia();
      boolean ehParametroPorReferencia =
          declaracao instanceof NoDeclaracaoParametro
              && (((NoDeclaracaoParametro) declaracao).getModoAcesso()
                  == ModoAcesso.POR_REFERENCIA);
      if (ehParametroPorReferencia || no.ehPassadoPorReferencia()) {
        String stringIndice = ehParametroPorReferencia ? no.getNome() : Utils.geraStringIndice(no);
        String nomeTipo = Utils.getNomeTipoJava(declaracao.getTipoDado()).toUpperCase();
        saida.format("REFS_%s[%s]", nomeTipo, stringIndice);
      } else {
        saida.append(nome);
      }

      return null;
    }
    private void visitarBlocos(List<NoBloco> blocos) throws ExcecaoVisitaASA {
      nivelEscopo++;

      Utils.visitarBlocos(
          blocos,
          saida,
          this,
          nivelEscopo,
          gerandoCodigoParaInterrupcaoDeThread,
          gerandoCodigoParaPontosDeParada,
          gerandoCodigoParaInspecaoDeSimbolos,
          seed);

      nivelEscopo--;
    }
    @Override
    public Void visitar(NoEnquanto no) throws ExcecaoVisitaASA {

      saida.append("while(");

      no.getCondicao().aceitar(this);

      saida.append(")").println();

      String identacao = Utils.geraIdentacao(nivelEscopo);

      saida.append(identacao).append("{").println();

      geraVerificacaoThreadInterrompida();

      visitarBlocos(no.getBlocos());

      saida.println();

      saida.append(identacao).append("}").println();

      return null;
    }
    @Override
    public Void visitar(NoPara no) throws ExcecaoVisitaASA {
      saida.append("for(");
      if (no.getInicializacao() != null) {
        no.getInicializacao().aceitar(this);
      }

      saida.append("; "); // separador depois da inicialização do for

      no.getCondicao().aceitar(this);

      saida.append("; "); // separador depois da c

      if (no.getIncremento() != null) {
        no.getIncremento().aceitar(this);
      }

      saida.append(")").println(); // fecha o parênteses do for

      String identacao = Utils.geraIdentacao(nivelEscopo);

      saida.append(identacao).append("{").println();

      geraVerificacaoThreadInterrompida();

      if (gerandoCodigoParaInspecaoDeSimbolos) {
        geraCodigoInspecao(no);
      }

      visitarBlocos(no.getBlocos());

      saida.println();

      saida.append(identacao).append("}").println();

      return null;
    }