Skip to content

Commit

Permalink
Implementação inicial de declaração de registro e acesso a propriedad…
Browse files Browse the repository at this point in the history
…es de registro.
  • Loading branch information
leonelsanchesdasilva committed Jun 23, 2024
1 parent e244190 commit 0c74fae
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 7 deletions.
82 changes: 75 additions & 7 deletions fontes/avaliador-sintatico/avaliador-sintatico-visualg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Aleatorio,
Bloco,
CabecalhoPrograma,
Classe,
Declaracao,
Enquanto,
Escolha,
Expand All @@ -15,6 +16,7 @@ import {
InicioAlgoritmo,
Leia,
Para,
PropriedadeClasse,
Retorna,
Se,
Sustar,
Expand All @@ -38,6 +40,7 @@ import {
Unario,
Variavel,
Comentario,
AcessoMetodoOuPropriedade,
} from '@designliquido/delegua/construtos';
import { ParametroInterface, SimboloInterface } from '@designliquido/delegua/interfaces';
import { Simbolo } from '@designliquido/delegua/lexador';
Expand All @@ -52,11 +55,13 @@ import tiposDeSimbolos from '../tipos-de-simbolos/lexico-regular';
export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
blocoPrincipalIniciado: boolean;
fimAlgoritmoEncontrado: boolean;
tiposConhecidos: string[];

constructor() {
super();
this.blocoPrincipalIniciado = false;
this.fimAlgoritmoEncontrado = false;
this.tiposConhecidos = [];
}

private validarSegmentoAlgoritmo(): SimboloInterface {
Expand Down Expand Up @@ -122,28 +127,31 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
this.consumir(tiposDeSimbolos.DOIS_PONTOS, 'Esperado dois-pontos após nome de variável.');

if (
!this.verificarSeSimboloAtualEIgualA(
![
tiposDeSimbolos.CARACTER,
tiposDeSimbolos.CARACTERE,
tiposDeSimbolos.INTEIRO,
tiposDeSimbolos.LOGICO,
tiposDeSimbolos.REAL,
tiposDeSimbolos.VETOR
)
].includes(this.simbolos[this.atual].tipo) && !this.tiposConhecidos.includes(this.simbolos[this.atual].lexema)
) {
throw this.erro(
this.simbolos[this.atual],
`Tipo de variável não conhecido: ${this.simbolos[this.atual].lexema}`
);
}

const simboloAnterior = this.simbolos[this.atual - 1];
const tipoVariavel: string = simboloAnterior.tipo;
const simboloTipo = this.avancarEDevolverAnterior();
let tipoVariavel: string = simboloTipo.tipo;
if (tipoVariavel === tiposDeSimbolos.IDENTIFICADOR) {
tipoVariavel = simboloTipo.lexema;
}

return {
identificadores,
tipo: tipoVariavel,
simbolo: simboloAnterior,
simbolo: simboloTipo,
referencia: referencia,
};
}
Expand Down Expand Up @@ -214,9 +222,9 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
tiposDeSimbolos.LOGICO,
tiposDeSimbolos.REAL,
tiposDeSimbolos.VETOR,
].includes(simboloTipo.tipo)
].includes(simboloTipo.tipo) && !this.tiposConhecidos.includes(simboloTipo.lexema)
) {
throw this.erro(simboloTipo, 'Tipo de variável não conhecido para inicialização de vetor.');
throw this.erro(simboloTipo, 'Tipo de variável ou registro não conhecido para inicialização de vetor.');
}
for (let identificador of dadosVariaveis.identificadores) {
inicializacoes.push(
Expand Down Expand Up @@ -265,6 +273,20 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
)
);
break;
default:
// Neste caso, o tipo pode ser um registro.
// Se for, verificamos aqui.
if (!this.tiposConhecidos.includes(dadosVariaveis.tipo)) {
throw this.erro(identificador, `Tipo ${dadosVariaveis.tipo} não parece ser de um tipo conhecido ou registro.`);
}

