@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
502 lines • 29.7 kB
JavaScript
"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