UNPKG

@designliquido/delegua

Version:

Linguagem de programação simples e moderna usando português estruturado.

502 lines 29.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AvaliadorSintaticoCalango = void 0; const construtos_1 = require("../../construtos"); const simbolo_1 = require("../../lexador/simbolo"); const declaracoes_1 = require("../../declaracoes"); const avaliador_sintatico_base_1 = require("../avaliador-sintatico-base"); const pilha_escopos_1 = require("../pilha-escopos"); const informacao_escopo_1 = require("../informacao-escopo"); const informacao_elemento_sintatico_1 = require("../../informacao-elemento-sintatico"); const calango_1 = __importDefault(require("../../tipos-de-simbolos/calango")); class AvaliadorSintaticoCalango extends avaliador_sintatico_base_1.AvaliadorSintaticoBase { constructor() { super(); /** Flag ativa quando se está a parsear a condição de um `se`, `enquanto` ou `faca/enquanto`. * Permite que `=` seja tratado como igualdade (não atribuição) nesses contextos. */ this.emContextoCondicao = false; this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos(); } async atribuir() { const expressao = await this.ou(); if (this.verificarSeSimboloAtualEIgualA(calango_1.default.IGUAL_ATRIBUICAO)) { const setaAtribuicao = this.simbolos[this.atual - 1]; const valor = await this.atribuir(); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); if (expressao instanceof construtos_1.Variavel) { return new construtos_1.Atribuir(this.hashArquivo, expressao, valor); } if (expressao instanceof construtos_1.AcessoIndiceVariavel) { return new construtos_1.AtribuicaoPorIndice(this.hashArquivo, expressao.linha, expressao.entidadeChamada, expressao.indice, valor); } throw this.erro(setaAtribuicao, 'Tarefa de atribuição inválida'); } return expressao; } blocoEscopo() { throw new Error('Método não implementado.'); } async chamar() { let expressao = await this.primario(); while (true) { if (this.verificarSeSimboloAtualEIgualA(calango_1.default.PARENTESE_ESQUERDO)) { const argumentos = []; if (!this.verificarTipoSimboloAtual(calango_1.default.PARENTESE_DIREITO)) { do { argumentos.push(await this.expressao()); } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); } this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após argumentos da chamada."); expressao = new construtos_1.Chamada(this.hashArquivo, expressao, argumentos); } else if (this.verificarSeSimboloAtualEIgualA(calango_1.default.COLCHETE_ESQUERDO)) { const indice = await this.expressao(); const fechamento = this.consumir(calango_1.default.COLCHETE_DIREITO, "Esperado ']' após índice."); expressao = new construtos_1.AcessoIndiceVariavel(this.hashArquivo, expressao, indice, fechamento); } else { break; } } return expressao; } async declaracaoEnquanto() { try { this.blocos += 1; this.avancarEDevolverAnterior(); // consome 'enquanto' this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após 'enquanto'."); this.emContextoCondicao = true; const condicao = await this.ou(); this.emContextoCondicao = false; this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após condição do 'enquanto'."); this.consumir(calango_1.default.FACA, "Esperado 'faca' após condição do 'enquanto'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const corpo = await this.resolverBloco(['fimEnquanto']); this.consumir(calango_1.default.FIM_ENQUANTO, "Esperado 'fimEnquanto' para fechar o laço."); return new declaracoes_1.Enquanto(condicao, corpo); } finally { this.blocos -= 1; } } async declaracaoEscolha() { this.avancarEDevolverAnterior(); // consome 'escolha' this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após 'escolha'."); const identificador = await this.expressao(); this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após expressão do 'escolha'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const caminhos = []; let caminhoPadrao = null; while (!this.estaNoFinal() && this.simbolos[this.atual].tipo !== calango_1.default.FIM_ESCOLHA) { if (this.verificarSeSimboloAtualEIgualA(calango_1.default.CASO)) { const condicao = await this.expressao(); this.consumir(calango_1.default.DOIS_PONTOS, "Esperado ':' após valor do 'caso'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const bloco = await this.resolverBloco(['caso', 'outroCaso', 'fimEscolha']); caminhos.push({ condicoes: [condicao], declaracoes: bloco.declaracoes }); } else if (this.verificarSeSimboloAtualEIgualA(calango_1.default.OUTRO_CASO)) { this.consumir(calango_1.default.DOIS_PONTOS, "Esperado ':' após 'outroCaso'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const bloco = await this.resolverBloco(['fimEscolha']); caminhoPadrao = { condicoes: [], declaracoes: bloco.declaracoes }; } else { break; } } this.consumir(calango_1.default.FIM_ESCOLHA, "Esperado 'fimEscolha' para fechar o 'escolha'."); return new declaracoes_1.Escolha(identificador, caminhos, caminhoPadrao); } // Em Calango, método "escreval" async declaracaoEscreva() { const simboloAtual = this.avancarEDevolverAnterior(); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em escreva."); const argumentos = []; if (!this.verificarTipoSimboloAtual(calango_1.default.PARENTESE_DIREITO)) { do { const valor = await this.resolverDeclaracaoForaDeBloco(); argumentos.push(new construtos_1.FormatacaoEscrita(this.hashArquivo, Number(simboloAtual.linha), valor)); } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); } this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em escreva."); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); return new declaracoes_1.Escreva(Number(simboloAtual.linha), this.hashArquivo, argumentos); } /** * Em Calango, este é o método `escreva()`. * @returns {EscrevaMesmaLinha} Uma declaracao de escrita na mesma linha. */ async declaracaoEscrevaMesmaLinha() { const simboloAtual = this.avancarEDevolverAnterior(); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em escreva."); const argumentos = []; if (!this.verificarTipoSimboloAtual(calango_1.default.PARENTESE_DIREITO)) { do { const valor = await this.resolverDeclaracaoForaDeBloco(); argumentos.push(new construtos_1.FormatacaoEscrita(this.hashArquivo, Number(simboloAtual.linha), valor)); } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); } this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em escreva."); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); return new declaracoes_1.EscrevaMesmaLinha(Number(simboloAtual.linha), this.hashArquivo, argumentos); } declaracaoVariaveis(_tipoToken, tipoDelégua, valorPadrao) { const simboloTipo = this.avancarEDevolverAnterior(); const inicializacoes = []; do { const identificador = this.consumir(calango_1.default.IDENTIFICADOR, `Esperado identificador após palavra reservada '${simboloTipo.lexema}'.`); // Vetor com tamanho fixo: inteiro v[10]; if (this.verificarSeSimboloAtualEIgualA(calango_1.default.COLCHETE_ESQUERDO)) { const tamanhoSimbolo = this.consumir(calango_1.default.NUMERO, 'Esperado tamanho do vetor.'); const tamanho = Number(tamanhoSimbolo.literal); if (!Number.isInteger(tamanho) || tamanho < 0) { throw this.erro(tamanhoSimbolo, 'Tamanho do vetor deve ser um inteiro não-negativo.'); } this.consumir(calango_1.default.COLCHETE_DIREITO, "Esperado ']' após tamanho do vetor."); const elementos = Array.from({ length: tamanho }, () => new construtos_1.Literal(this.hashArquivo, Number(simboloTipo.linha), valorPadrao, tipoDelégua)); const tipoVetor = `${tipoDelégua}[]`; inicializacoes.push(new declaracoes_1.Var(identificador, new construtos_1.Vetor(this.hashArquivo, Number(simboloTipo.linha), elementos, tipoVetor))); this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(identificador.lexema, tipoVetor)); } else { inicializacoes.push(new declaracoes_1.Var(identificador, new construtos_1.Literal(this.hashArquivo, Number(simboloTipo.linha), valorPadrao, tipoDelégua))); this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(identificador.lexema, tipoDelégua)); } } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); this.consumir(calango_1.default.PONTO_E_VIRGULA, 'Esperado ponto e vírgula após declaração de variáveis.'); return inicializacoes; } declaracaoInteiros() { return this.declaracaoVariaveis(calango_1.default.INTEIRO, 'inteiro', 0); } declaracaoReais() { return this.declaracaoVariaveis(calango_1.default.REAL, 'real', 0.0); } declaracaoLogicos() { return this.declaracaoVariaveis(calango_1.default.LOGICO, 'lógico', false); } declaracaoCaracteres() { return this.declaracaoVariaveis(calango_1.default.CARACTER, 'caracter', ''); } declaracaoTextos() { return this.declaracaoVariaveis(calango_1.default.TIPO_TEXTO, 'texto', ''); } async declaracaoFazer() { try { this.blocos += 1; const simboloFaca = this.avancarEDevolverAnterior(); // consome 'faca' this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); // Corpo termina quando encontramos o 'enquanto' do do-while. // LIMITAÇÃO CONHECIDA: um `enquanto...fimEnquanto` (while) aninhado dentro deste bloco // causará término prematuro, pois o parser não consegue distinguir o 'enquanto' de // fechamento do do-while do 'enquanto' de abertura de um while aninhado sem lookahead // arbitrário. Este é um defeito da gramática do Calango, presente também no interpretador // de referência (github.com/GeovanaRamos/calango-interpreter). Não deve ser corrigido. const corpo = await this.resolverBloco(['enquanto']); this.consumir(calango_1.default.ENQUANTO, "Esperado 'enquanto' após corpo do 'faca'."); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após 'enquanto' no 'faca'."); this.emContextoCondicao = true; const condicao = await this.ou(); this.emContextoCondicao = false; this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após condição do 'faca'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); return new declaracoes_1.Fazer(this.hashArquivo, Number(simboloFaca.linha), corpo, condicao); } finally { this.blocos -= 1; } } async declaracaoPara() { try { this.blocos += 1; const simboloPara = this.avancarEDevolverAnterior(); // consome 'para' const identificador = this.consumir(calango_1.default.IDENTIFICADOR, "Esperado identificador após 'para'."); this.consumir(calango_1.default.DE, "Esperado 'de' após variável do 'para'."); const inicioExpr = await this.expressao(); this.consumir(calango_1.default.ATE, "Esperado 'ate' após valor inicial do 'para'."); const fimExpr = await this.expressao(); let passoExpr = new construtos_1.Literal(this.hashArquivo, Number(simboloPara.linha), 1, 'inteiro'); if (this.verificarSeSimboloAtualEIgualA(calango_1.default.PASSO)) { passoExpr = await this.expressao(); } this.consumir(calango_1.default.FACA, "Esperado 'faca' após condição do 'para'."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const corpo = await this.resolverBloco(['fimPara']); this.consumir(calango_1.default.FIM_PARA, "Esperado 'fimPara' para fechar o laço 'para'."); const linha = Number(simboloPara.linha); const varIteracao = new construtos_1.Variavel(this.hashArquivo, identificador, 'inteiro'); const simboloMenorIgual = new simbolo_1.Simbolo(calango_1.default.MENOR_IGUAL, '<=', null, linha, this.hashArquivo); const simboloAdicao = new simbolo_1.Simbolo(calango_1.default.ADICAO, '+', null, linha, this.hashArquivo); const inicializador = new declaracoes_1.Expressao(new construtos_1.Atribuir(this.hashArquivo, varIteracao, inicioExpr)); const condicao = new construtos_1.Binario(this.hashArquivo, varIteracao, simboloMenorIgual, fimExpr); const incrementar = new construtos_1.Atribuir(this.hashArquivo, varIteracao, new construtos_1.Binario(this.hashArquivo, varIteracao, simboloAdicao, passoExpr)); return new declaracoes_1.Para(this.hashArquivo, linha, inicializador, condicao, incrementar, corpo); } finally { this.blocos -= 1; } } /** * Em Calango, `=` é usado tanto para atribuição (em comandos) quanto para igualdade (em condições). * Este override só trata `IGUAL_ATRIBUICAO` como igualdade quando `emContextoCondicao` estiver ativo, * evitando que `i = i + 1` dentro de blocos seja erroneamente interpretado como comparação. */ async comparacaoIgualdade() { let expressao = await this.comparar(); while (this.verificarSeSimboloAtualEIgualA(calango_1.default.DIFERENTE, calango_1.default.IGUAL, calango_1.default.IGUAL_IGUAL) || (this.emContextoCondicao && this.verificarSeSimboloAtualEIgualA(calango_1.default.IGUAL_ATRIBUICAO))) { let operador = this.simbolos[this.atual - 1]; if (operador.tipo === calango_1.default.IGUAL_ATRIBUICAO) { operador = new simbolo_1.Simbolo(calango_1.default.IGUAL_IGUAL, '=', null, operador.linha, operador.hashArquivo); } const direito = await this.comparar(); expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito); } return expressao; } async resolverBloco(simbolosParada) { const declaracoes = []; this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo()); const primeiroSimbolo = this.simbolos[this.atual]; while (!this.estaNoFinal() && !simbolosParada.includes(this.simbolos[this.atual].lexema)) { const resolucao = await this.resolverDeclaracaoForaDeBloco(); if (Array.isArray(resolucao)) { declaracoes.push(...resolucao); } else { declaracoes.push(resolucao); } } this.pilhaEscopos.removerUltimo(); return new declaracoes_1.Bloco(this.hashArquivo, primeiroSimbolo.linha, declaracoes.filter((d) => d)); } async declaracaoSe() { this.avancarEDevolverAnterior(); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após 'se'"); this.emContextoCondicao = true; const condicao = await this.ou(); this.emContextoCondicao = false; this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após condição do 'se'"); this.consumir(calango_1.default.ENTAO, "Esperado 'entao' após condição"); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const caminhoEntao = await this.resolverBloco(['senao', 'fimSe']); while (this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA)) ; let caminhoSenao = null; if (this.verificarSeSimboloAtualEIgualA(calango_1.default.SENAO)) { this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); caminhoSenao = await this.resolverBloco(['senao', 'fimSe']); } this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); this.consumir(calango_1.default.FIM_SE, "Esperado 'fimSe' para finalização de uma instrução se."); return new declaracoes_1.Se(condicao, caminhoEntao, [], caminhoSenao); } async expressaoLeia() { const simboloAtual = this.avancarEDevolverAnterior(); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' depois da declaração 'leia'"); const argumentos = []; do { argumentos.push(await this.resolverDeclaracaoForaDeBloco()); } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após declaração 'leia'"); this.consumir(calango_1.default.PONTO_E_VIRGULA, 'Esperado ponto e vírgula após declaração leia'); return new construtos_1.Leia(simboloAtual, argumentos); } async primario() { switch (this.simbolos[this.atual].tipo) { case calango_1.default.IDENTIFICADOR: const simboloIdentificador = this.avancarEDevolverAnterior(); let tipoOperando; try { tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema); } catch (erro) { throw this.erro(simboloIdentificador, erro.message); } return new construtos_1.Variavel(this.hashArquivo, simboloIdentificador, tipoOperando); case calango_1.default.NUMERO: const simboloNumero = this.avancarEDevolverAnterior(); return new construtos_1.Literal(this.hashArquivo, Number(simboloNumero.linha), simboloNumero.literal, Number.isInteger(simboloNumero.literal) ? 'inteiro' : 'real'); case calango_1.default.TEXTO: const simboloTexto = this.avancarEDevolverAnterior(); return new construtos_1.Literal(this.hashArquivo, Number(simboloTexto.linha), simboloTexto.literal, 'texto'); case calango_1.default.LITERAL_CARACTER: const simboloCaracter = this.avancarEDevolverAnterior(); return new construtos_1.Literal(this.hashArquivo, Number(simboloCaracter.linha), simboloCaracter.literal, 'caracter'); case calango_1.default.VERDADEIRO: const simboloVerdadeiro = this.avancarEDevolverAnterior(); return new construtos_1.Literal(this.hashArquivo, Number(simboloVerdadeiro.linha), true, 'lógico'); case calango_1.default.FALSO: const simboloFalso = this.avancarEDevolverAnterior(); return new construtos_1.Literal(this.hashArquivo, Number(simboloFalso.linha), false, 'lógico'); case calango_1.default.PARENTESE_ESQUERDO: this.avancarEDevolverAnterior(); const expressao = await this.expressao(); this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão."); return new construtos_1.Agrupamento(this.hashArquivo, this.simbolos[this.atual].linha, expressao); } } async resolverDeclaracaoForaDeBloco() { const simboloAtual = this.simbolos[this.atual]; switch (simboloAtual.tipo) { case calango_1.default.ESCREVA: return await this.declaracaoEscrevaMesmaLinha(); case calango_1.default.ESCREVAL: return await this.declaracaoEscreva(); case calango_1.default.LEIA: return await this.expressaoLeia(); case calango_1.default.INTEIRO: return this.declaracaoInteiros(); case calango_1.default.REAL: return this.declaracaoReais(); case calango_1.default.LOGICO: return this.declaracaoLogicos(); case calango_1.default.CARACTER: return this.declaracaoCaracteres(); case calango_1.default.TIPO_TEXTO: return this.declaracaoTextos(); case calango_1.default.ENQUANTO: return await this.declaracaoEnquanto(); case calango_1.default.ESCOLHA: return await this.declaracaoEscolha(); case calango_1.default.INTERROMPA: return new declaracoes_1.Sustar(this.avancarEDevolverAnterior()); case calango_1.default.RETORNA: return await this.declaracaoRetorna(); case calango_1.default.FACA: return await this.declaracaoFazer(); case calango_1.default.PARA: return await this.declaracaoPara(); case calango_1.default.SE: return await this.declaracaoSe(); case calango_1.default.QUEBRA_LINHA: this.avancarEDevolverAnterior(); return null; default: { const resultado = await this.expressao(); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); return resultado; } } } corpoDaFuncao(_tipo) { throw new Error('Método não implementado.'); } /** Mapeia um tipo de token Calango para a string de tipo da Delégua. */ mapearTipo(tipoToken) { switch (tipoToken) { case calango_1.default.INTEIRO: return 'inteiro'; case calango_1.default.REAL: return 'real'; case calango_1.default.LOGICO: return 'lógico'; case calango_1.default.CARACTER: return 'caracter'; case calango_1.default.TIPO_TEXTO: return 'texto'; default: return 'qualquer'; } } async analisarParametrosCalango() { const parametros = []; if (this.verificarTipoSimboloAtual(calango_1.default.PARENTESE_DIREITO)) { return parametros; } do { const tipoTipo = this.mapearTipo(this.simbolos[this.atual].tipo); this.avancarEDevolverAnterior(); // consome o token de tipo const nome = this.consumir(calango_1.default.IDENTIFICADOR, 'Esperado nome de parâmetro.'); this.pilhaEscopos.definirInformacoesVariavel(nome.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(nome.lexema, tipoTipo)); parametros.push({ abrangencia: 'padrao', nome, tipoDado: tipoTipo }); } while (this.verificarSeSimboloAtualEIgualA(calango_1.default.VIRGULA)); return parametros; } async declaracaoFuncao() { this.avancarEDevolverAnterior(); // consome 'funcao' const simboloNome = this.consumir(calango_1.default.IDENTIFICADOR, "Esperado nome da função."); this.pilhaEscopos.definirInformacoesVariavel(simboloNome.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(simboloNome.lexema, 'qualquer')); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após nome da função."); const parametros = await this.analisarParametrosCalango(); this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros."); this.consumir(calango_1.default.DOIS_PONTOS, "Esperado ':' após ')' na função."); const tipoRetorno = this.mapearTipo(this.simbolos[this.atual].tipo); this.avancarEDevolverAnterior(); // consome o tipo de retorno this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const bloco = await this.resolverBloco(['fimFuncao']); this.consumir(calango_1.default.FIM_FUNCAO, "Esperado 'fimFuncao' para fechar a função."); const funcaoConstruto = new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simboloNome.linha), parametros, bloco.declaracoes, tipoRetorno, true); return new declaracoes_1.FuncaoDeclaracao(simboloNome, funcaoConstruto, tipoRetorno); } async declaracaoProcedimento() { this.avancarEDevolverAnterior(); // consome 'procedimento' const simboloNome = this.consumir(calango_1.default.IDENTIFICADOR, "Esperado nome do procedimento."); this.pilhaEscopos.definirInformacoesVariavel(simboloNome.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(simboloNome.lexema, 'qualquer')); this.consumir(calango_1.default.PARENTESE_ESQUERDO, "Esperado '(' após nome do procedimento."); const parametros = await this.analisarParametrosCalango(); this.consumir(calango_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros."); this.verificarSeSimboloAtualEIgualA(calango_1.default.QUEBRA_LINHA); const bloco = await this.resolverBloco(['fimProcedimento']); this.consumir(calango_1.default.FIM_PROCEDIMENTO, "Esperado 'fimProcedimento' para fechar o procedimento."); const funcaoConstruto = new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simboloNome.linha), parametros, bloco.declaracoes, 'vazio', false); return new declaracoes_1.FuncaoDeclaracao(simboloNome, funcaoConstruto, 'vazio'); } async declaracaoRetorna() { const simbolo = this.avancarEDevolverAnterior(); // consome 'retorna' const valor = await this.expressao(); this.verificarSeSimboloAtualEIgualA(calango_1.default.PONTO_E_VIRGULA); return new declaracoes_1.Retorna(simbolo, valor); } validarSegmentoAlgoritmo() { this.consumir(calango_1.default.ALGORITMO, `Expressão 'algoritmo' não declarada`); this.consumir(calango_1.default.IDENTIFICADOR, `Esperado identificador após 'algoritmo'.`); this.consumir(calango_1.default.PONTO_E_VIRGULA, `Esperado ponto e vírgula após identificador do algoritmo.`); } validarSegmentoPrincipal(algoritmoOuFuncao) { this.consumir(calango_1.default.PRINCIPAL, `Expressão 'principal' não declarada`); } async analisar(retornoLexador, hashArquivo) { this.erros = []; this.atual = 0; this.blocos = 0; this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos(); this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo()); this.hashArquivo = hashArquivo || 0; this.simbolos = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.simbolos) || []; while (this.verificarTipoSimboloAtual(calango_1.default.QUEBRA_LINHA)) { this.avancarEDevolverAnterior(); } let declaracoes = []; this.validarSegmentoAlgoritmo(); // Declarações de funções e procedimentos antes do bloco principal while (!this.estaNoFinal() && this.simbolos[this.atual].tipo !== calango_1.default.PRINCIPAL) { if (this.simbolos[this.atual].tipo === calango_1.default.FUNCAO) { declaracoes.push(await this.declaracaoFuncao()); } else if (this.simbolos[this.atual].tipo === calango_1.default.PROCEDIMENTO) { declaracoes.push(await this.declaracaoProcedimento()); } else { this.avancarEDevolverAnterior(); // pula tokens inesperados } } this.validarSegmentoPrincipal('principal'); while (!this.estaNoFinal() && this.simbolos[this.atual].tipo !== calango_1.default.FIM_PRINCIPAL) { const resolucaoDeclaracao = await this.resolverDeclaracaoForaDeBloco(); if (Array.isArray(resolucaoDeclaracao)) { declaracoes = declaracoes.concat(resolucaoDeclaracao); } else { declaracoes.push(resolucaoDeclaracao); } } return { declaracoes: declaracoes.filter((d) => d), erros: this.erros, }; } } exports.AvaliadorSintaticoCalango = AvaliadorSintaticoCalango; //# sourceMappingURL=avaliador-sintatico-calango.js.map