inicializacoes.push(
new Var(
identificador,
new Literal(this.hashArquivo, Number(dadosVariaveis.simbolo.linha), false),
dadosVariaveis.tipo as any
)
);
}
}
}
Expand Down Expand Up @@ -416,6 +438,9 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
while (true) {
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
expressao = this.finalizarChamada(expressao);
} else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO)) {
const nome = this.consumir(tiposDeSimbolos.IDENTIFICADOR, "Esperado nome da propriedade após '.'.");
expressao = new AcessoMetodoOuPropriedade(this.hashArquivo, expressao, nome);
} else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) {
const indices = [];
do {
Expand Down Expand Up @@ -1116,6 +1141,46 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
);
}

/**
* No VisuAlg não existe o conceito de classe, mas existe o conceito de registro,
* que é como se fosse uma classe sem métodos.
* Por isso aqui retornamos `Classe`
* @returns {Classe} Uma declaração de Classe, que serve como um tipo.
*/
declaracaoTipo(): Classe {
const simboloTipo: SimboloInterface = this.avancarEDevolverAnterior();
const nomeTipo: SimboloInterface = this.consumir(
tiposDeSimbolos.IDENTIFICADOR,
'Esperado identificador com o nome do tipo a ser declarado.'
);

this.consumir(tiposDeSimbolos.IGUAL, 'Esperado símbolo de igual após nome do tipo.');
this.consumir(tiposDeSimbolos.REGISTRO, 'Esperado expressão "registro" após sinal de igual em declaração de tipo.');
this.consumir(tiposDeSimbolos.QUEBRA_LINHA, 'Esperado quebra de linha após palavra reservada "registro".');

let propriedades = [];
while (this.simbolos[this.atual].tipo !== tiposDeSimbolos.FIM_REGISTRO) {
const nomePropriedade = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado identificador como nome de propriedade em especificação de registro.');
this.consumir(tiposDeSimbolos.DOIS_PONTOS, 'Esperado dois-pontos após nome de propriedade em especificação de registro.');
if (!this.verificarSeSimboloAtualEIgualA(
tiposDeSimbolos.INTEIRO,
tiposDeSimbolos.CARACTERE,
tiposDeSimbolos.REAL,
tiposDeSimbolos.LOGICO
)) {
throw this.erro(this.simbolos[this.atual], `Esperado um tipo válido de propriedade em especificação de registro. Atual: ${this.simbolos[this.atual].lexema}.`);
}

const tipoPropriedade = this.simboloAnterior();
this.consumir(tiposDeSimbolos.QUEBRA_LINHA, 'Esperado quebra de linha após tipo de propriedade em especificação de registro.');
propriedades.push(new PropriedadeClasse(nomePropriedade, tipoPropriedade.lexema))
}

this.consumir(tiposDeSimbolos.FIM_REGISTRO, 'Não deve ocorrer erro aqui.');
this.tiposConhecidos.push(nomeTipo.lexema);
return new Classe(simboloTipo, undefined, [], propriedades, []);
}

