From 4b9d00c8d2bdc69ae876cd545397d52f08d2767c Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Fri, 19 Jan 2024 17:57:37 +0100 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20criado=20analisador=20sem=C3=A2ntic?= =?UTF-8?q?o=20do=20visualg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialetos/analisador-semantico-visualf.ts | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts new file mode 100644 index 00000000..e7e5c081 --- /dev/null +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts @@ -0,0 +1,263 @@ +import { Atribuir, Chamada, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, Super, TipoDe } from "../../construtos"; +import { + Bloco, + Classe, + Const, + ConstMultiplo, + Continua, + Declaracao, + Enquanto, + Escolha, + Escreva, + EscrevaMesmaLinha, + Expressao, + Fazer, + FuncaoDeclaracao, + Importar, + Leia, + LeiaMultiplo, + Para, + ParaCada, + Retorna, + Se, + Sustar, + Tente, + Var, + VarMultiplo +} from "../../declaracoes"; +import { SimboloInterface } from "../../interfaces"; +import { AnalisadorSemanticoInterface } from "../../interfaces/analisador-semantico-interface"; +import { DiagnosticoAnalisadorSemantico, DiagnosticoSeveridade } from "../../interfaces/erros"; +import { RetornoAnalisadorSemantico } from "../../interfaces/retornos/retorno-analisador-semantico"; +import { TiposDadosInterface } from "../../interfaces/tipos-dados-interface"; +import { ContinuarQuebra, RetornoQuebra, SustarQuebra } from "../../quebras"; +import { PilhaVariaveis } from "../pilha-variaveis"; + +interface VariavelHipoteticaInterface { + tipo: TiposDadosInterface; + subtipo?: 'texto' | 'número' | 'inteiro' | 'longo' | 'lógico'; + imutavel: boolean; + valor?: any +} + +interface FuncaoHipoteticaInterface { + valor: any +} + +export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface { + pilhaVariaveis: PilhaVariaveis; + variaveis: { [nomeVariavel: string]: VariavelHipoteticaInterface }; + funcoes: { [nomeFuncao: string]: FuncaoHipoteticaInterface } + atual: number; + diagnosticos: DiagnosticoAnalisadorSemantico[]; + + constructor() { + this.pilhaVariaveis = new PilhaVariaveis(); + this.variaveis = {}; + this.funcoes = {}; + this.atual = 0; + this.diagnosticos = []; + } + + erro(simbolo: SimboloInterface, mensagem: string): void { + this.diagnosticos.push({ + simbolo: simbolo, + mensagem: mensagem, + hashArquivo: simbolo.hashArquivo, + linha: simbolo.linha, + severidade: DiagnosticoSeveridade.ERRO + }); + } + + visitarDeclaracaoDeAtribuicao(expressao: Atribuir) { + return Promise.resolve() + } + + visitarDeclaracaoVar(declaracao: Var): Promise { + return Promise.resolve(); + } + + visitarDeclaracaoClasse(declaracao: Classe) { + return Promise.resolve(); + } + + visitarDeclaracaoConst(declaracao: Const): Promise { + return Promise.resolve(); + } + + visitarDeclaracaoConstMultiplo(declaracao: ConstMultiplo): Promise { + return Promise.resolve(); + } + + visitarDeclaracaoDeExpressao(declaracao: Expressao) { + return Promise.resolve(); + } + + visitarDeclaracaoDefinicaoFuncao(declaracao: FuncaoDeclaracao) { + return Promise.resolve(); + } + + visitarDeclaracaoEnquanto(declaracao: Enquanto) { + return Promise.resolve(); + } + + visitarDeclaracaoEscolha(declaracao: Escolha) { + return Promise.resolve(); + } + + visitarDeclaracaoEscreva(declaracao: Escreva) { + return Promise.resolve(); + } + + visitarDeclaracaoEscrevaMesmaLinha(declaracao: EscrevaMesmaLinha) { + return Promise.resolve(); + } + + visitarDeclaracaoFazer(declaracao: Fazer) { + return Promise.resolve(); + } + + visitarDeclaracaoImportar(declaracao: Importar) { + return Promise.resolve(); + } + + visitarDeclaracaoPara(declaracao: Para): Promise { + return Promise.resolve(); + } + + visitarDeclaracaoParaCada(declaracao: ParaCada): Promise { + return Promise.resolve(); + } + + visitarDeclaracaoSe(declaracao: Se) { + return Promise.resolve(); + } + + visitarDeclaracaoTente(declaracao: Tente) { + return Promise.resolve(); + } + + visitarDeclaracaoVarMultiplo(declaracao: VarMultiplo): Promise { + return Promise.resolve(); + } + + visitarExpressaoAcessoIndiceVariavel(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoVetor(expressao: any) { + return Promise.resolve(); + } + visitarExpressaoAcessoMetodo(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoAgrupamento(expressao: any): Promise { + return Promise.resolve(); + } + + visitarExpressaoAtribuicaoPorIndice(expressao: any): Promise { + return Promise.resolve(); + } + + visitarExpressaoBinaria(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoBloco(declaracao: Bloco): Promise { + return Promise.resolve(); + } + + visitarExpressaoContinua(declaracao?: Continua): ContinuarQuebra { + return Promise.resolve(); + } + + visitarExpressaoDeChamada(expressao: Chamada) { + return Promise.resolve() + } + + visitarExpressaoDeVariavel(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoDefinirValor(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoDeleguaFuncao(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoDicionario(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { + return Promise.resolve(); + } + + visitarExpressaoFalhar(expressao: any): Promise { + return Promise.resolve(); + } + + visitarExpressaoFimPara(declaracao: FimPara) { + return Promise.resolve(); + } + visitarExpressaoFormatacaoEscrita(declaracao: FormatacaoEscrita) { + return Promise.resolve(); + } + + visitarExpressaoIsto(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoLeia(expressao: Leia): Promise { + return Promise.resolve(); + } + + visitarExpressaoLeiaMultiplo(expressao: LeiaMultiplo): Promise { + return Promise.resolve(); + } + + visitarExpressaoLiteral(expressao: Literal): Promise { + return Promise.resolve(); + } + + visitarExpressaoLogica(expressao: any) { + return Promise.resolve(); + } + + visitarExpressaoRetornar(declaracao: Retorna): Promise { + return Promise.resolve(null); + } + + visitarExpressaoSuper(expressao: Super) { + return Promise.resolve(); + } + + visitarExpressaoSustar(declaracao?: Sustar): SustarQuebra { + return Promise.resolve(); + } + + visitarExpressaoTipoDe(expressao: TipoDe): Promise { + return Promise.resolve(); + } + + visitarExpressaoUnaria(expressao: any) { + return Promise.resolve(); + } + + analisar(declaracoes: Declaracao[]): RetornoAnalisadorSemantico { + this.variaveis = {}; + this.atual = 0; + this.diagnosticos = []; + while (this.atual < declaracoes.length) { + declaracoes[this.atual].aceitar(this); + this.atual++; + } + + return { + diagnosticos: this.diagnosticos + } as RetornoAnalisadorSemantico + } +} From 9063601250c950e84c815ca3e6c7e85d334a0be7 Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Fri, 19 Jan 2024 20:28:19 +0100 Subject: [PATCH 2/8] feat: renomeado o analisador e criado o teste de variavel inexistente --- ...alf.ts => analisador-semantico-visualg.ts} | 34 +++++++++++++++++-- testes/visualg/analisador-semantico.test.ts | 34 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) rename fontes/analisador-semantico/dialetos/{analisador-semantico-visualf.ts => analisador-semantico-visualg.ts} (81%) create mode 100644 testes/visualg/analisador-semantico.test.ts diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts similarity index 81% rename from fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts rename to fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts index e7e5c081..c0758656 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-visualf.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts @@ -1,4 +1,4 @@ -import { Atribuir, Chamada, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, Super, TipoDe } from "../../construtos"; +import { Atribuir, Chamada, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, Super, TipoDe, Variavel, Vetor } from "../../construtos"; import { Bloco, Classe, @@ -69,11 +69,27 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface }); } + aviso(simbolo: SimboloInterface, mensagem: string): void { + this.diagnosticos.push({ + simbolo: simbolo, + mensagem: mensagem, + hashArquivo: simbolo.hashArquivo, + linha: simbolo.linha, + severidade: DiagnosticoSeveridade.AVISO + }); + } + visitarDeclaracaoDeAtribuicao(expressao: Atribuir) { - return Promise.resolve() + return Promise.resolve(); } visitarDeclaracaoVar(declaracao: Var): Promise { + this.variaveis[declaracao.simbolo.lexema] = { + imutavel: false, + tipo: declaracao.tipo, + valor: declaracao.inicializador !== null ? declaracao.inicializador.valor !== undefined ? declaracao.inicializador.valor : declaracao.inicializador : undefined + } + console.log(declaracao.simbolo.lexema) return Promise.resolve(); } @@ -110,6 +126,20 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface } visitarDeclaracaoEscrevaMesmaLinha(declaracao: EscrevaMesmaLinha) { + declaracao.argumentos.forEach((argumento: FormatacaoEscrita) => { + if (argumento.expressao instanceof Variavel) { + if (!this.variaveis[argumento.expressao.simbolo.lexema]) { + this.erro(argumento.expressao.simbolo, `Variável '${argumento.expressao.simbolo.lexema}' não existe.`) + return Promise.resolve(); + } + if (this.variaveis[argumento.expressao.simbolo.lexema]?.valor === undefined) { + console.log("Acho que está passando aqui") + this.aviso(argumento.expressao.simbolo, `Variável '${argumento.expressao.simbolo.lexema}' não foi inicializada.`) + return Promise.resolve(); + } + } + }) + return Promise.resolve(); } diff --git a/testes/visualg/analisador-semantico.test.ts b/testes/visualg/analisador-semantico.test.ts new file mode 100644 index 00000000..e294460d --- /dev/null +++ b/testes/visualg/analisador-semantico.test.ts @@ -0,0 +1,34 @@ +import { AnalisadorSemanticoVisualg } from '../../fontes/analisador-semantico/dialetos/analisador-semantico-visualg' +import { AvaliadorSintaticoVisuAlg } from "../../fontes/avaliador-sintatico/dialetos"; +import { LexadorVisuAlg } from "../../fontes/lexador/dialetos"; + +describe('Analisador sêmantico (Visualg)', () => { + describe('analisar()', () => { + let lexador: LexadorVisuAlg; + let avaliadorSintaticoVisuAlg: AvaliadorSintaticoVisuAlg; + let analisadorSemanticoVisualg: AnalisadorSemanticoVisualg + + beforeEach(() => { + lexador = new LexadorVisuAlg(); + avaliadorSintaticoVisuAlg = new AvaliadorSintaticoVisuAlg(); + analisadorSemanticoVisualg = new AnalisadorSemanticoVisualg(); + }); + + + describe('Cenários de falha', () => { + it('Variável não existe', () => { + const retornoLexador = lexador.mapear([ + 'algoritmo "Declaração de variável"', + 'var', + 'inicio', + 'escreva(idade, "teste");', + 'fimalgoritmo' + ], -1); + const retornoAvaliadorSintatico = avaliadorSintaticoVisuAlg.analisar(retornoLexador, -1); + const retornoAnalisadorSemantico = analisadorSemanticoVisualg.analisar(retornoAvaliadorSintatico.declaracoes); + expect(retornoAnalisadorSemantico).toBeTruthy(); + expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); + }); + }) + }) +}) \ No newline at end of file From 333055e5645447fedd998ea8467b8c0f4579d5f9 Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Fri, 19 Jan 2024 21:20:25 +0100 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20apresentando=20o=20tipo=20de=20dado?= =?UTF-8?q?s=20e=20verificando=20na=20atribui=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialetos/analisador-semantico-visualg.ts | 46 +++++++++++++++++-- .../visualg/avaliador-sintatico-visualg.ts | 13 ++++-- testes/visualg/analisador-semantico.test.ts | 33 ++++++++++++- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts index c0758656..b6460106 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts @@ -80,7 +80,49 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface } visitarDeclaracaoDeAtribuicao(expressao: Atribuir) { - return Promise.resolve(); + const { simbolo, valor } = expressao; + let variavel = this.variaveis[simbolo.lexema]; + if (!variavel) { + this.erro( + simbolo, + `Variável ${simbolo.lexema} ainda não foi declarada.` + ); + return Promise.resolve(); + } + + + if (variavel.tipo) { + if (valor instanceof Literal && variavel.tipo.includes('[]')) { + this.erro(simbolo, `Atribuição inválida, esperado tipo '${variavel.tipo}' na atribuição.`); + return Promise.resolve(); + } + if (valor instanceof Vetor && !variavel.tipo.includes('[]')) { + this.erro(simbolo, `Atribuição inválida, esperado tipo '${variavel.tipo}' na atribuição.`); + return Promise.resolve(); + } + + if (valor instanceof Literal) { + let valorLiteral = typeof (valor as Literal).valor; + if (!['qualquer'].includes(variavel.tipo)) { + if (valorLiteral === 'string') { + if (variavel.tipo != 'texto') { + this.erro(simbolo, `Esperado tipo '${variavel.tipo}' na atribuição.`); + return Promise.resolve(); + } + } + if (valorLiteral === 'number') { + if (!['inteiro', 'real'].includes(variavel.tipo)) { + this.erro(simbolo, `Esperado tipo '${variavel.tipo}' na atribuição.`); + return Promise.resolve(); + } + } + } + } + } + + if (variavel) { + this.variaveis[simbolo.lexema].valor = valor; + } } visitarDeclaracaoVar(declaracao: Var): Promise { @@ -89,7 +131,6 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface tipo: declaracao.tipo, valor: declaracao.inicializador !== null ? declaracao.inicializador.valor !== undefined ? declaracao.inicializador.valor : declaracao.inicializador : undefined } - console.log(declaracao.simbolo.lexema) return Promise.resolve(); } @@ -133,7 +174,6 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface return Promise.resolve(); } if (this.variaveis[argumento.expressao.simbolo.lexema]?.valor === undefined) { - console.log("Acho que está passando aqui") this.aviso(argumento.expressao.simbolo, `Variável '${argumento.expressao.simbolo.lexema}' não foi inicializada.`) return Promise.resolve(); } diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index 7176038f..e2e80020 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -38,6 +38,7 @@ import { Simbolo } from '../../../lexador'; import tiposDeSimbolos from '../../../tipos-de-simbolos/visualg'; import { ParametroVisuAlg } from './parametro-visualg'; +import { TiposDadosInterface } from '../../../interfaces/tipos-dados-interface'; export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { blocoPrincipalIniciado: boolean; @@ -143,6 +144,7 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { * @returns Vetor de Construtos para inicialização de variáveis. */ private validarSegmentoVar(): Construto[] | Declaracao[] { + console.log("Estou verificando") // Podem haver linhas de comentários acima de `var`, que geram // quebras de linha. while (this.simbolos[this.atual].tipo === tiposDeSimbolos.QUEBRA_LINHA) { @@ -178,6 +180,7 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { break; default: const dadosVariaveis = this.logicaComumParametroVisuAlg(); + console.log(dadosVariaveis.tipo) // Se chegou até aqui, variáveis são válidas. // Devem ser declaradas com um valor inicial padrão. if (dadosVariaveis.tipo === tiposDeSimbolos.VETOR) { @@ -224,13 +227,15 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { this.atual++; } else { for (let identificador of dadosVariaveis.identificadores) { + const tipo = dadosVariaveis.tipo as TiposDadosInterface switch (dadosVariaveis.tipo) { case tiposDeSimbolos.CARACTER: case tiposDeSimbolos.CARACTERE: inicializacoes.push( new Var( identificador, - new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), '') + new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), ''), + tipo ) ); break; @@ -239,7 +244,8 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { inicializacoes.push( new Var( identificador, - new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), 0) + new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), 0), + tipo ) ); break; @@ -247,7 +253,8 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { inicializacoes.push( new Var( identificador, - new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), false) + new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), false), + tipo ) ); break; diff --git a/testes/visualg/analisador-semantico.test.ts b/testes/visualg/analisador-semantico.test.ts index e294460d..3ecc9511 100644 --- a/testes/visualg/analisador-semantico.test.ts +++ b/testes/visualg/analisador-semantico.test.ts @@ -16,7 +16,7 @@ describe('Analisador sêmantico (Visualg)', () => { describe('Cenários de falha', () => { - it('Variável não existe', () => { + it('Variável indefinida, não declarada(escreva)', () => { const retornoLexador = lexador.mapear([ 'algoritmo "Declaração de variável"', 'var', @@ -29,6 +29,37 @@ describe('Analisador sêmantico (Visualg)', () => { expect(retornoAnalisadorSemantico).toBeTruthy(); expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); }); + + it('Variável indefinida, não declarada(atribuição)', () => { + const retornoLexador = lexador.mapear([ + 'algoritmo "Atribuição de valor"', + 'var', + 'inicio', + 'idade <- 2', + 'fimalgoritmo' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintaticoVisuAlg.analisar(retornoLexador, -1); + const retornoAnalisadorSemantico = analisadorSemanticoVisualg.analisar(retornoAvaliadorSintatico.declaracoes); + expect(retornoAnalisadorSemantico).toBeTruthy(); + expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); + }); + + it('Atribuição inválida', () => { + const retornoLexador = lexador.mapear([ + 'algoritmo "Atribuição de valor"', + 'var', + 'idade: real', + 'inicio', + 'idade <- "2"', + 'fimalgoritmo' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintaticoVisuAlg.analisar(retornoLexador, -1); + const retornoAnalisadorSemantico = analisadorSemanticoVisualg.analisar(retornoAvaliadorSintatico.declaracoes); + expect(retornoAnalisadorSemantico).toBeTruthy(); + expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); + }); }) }) }) \ No newline at end of file From 61acad20c9e0cc4ac5e568c3a079e20d9af5d36d Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Sat, 20 Jan 2024 09:13:50 +0100 Subject: [PATCH 4/8] refactor: guardando o tipo de retorno --- .../visualg/avaliador-sintatico-visualg.ts | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index e2e80020..93eead2e 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -180,7 +180,6 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { break; default: const dadosVariaveis = this.logicaComumParametroVisuAlg(); - console.log(dadosVariaveis.tipo) // Se chegou até aqui, variáveis são válidas. // Devem ser declaradas com um valor inicial padrão. if (dadosVariaveis.tipo === tiposDeSimbolos.VETOR) { @@ -448,6 +447,34 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { return expressao; } + simboloAtual(): SimboloInterface { + return this.simbolos[this.atual]; + } + + verificarDefinicaoTipoAtual(): TiposDadosInterface { + const tipos = ['inteiro', 'qualquer', 'real', 'texto', 'vazio', 'vetor']; + + const lexema = this.simboloAtual().lexema.toLowerCase(); + const contemTipo = tipos.find((tipo) => tipo === lexema); + + if (contemTipo && this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO)) { + const tiposVetores = ['inteiro[]', 'qualquer[]', 'real[]', 'texto[]']; + this.avancarEDevolverAnterior(); + + if (!this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_DIREITO)) { + throw this.erro(this.simbolos[this.atual], "Esperado símbolo de fechamento do vetor ']'."); + } + + const contemTipoVetor = tiposVetores.find((tipo) => tipo === `${lexema}[]`); + + this.avancarEDevolverAnterior(); + + return contemTipoVetor as TiposDadosInterface; + } + + return contemTipo as TiposDadosInterface; + } + corpoDaFuncao(tipo: any): FuncaoConstruto { const simboloAnterior = this.simbolos[this.atual - 1]; @@ -456,6 +483,7 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { this.consumir(tiposDeSimbolos.DOIS_PONTOS, 'Esperado dois-pontos após nome de função.'); // Tipo retornado pela função. + let tipoRetorno = null if ( !this.verificarSeSimboloAtualEIgualA( tiposDeSimbolos.INTEIRO, @@ -469,7 +497,8 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { } this.consumir(tiposDeSimbolos.QUEBRA_LINHA, "Esperado quebra de linha após tipo retornado por 'funcao'."); - + tipoRetorno = this.verificarDefinicaoTipoAtual(); + this.avancarEDevolverAnterior(); const inicializacoes = this.validarSegmentoVar(); this.validarSegmentoInicio('função'); @@ -479,7 +508,8 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { this.hashArquivo, Number(simboloAnterior.linha), parametros, - corpo.filter((d) => d) + corpo.filter((d) => d), + tipoRetorno ); } From 879b4db4c939c6085ef183b6a6a2297a0386416b Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Sat, 20 Jan 2024 10:54:22 +0100 Subject: [PATCH 5/8] =?UTF-8?q?refactor:=20adicionando=20valida=C3=A7?= =?UTF-8?q?=C3=B5es=20para=20as=20fun=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialetos/analisador-semantico-visualg.ts | 57 ++++++++++++++++++- .../visualg/avaliador-sintatico-visualg.ts | 16 ++++-- fontes/interfaces/tipos-dados-interface.ts | 2 + testes/visualg/analisador-semantico.test.ts | 37 ++++++++++++ 4 files changed, 107 insertions(+), 5 deletions(-) diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts index b6460106..2c63d7b1 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts @@ -1,4 +1,4 @@ -import { Atribuir, Chamada, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, Super, TipoDe, Variavel, Vetor } from "../../construtos"; +import { Atribuir, Chamada, ExpressaoRegular, FimPara, FormatacaoEscrita, FuncaoConstruto, Literal, Super, TipoDe, Variavel, Vetor } from "../../construtos"; import { Bloco, Classe, @@ -151,6 +151,24 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface } visitarDeclaracaoDefinicaoFuncao(declaracao: FuncaoDeclaracao) { + for (let parametro of declaracao.funcao.parametros) { + if (parametro.hasOwnProperty('tipoDado') && !parametro.tipoDado.tipo) { + this.erro(declaracao.simbolo, `O tipo '${parametro.tipoDado.tipoInvalido}' não é valido`); + } + } + + if (declaracao.funcao.tipoRetorno === undefined) { + this.erro(declaracao.simbolo, `Declaração de retorno da função é inválida`); + } + + if (declaracao.funcao.parametros.length >= 255) { + this.erro(declaracao.simbolo, 'Não pode haver mais de 255 parâmetros'); + } + + this.funcoes[declaracao.simbolo.lexema] = { + valor: declaracao.funcao + } + return Promise.resolve(); } @@ -243,6 +261,43 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface } visitarExpressaoDeChamada(expressao: Chamada) { + if (expressao.entidadeChamada instanceof Variavel) { + const variavel = expressao.entidadeChamada as Variavel; + const funcaoChamada = this.variaveis[variavel.simbolo.lexema] || this.funcoes[variavel.simbolo.lexema] + if (!funcaoChamada) { + this.erro( + variavel.simbolo, + `Função '${variavel.simbolo.lexema} não foi declarada.'` + ) + return Promise.resolve(); + } + const funcao = funcaoChamada.valor as FuncaoConstruto; + if (funcao.parametros.length != expressao.argumentos.length) { + this.erro( + variavel.simbolo, + `Esperava ${funcao.parametros.length} ${funcao.parametros.length > 1 ? "argumentos" : "argumento"}, mas obteve ${expressao.argumentos.length}.` + ) + } + + for (let [indice, arg0] of funcao.parametros.entries()) { + const arg1 = expressao.argumentos[indice]; + if (arg1) { + if (arg0.tipoDado?.tipo.toLowerCase() === 'caracter' && typeof arg1.valor !== 'string') { + this.erro( + variavel.simbolo, + `O valor passado para o parâmetro '${arg0.tipoDado.nome}' é diferente do esperado pela função.` + ); + } + else if (['inteiro', 'real'].includes(arg0.tipoDado?.tipo.toLowerCase()) + && typeof arg1.valor !== 'number') { + this.erro( + variavel.simbolo, + `O valor passado para o parâmetro '${arg0.tipoDado.nome}' é diferente do esperado pela função.` + ); + } + } + } + } return Promise.resolve() } diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index 93eead2e..038ade36 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -448,21 +448,22 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { } simboloAtual(): SimboloInterface { - return this.simbolos[this.atual]; + return this.simbolos[this.atual - 2]; } verificarDefinicaoTipoAtual(): TiposDadosInterface { - const tipos = ['inteiro', 'qualquer', 'real', 'texto', 'vazio', 'vetor']; + const tipos = ['inteiro', 'qualquer', 'real', 'texto', 'vazio', 'vetor', 'caracter']; const lexema = this.simboloAtual().lexema.toLowerCase(); + const contemTipo = tipos.find((tipo) => tipo === lexema); if (contemTipo && this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO)) { - const tiposVetores = ['inteiro[]', 'qualquer[]', 'real[]', 'texto[]']; + const tiposVetores = ['inteiro[]', 'qualquer[]', 'real[]', 'texto[]', 'caracter[]']; this.avancarEDevolverAnterior(); if (!this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_DIREITO)) { - throw this.erro(this.simbolos[this.atual], "Esperado símbolo de fechamento do vetor ']'."); + throw this.erro(this.simbolos[this.atual - 1], "Esperado símbolo de fechamento do vetor ']'."); } const contemTipoVetor = tiposVetores.find((tipo) => tipo === `${lexema}[]`); @@ -967,11 +968,18 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) { while (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) { const dadosParametros = this.logicaComumParametroVisuAlg(); + const tipoDadoParametro = { + nome: dadosParametros.simbolo.lexema, + tipo: dadosParametros.tipo as TiposDadosInterface, + tipoInvalido: !dadosParametros.tipo ? this.simboloAtual().lexema : null + } + for (let parametro of dadosParametros.identificadores) { parametros.push({ abrangencia: 'padrao', nome: parametro, referencia: dadosParametros.referencia, + tipoDado: tipoDadoParametro, }); } } diff --git a/fontes/interfaces/tipos-dados-interface.ts b/fontes/interfaces/tipos-dados-interface.ts index a95581e2..a1161011 100644 --- a/fontes/interfaces/tipos-dados-interface.ts +++ b/fontes/interfaces/tipos-dados-interface.ts @@ -15,5 +15,7 @@ export type TiposDadosInterface = | 'símbolo' | 'texto' | 'texto[]' + | 'caracter' + | 'caracter[]' | 'vetor' | undefined; diff --git a/testes/visualg/analisador-semantico.test.ts b/testes/visualg/analisador-semantico.test.ts index 3ecc9511..88961e4c 100644 --- a/testes/visualg/analisador-semantico.test.ts +++ b/testes/visualg/analisador-semantico.test.ts @@ -60,6 +60,43 @@ describe('Analisador sêmantico (Visualg)', () => { expect(retornoAnalisadorSemantico).toBeTruthy(); expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); }); + + it("Chamada de função inexistente", () => { + const retornoLexador = lexador.mapear([ + 'algoritmo "definindo função"', + 'var', + 'resultado: caracter', + 'inicio', + 'saudacao(4);', + 'fimalgoritmo' + ], -1) + + const retornoAvaliadorSintatico = avaliadorSintaticoVisuAlg.analisar(retornoLexador, -1); + const retornoAnalisadorSemantico = analisadorSemanticoVisualg.analisar(retornoAvaliadorSintatico.declaracoes); + expect(retornoAnalisadorSemantico).toBeTruthy(); + expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); + }) + + it("Chamada de função com número de parametro diferentes", () => { + const retornoLexador = lexador.mapear([ + 'algoritmo "definindo função"', + 'var', + 'resultado: caracter', + 'função saudacao(nome: caracter): caracter', + 'var', + 'inicio', + 'retorna "Bem vindo " + nome', + 'fimfunção', + 'inicio', + 'saudacao(4);', + 'fimalgoritmo' + ], -1) + + const retornoAvaliadorSintatico = avaliadorSintaticoVisuAlg.analisar(retornoLexador, -1); + const retornoAnalisadorSemantico = analisadorSemanticoVisualg.analisar(retornoAvaliadorSintatico.declaracoes); + expect(retornoAnalisadorSemantico).toBeTruthy(); + expect(retornoAnalisadorSemantico.diagnosticos).toHaveLength(1); + }) }) }) }) \ No newline at end of file From cc455b1b3ead2ee03df98f00de2a2e4edc255836 Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Sat, 20 Jan 2024 11:33:51 +0100 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20resolvendo=20problema=20gerado=20ao?= =?UTF-8?q?=20avan=C3=A7ar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialetos/visualg/avaliador-sintatico-visualg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index 038ade36..664eaf09 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -499,7 +499,7 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { this.consumir(tiposDeSimbolos.QUEBRA_LINHA, "Esperado quebra de linha após tipo retornado por 'funcao'."); tipoRetorno = this.verificarDefinicaoTipoAtual(); - this.avancarEDevolverAnterior(); + /* this.avancarEDevolverAnterior(); */ const inicializacoes = this.validarSegmentoVar(); this.validarSegmentoInicio('função'); From 83e7933ed299fe08af18ab60a81877109fd9d5a1 Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Sat, 20 Jan 2024 12:20:37 +0100 Subject: [PATCH 7/8] refactor: exportando o analisador --- .../dialetos/analisador-semantico-visualg.ts | 6 ++++++ fontes/analisador-semantico/dialetos/index.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts index 2c63d7b1..b4c6540a 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-visualg.ts @@ -371,7 +371,13 @@ export class AnalisadorSemanticoVisualg implements AnalisadorSemanticoInterface visitarExpressaoUnaria(expressao: any) { return Promise.resolve(); } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + return Promise.resolve() + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + return Promise.resolve() + } analisar(declaracoes: Declaracao[]): RetornoAnalisadorSemantico { this.variaveis = {}; this.atual = 0; diff --git a/fontes/analisador-semantico/dialetos/index.ts b/fontes/analisador-semantico/dialetos/index.ts index 6df675a9..2bead003 100644 --- a/fontes/analisador-semantico/dialetos/index.ts +++ b/fontes/analisador-semantico/dialetos/index.ts @@ -1,2 +1,3 @@ export * from './analisador-semantico-birl'; export * from './analisador-semantico-mapler'; +export * from './analisador-semantico-visualg'; From cd6b4a1fb05f94c6b2c11bbc35460464cc3420df Mon Sep 17 00:00:00 2001 From: Aristidescosta Date: Wed, 24 Jan 2024 19:03:19 +0100 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20eliminando=20informa=C3=A7?= =?UTF-8?q?=C3=B5es=20desnecessarias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialetos/visualg/avaliador-sintatico-visualg.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index 607903da..525054e0 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -146,7 +146,6 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { * @returns Vetor de Construtos para inicialização de variáveis. */ private validarSegmentoVar(): Construto[] | Declaracao[] { - console.log("Estou verificando") // Podem haver linhas de comentários acima de `var`, que geram // quebras de linha. while (this.simbolos[this.atual].tipo === tiposDeSimbolos.QUEBRA_LINHA) { @@ -513,7 +512,6 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { this.consumir(tiposDeSimbolos.QUEBRA_LINHA, "Esperado quebra de linha após tipo retornado por 'funcao'."); tipoRetorno = this.verificarDefinicaoTipoAtual(); - /* this.avancarEDevolverAnterior(); */ const inicializacoes = this.validarSegmentoVar(); this.validarSegmentoInicio('função');