From d3ebb5b032a7cddf6b0f7746b843781dfc9fd2a1 Mon Sep 17 00:00:00 2001 From: Leonel Sanches da Silva <53848829+leonelsanchesdasilva@users.noreply.github.com> Date: Sun, 7 Apr 2024 18:54:21 -0700 Subject: [PATCH] =?UTF-8?q?Mesma=20l=C3=B3gica=20recursiva=20para=20tipos?= =?UTF-8?q?=20reais=20e=20caracteres.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../avaliador-sintatico-portugol-studio.ts | 138 ++++++++++-------- 1 file changed, 76 insertions(+), 62 deletions(-) diff --git a/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts b/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts index 269d509..4f5e836 100644 --- a/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts +++ b/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts @@ -49,7 +49,7 @@ import tiposDeSimbolos from '../tipos-de-simbolos/lexico-regular'; * Há dois grupos de estruturas de alto nível: Construtos e Declarações. */ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { - private declaracoes: Declaracao[] = [] + private declaracoes: Declaracao[] = []; declaracaoEscreva(): Escreva { throw new Error('Método não implementado.'); @@ -214,7 +214,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } /** - * Declaração para inclusão de uma biblioteca. + * Declaração para inclusão de uma biblioteca. * Exemplo: `inclua biblioteca Matematica --> mat` seria o mesmo que * `const mat = importar('Matematica')` em Delégua, ou * `inclua biblioteca Matematica` (sem o nome da variável) seria o @@ -224,10 +224,16 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { declaracaoInclua(): Const { this.avancarEDevolverAnterior(); this.consumir(tiposDeSimbolos.BIBLIOTECA, 'Esperado palavra reservada "biblioteca" após "inclua".'); - const nomeBiblioteca = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado identificador com nome de biblioteca após palavra reservada "biblioteca"'); + const nomeBiblioteca = this.consumir( + tiposDeSimbolos.IDENTIFICADOR, + 'Esperado identificador com nome de biblioteca após palavra reservada "biblioteca"' + ); let constanteBiblioteca = nomeBiblioteca; if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.SETA)) { - constanteBiblioteca = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado identificador com nome de constante de biblioteca após seta de atribuição em declaração "inclua".'); + constanteBiblioteca = this.consumir( + tiposDeSimbolos.IDENTIFICADOR, + 'Esperado identificador com nome de constante de biblioteca após seta de atribuição em declaração "inclua".' + ); } return new Const( @@ -298,7 +304,6 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { let caminhoPadrao = null; while (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA) && !this.estaNoFinal()) { if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CASO)) { - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONTRARIO)) { if (caminhoPadrao !== null) { const excecao = new ErroAvaliadorSintatico( @@ -315,7 +320,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { do { declaracoes.push(this.resolverDeclaracaoForaDeBloco()); - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE); } while ( !this.verificarTipoSimboloAtual(tiposDeSimbolos.CASO) && !this.verificarTipoSimboloAtual(tiposDeSimbolos.CONTRARIO) && @@ -345,7 +350,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } else { declaracoes.push(retornoDeclaracao as Declaracao); } - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE); } while ( !this.verificarTipoSimboloAtual(tiposDeSimbolos.CASO) && !this.verificarTipoSimboloAtual(tiposDeSimbolos.CONTRARIO) && @@ -501,7 +506,11 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloCadeia.linha), valorInicializacao), "caracter") + new Var( + identificador, + new Literal(this.hashArquivo, Number(simboloCadeia.linha), valorInicializacao), + 'caracter' + ) ); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); @@ -518,19 +527,15 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'caracter'." ); - // Inicializações de variáveis podem ter valores definidos. - let valorInicializacao = ''; - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - const literalInicializacao = this.consumir( - tiposDeSimbolos.CARACTER, - 'Esperado literal de caracter após símbolo de igual em declaração de variável.' + const dimensoes = this.logicaComumDimensoesMatrizes(); + + if (dimensoes.length > 0) { + inicializacoes.push( + this.declaracaoVetorOuMatriz(simboloCaracter, identificador, dimensoes, 'caracter') ); - valorInicializacao = literalInicializacao.literal; + } else { + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloCaracter, identificador, 'caracter')); } - - inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloCaracter.linha), valorInicializacao), "caracter") - ); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); return inicializacoes; @@ -549,7 +554,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { /** * Método recursivo que lê os valores de inicialização de uma matriz de N dimensões. - * @param {number[]} dimensoes O número de dimensões faltantes. + * @param {number[]} dimensoes O número de dimensões faltantes. * Cada passo recursivo usa o primeiro valor e chama a função passando esse vetor, mas sem * o primeiro valor. */ @@ -584,26 +589,53 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { return valores; } - protected declaracaoVetorOuMatrizDeInteiros( - simboloInteiro: SimboloInterface, + protected declaracaoVetorOuMatriz( + simboloTipo: SimboloInterface, identificador: SimboloInterface, - dimensoes: number[] + dimensoes: number[], + tipoDados: string = 'inteiro' ) { - let valorInicializacao: Matriz = new Matriz(this.hashArquivo, Number(simboloInteiro.linha), dimensoes, null); + let valorInicializacao: Matriz = new Matriz(this.hashArquivo, Number(simboloTipo.linha), dimensoes, null); if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { valorInicializacao.valores = this.lerValoresAtribuicaoMatriz(dimensoes); } - return new Var(identificador, valorInicializacao, "inteiro[]"); + return new Var(identificador, valorInicializacao, `${tipoDados}[]` as any); } - protected declaracaoTrivialInteiro(simboloInteiro: SimboloInterface, identificador: SimboloInterface) { + protected declaracaoVariavelSemDimensoes( + simboloInteiro: SimboloInterface, + identificador: SimboloInterface, + tipoDados: string = 'inteiro' + ) { // Inicializações de variáveis podem ter valores definidos. let valorInicializacao: Construto = new Literal(this.hashArquivo, Number(simboloInteiro.linha), 0); if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { valorInicializacao = this.expressao(); } - return new Var(identificador, valorInicializacao, 'inteiro'); + return new Var(identificador, valorInicializacao, tipoDados as any); + } + + protected logicaComumDimensoesMatrizes(): number[] { + let dimensoes = []; + while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) { + let simboloNumeroPosicoes: SimboloInterface; + if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INTEIRO)) { + simboloNumeroPosicoes = this.simboloAnterior(); + } + + this.consumir( + tiposDeSimbolos.COLCHETE_DIREITO, + 'Esperado fechamento de identificação de número de posições de uma dimensão de vetor ou matriz.' + ); + + // Portugol Studio permite declarar vetores sem posições definidas. + // Quando isso acontece, definimos a quantidade de posições de uma dimensão como -1. + const numeroPosicoes = simboloNumeroPosicoes ? Number(simboloNumeroPosicoes.literal) : -1; + dimensoes.push(numeroPosicoes); + } + + return dimensoes; } declaracaoInteiros(): Var[] { @@ -616,27 +648,12 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'inteiro'." ); - let dimensoes = []; - while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) { - const numeroPosicoes = this.consumir( - tiposDeSimbolos.INTEIRO, - 'Esperado número inteiro para definir quantas posições terá a dimensão do vetor ou matriz.' - ); - - this.consumir( - tiposDeSimbolos.COLCHETE_DIREITO, - 'Esperado fechamento de identificação de número de posições de uma dimensão de vetor ou matriz.' - ); - - dimensoes.push(Number(numeroPosicoes.literal)); - } + const dimensoes = this.logicaComumDimensoesMatrizes(); if (dimensoes.length > 0) { - inicializacoes.push( - this.declaracaoVetorOuMatrizDeInteiros(simboloInteiro, identificador, dimensoes) - ); + inicializacoes.push(this.declaracaoVetorOuMatriz(simboloInteiro, identificador, dimensoes)); } else { - inicializacoes.push(this.declaracaoTrivialInteiro(simboloInteiro, identificador)); + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloInteiro, identificador)); } } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); @@ -686,7 +703,11 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloLogico.linha), valorInicializacao), 'lógico') + new Var( + identificador, + new Literal(this.hashArquivo, Number(simboloLogico.linha), valorInicializacao), + 'lógico' + ) ); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); @@ -694,7 +715,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } declaracaoRetorne(): Retorna { - this.avancarEDevolverAnterior() + this.avancarEDevolverAnterior(); const simboloChave = this.simbolos[this.atual]; let valor = null; @@ -740,7 +761,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { let incrementar = null; if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) { incrementar = this.expressao(); - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR); } this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após cláusulas"); @@ -763,25 +784,18 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'real'." ); - // Inicializações de variáveis podem ter valores definidos. - let valorInicializacao = 0; - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - const literalInicializacao = this.consumir( - tiposDeSimbolos.REAL, - 'Esperado literal real após símbolo de igual em declaração de variável.' - ); - valorInicializacao = Number(literalInicializacao.literal); - } + const dimensoes = this.logicaComumDimensoesMatrizes(); - inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloReal.linha), valorInicializacao), 'real') - ); + if (dimensoes.length > 0) { + inicializacoes.push(this.declaracaoVetorOuMatriz(simboloReal, identificador, dimensoes, 'real')); + } else { + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloReal, identificador, 'real')); + } } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); return inicializacoes; } - expressao(): Construto { return this.atribuir(); } @@ -892,7 +906,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { this.hashArquivo = hashArquivo || 0; this.simbolos = retornoLexador?.simbolos || []; - this.declaracoes = [] + this.declaracoes = []; this.validarEscopoProgramaEAvaliacaoSintatica();