declaracaoAleatorio(): Aleatorio {
const simboloAleatorio: SimboloInterface = this.avancarEDevolverAnterior();

Expand Down Expand Up @@ -1223,6 +1288,8 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
return this.declaracaoRetorna();
case tiposDeSimbolos.SE:
return this.declaracaoSe();
case tiposDeSimbolos.TIPO:
return this.declaracaoTipo();
case tiposDeSimbolos.VAR:
if (this.blocoPrincipalIniciado) {
throw this.erro(
Expand Down Expand Up @@ -1260,6 +1327,7 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase {
this.blocos = 0;
this.blocoPrincipalIniciado = false;
this.fimAlgoritmoEncontrado = false;
this.tiposConhecidos = [];

this.hashArquivo = hashArquivo || 0;
this.simbolos = retornoLexador?.simbolos || [];
Expand Down
3 changes: 3 additions & 0 deletions fontes/lexador/palavras-reservadas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const palavrasReservadas = {
fimfunção: tiposDeSimbolos.FIM_FUNÇÃO,
fimpara: tiposDeSimbolos.FIM_PARA,
fimprocedimento: tiposDeSimbolos.FIM_PROCEDIMENTO,
fimregistro: tiposDeSimbolos.FIM_REGISTRO,
fimrepita: tiposDeSimbolos.FIM_REPITA,
fimse: tiposDeSimbolos.FIM_SE,
funcao: tiposDeSimbolos.FUNCAO,
Expand Down Expand Up @@ -62,13 +63,15 @@ export const palavrasReservadas = {
rand: tiposDeSimbolos.METODO_BIBLIOTECA_GLOBAL,
randi: tiposDeSimbolos.METODO_BIBLIOTECA_GLOBAL,
real: tiposDeSimbolos.REAL,
registro: tiposDeSimbolos.REGISTRO,
repita: tiposDeSimbolos.REPITA,
retorne: tiposDeSimbolos.RETORNE,
se: tiposDeSimbolos.SE,
sen: tiposDeSimbolos.METODO_BIBLIOTECA_GLOBAL,
senao: tiposDeSimbolos.SENAO,
senão: tiposDeSimbolos.SENÃO,
tan: tiposDeSimbolos.METODO_BIBLIOTECA_GLOBAL,
tipo: tiposDeSimbolos.TIPO,
var: tiposDeSimbolos.VAR,
verdadeiro: tiposDeSimbolos.VERDADEIRO,
vetor: tiposDeSimbolos.VETOR,
Expand Down
3 changes: 3 additions & 0 deletions fontes/tipos-de-simbolos/lexico-regular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default {
FIM_FUNÇÃO: 'FIM_FUNÇÃO',
FIM_PARA: 'FIM_PARA',
FIM_PROCEDIMENTO: 'FIM_PROCEDIMENTO',
FIM_REGISTRO: 'FIM_REGISTRO',
FIM_REPITA: 'FIM_REPITA',
FIM_SE: 'FIM_SE',
FUNCAO: 'FUNCAO',
Expand Down Expand Up @@ -65,6 +66,7 @@ export default {
PONTO: 'PONTO',
PROCEDIMENTO: 'PROCEDIMENTO',
REAL: 'REAL',
REGISTRO: 'REGISTRO',
REPITA: 'REPITA',
RETORNE: 'RETORNE',
SE: 'SE',
Expand All @@ -73,6 +75,7 @@ export default {
SETA_ATRIBUICAO: 'SETA_ATRIBUICAO',
SUBTRACAO: 'SUBTRACAO',
QUEBRA_LINHA: 'QUEBRA_LINHA',
TIPO: 'TIPO',
VAR: 'VAR',
VERDADEIRO: 'VERDADEIRO',
VETOR: 'VETOR',
Expand Down
124 changes: 124 additions & 0 deletions testes/avaliador-sintatico.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,130 @@ describe('Avaliador sintático', () => {
expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(8);
});

it('Sucesso - Registro', () => {
const retornoLexador = lexador.mapear(
[
`algoritmo "EXEMPLO_METALNOVO"`,
`Tipo deposito = registro`,
` codigo: inteiro`,
` descricao: caractere`,
` type: caractere`,
` preco: real`,
` quantidade: inteiro`,
`Fimregistro`,
`Var`,
` produto: vetor[1..50] de deposito`,
` i: inteiro`,
` maisCaro, maisBarato: deposito`,
` Procedimento lerProdutos()`,
` Inicio`,
` para i de 1 ate 50 faca`,
` escreva("CODIGO DO PRODUTO: ")`,
` leia(produto[i].codigo)`,
` escreva("DESCRIÇÃO DO PRODUTO: ")`,
` leia(produto[i].descricao)`,
` escreval("TIPOS DE PRODUTOS")`,
` escreval("PREGO = P")`,
` escreval("ARRUELA = A")`,
` escreval("PORCA = O")`,
` escreval("PARAFUSO = U")`,
` escreva("TIPO DE PRODUTO: ")`,
` leia(produto[i].type)`,
` escreva("PRECO DO PRODUTO: ")`,
` leia(produto[i].preco)`,
` escreva("QUANTIDADE DE PRODUTOS: ")`,
` leia(produto[i].quantidade)`,
` escreval("")`,
` fimpara`,
` Fimprocedimento`,
` Procedimento imprimirProdutos()`,
` Inicio`,
` para i de 1 ate 50 faca`,
` escreval("CODIGO DO PRODUTO: ", produto[i].codigo)`,
` escreval("DESCRIÇÃO DO PRODUTO: ", produto[i].descricao)`,
` escreval("TIPO DE PRODUTO: ", produto[i].type)`,
` escreval("PRECO DO PRODUTO: ", produto[i].preco)`,
` escreval("QUANTIDADE DE PRODUTOS: ", produto[i].quantidade)`,
` escreval("")`,
` fimpara`,
` Fimprocedimento`,
` Procedimento reajustarPrecos()`,
` Inicio`,
` para i de 1 ate 50 faca`,
` se (produto[i].type = "P") ou (produto[i].type = "p") entao`,
` produto[i].preco <- produto[i].preco + (produto[i].preco * 0.07)`,
` senao`,
` se (produto[i].type = "U") ou (produto[i].type = "u") entao`,
` produto[i].preco <- produto[i].preco + (produto[i].preco * 0.11)`,
` senao`,
` se (produto[i].type = "O") ou (produto[i].type = "o") entao`,
` produto[i].preco <- produto[i].preco + (produto[i].preco * 0.08)`,
` senao`,
` se (produto[i].type = "A") ou (produto[i].type = "a") entao`,
` produto[i].preco <- produto[i].preco + (produto[i].preco * 0.08)`,
` senao`,
` escreval("Codigo invalido")`,
` fimse`,
` fimse`,
` fimse`,
` fimse`,
` fimpara`,
` Fimprocedimento`,
` Procedimento imprimirMaisCaro()`,
` Inicio`,
` maisCaro <- produto[1]`,
` para i de 2 ate 50 faca`,
` se produto[i].preco > maisCaro.preco entao`,
` maisCaro <- produto[i]`,
` fimse`,
` fimpara`,
` escreval("CODIGO DO PRODUTO MAIS CARO: ", maisCaro.codigo)`,
` escreval("DESCRICAO DO PRODUTO MAIS CARO: ", maisCaro.descricao)`,
` escreval("PRECO DO PRODUTO MAIS CARO: ", maisCaro.preco)`,
` Fimprocedimento`,
` Procedimento imprimirMaisBarato()`,
` Inicio`,
` maisBarato <- produto[1]`,
` para i de 2 ate 50 faca`,
` se produto[i].preco < maisBarato.preco entao`,
` maisBarato <- produto[i]`,
` fimse`,
` fimpara`,
` escreval("CODIGO DO PRODUTO MAIS BARATO: ", maisBarato.codigo)`,
` escreval("DESCRICAO DO PRODUTO MAIS BARATO: ", maisBarato.descricao)`,
` escreval("PRECO DO PRODUTO MAIS BARATO: ", maisBarato.preco)`,
` Fimprocedimento`,
`Inicio`,
` escreval("|=====================================|")`,
` escreval("| LEITURA DE DADOS DOS PRODUTOS |")`,
` escreval("|=====================================|")`,
` lerProdutos()`,
` escreval("|=====================================|")`,
` escreval("| LISTA DE PRODUTOS ANTES DO REAJUSTE |")`,
` escreval("|=====================================|")`,
` imprimirProdutos()`,
` reajustarPrecos()`,
` escreval("|=====================================|")`,
` escreval("| LISTA DE PRODUTOS APOS REAJUSTE |")`,
` escreval("|=====================================|")`,
` imprimirProdutos()`,
` escreval("|=====================================|")`,
` escreval("| PRODUTO MAIS CARO |")`,
` escreval("|=====================================|")`,
` imprimirMaisCaro()`,
` escreval("|=====================================|")`,
` escreval("| PRODUTO MAIS BARATO |")`,
` escreval("|=====================================|")`,
` imprimirMaisBarato()`,
`Fimalgoritmo`
], -1);

const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);

expect(retornoAvaliadorSintatico).toBeTruthy();
expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(33);
});

it('Sucesso - Repita', () => {
const retornoLexador = lexador.mapear(
[
Expand Down
Loading

0 comments on commit 0c74fae

Please sign in to comment.