Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-empty-function": "off"
}
}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,7 @@ dist
.tern-port

# Yarn
package-lock.json
package-lock.json

#SQLite
*.db
13 changes: 13 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Execução",
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"cwd": "${workspaceRoot}",
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts"
],
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"]
},
{
"name": "Testes AvaliadorSintatico",
"type": "node",
Expand Down
16 changes: 16 additions & 0 deletions execucao.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// import { Lincones } from './fontes/lincones';
import { AvaliadorSintatico } from "./fontes/avaliador-sintatico";
import { Lexador } from "./fontes/lexador";

// const lincones = new Lincones();
const lexador = new Lexador();
const avaliadorSintatico = new AvaliadorSintatico();
const sentencaSelecao = 'SELECIONAR NOME, EMAIL DE clientes ONDE IDADE = 18;';
let resultadoLexador = lexador.mapear([sentencaSelecao]);
let teste = avaliadorSintatico.analisar(resultadoLexador);
console.log(teste);

const sentencaCriacao = 'CRIAR TABELA clientes(ID INTEIRO NAO NULO CHAVE PRIMARIA AUTO INCREMENTO, NOME TEXTO(100) NAO NULO, IDADE INTEIRO NAO NULO, EMAIL TEXTO(255) NAO NULO, ATIVO LOGICO NAO NULO);';
resultadoLexador = lexador.mapear([sentencaCriacao]);
teste = avaliadorSintatico.analisar(resultadoLexador);
console.log(teste);
12 changes: 8 additions & 4 deletions fontes/avaliador-sintatico/avaliador-sintatico-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export abstract class AvaliadorSintaticoBase
return this.simbolos[this.atual].tipo === tipo;
}

verificaSeLexemaSimboloAtual(lexama: string): boolean {
if (this.estaNoFinal()) return false;
return this.simbolos[this.atual].lexema === lexama;
}

avancarEDevolverAnterior(): SimboloInterface {
if (!this.estaNoFinal()) this.atual++;
return this.simbolos[this.atual - 1];
Expand All @@ -39,15 +44,14 @@ export abstract class AvaliadorSintaticoBase
}

verificarSeSimboloAtualEIgualA(...argumentos: string[]): boolean {
for (const argumento of argumentos) {
const tipoAtual = argumentos[argumento];
for (let i = 0; i < argumentos.length; i++) {
const tipoAtual = argumentos[i];
if (this.verificarTipoSimboloAtual(tipoAtual)) {
this.avancarEDevolverAnterior();
return true;
}
}

return false;
}

abstract declaracao(): void;
}
253 changes: 193 additions & 60 deletions fontes/avaliador-sintatico/avaliador-sintatico.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,214 @@
import {
Identificador,
Declaracao,
ParenteseEsquerdo,
ParenteseDireito,
Numero,
PontoEVirgula
} from '../declaracoes';
import { Virgula } from '../declaracoes/virgula';
import { SimboloInterface } from '../interfaces';
import { Condicao } from '../construtos';
import { Criar, Comando, Selecionar } from '../comandos';
import {
RetornoAvaliadorSintatico,
RetornoLexador
} from '../interfaces/retornos';
import tiposDeSimbolos from '../tipos-de-simbolos';
import { AvaliadorSintaticoBase } from './avaliador-sintatico-base';
import { Coluna } from '../construtos/coluna';

export class AvaliadorSintatico extends AvaliadorSintaticoBase {
declaracao() {
private avancar(): void {
if (!this.estaNoFinal()) {
this.atual++;
}
}

private declaracaoCriacaoColuna(): Coluna {
// Nome
const nomeDaColuna = this.consumir(tiposDeSimbolos.IDENTIFICADOR,
'Esperado identificador de nome de coluna em comando de criação de tabela.');

// Tipo de dados
let tipoColuna = null;
let tamanhoColuna = null;
switch (this.simbolos[this.atual].tipo) {
case tiposDeSimbolos.INTEIRO:
tipoColuna = tiposDeSimbolos.INTEIRO;
this.avancar();
break;
case tiposDeSimbolos.LOGICO:
tipoColuna = tiposDeSimbolos.LOGICO;
this.avancar();
break;
case tiposDeSimbolos.TEXTO:
tipoColuna = tiposDeSimbolos.TEXTO;
this.avancar();
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO)) {
tamanhoColuna = this.consumir(tiposDeSimbolos.NUMERO,
'Esperado tamanho de texto de coluna em comando de criação de tabela.');
this.consumir(tiposDeSimbolos.PARENTESE_DIREITO,
'Esperado parêntese direito após declaração de tamanho de coluna em comando de criação de tabela.');
}

break;
default:
throw this.erro(this.simbolos[this.atual],
'Esperado tipo de dados válido na definição de coluna em comando de criação de tabela.');
}

// Nulo/Não Nulo
let nulo = true;
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.NAO, tiposDeSimbolos.NULO)) {
const simboloAnterior = this.simbolos[this.atual - 1];
switch (simboloAnterior.tipo) {
case tiposDeSimbolos.NAO:
this.consumir(tiposDeSimbolos.NULO,
'Esperado palavra reservada "NULO" após palavra reservada "NÃO" em declaração de coluna em comando de criação de tabela.');
nulo = false;
break;
case tiposDeSimbolos.NULO:
default:
break;
}
}

// Chave primária?
let chavePrimaria = false;
let autoIncremento = false;
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE)) {
switch (this.simbolos[this.atual].tipo) {
case tiposDeSimbolos.PRIMARIA:
chavePrimaria = true;
this.avancar();
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.AUTO)) {
this.consumir(tiposDeSimbolos.INCREMENTO,
'Esperado palavra reservada "INCREMENTO" após palavra reservada "AUTO" em declaração de coluna em comando de criação de tabela.');
autoIncremento = true;
}
break;
default:
throw this.erro(this.simbolos[this.atual],
'Esperado palavra reservada "PRIMARIA" após palavra reservada "CHAVE" na definição de coluna em comando de criação de tabela.');
}
}

return new Coluna(nomeDaColuna.lexema, tipoColuna, tamanhoColuna, nulo, chavePrimaria, false);
}

private declaracaoCriar(): Criar {
// Essa linha nunca deve retornar erro.
this.consumir(tiposDeSimbolos.CRIAR, 'Esperado palavra reservada "CRIAR".');

switch (this.simbolos[this.atual].tipo) {
case 'TABELA':
default:
return this.declaracaoCriarTabela();
}
}

private declaracaoCriarTabela() {
// Essa linha nunca deve retornar erro.
this.consumir(tiposDeSimbolos.TABELA, 'Esperado palavra reservada "TABELA".');

const nomeDaTabela = this.consumir(tiposDeSimbolos.IDENTIFICADOR,
'Esperado identificador de nome de tabela após palavra reservada "TABELA".');

this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO,
'Esperado abertura de parênteses após nome da tabela');

const colunas: Coluna[] = [];

do {
colunas.push(this.declaracaoCriacaoColuna());
}
while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));

this.consumir(tiposDeSimbolos.PARENTESE_DIREITO,
'Esperado fechamento de parênteses após nome da tabela');

// Ponto-e-vírgula opcional.
// TODO: trazer isso mais tarde.
// this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_VIRGULA);

return new Criar(
this.simbolos[this.atual].linha,
nomeDaTabela.lexema,
colunas
);
}

private declaracaoSelecionar() {
// Essa linha nunca deve retornar erro.
this.consumir(tiposDeSimbolos.SELECIONAR, 'Esperado palavra reservada "SELECIONAR".');

// Colunas
let tudo = false;
const colunas = [];
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.TUDO)) {
tudo = true;
} else {
do {
colunas.push(this.simbolos[this.atual].lexema);
this.avancar();
} while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA))
}

// De
this.consumir(tiposDeSimbolos.DE, 'Esperado palavra reservada "de" após definição das colunas em comando de seleção.');
const nomeTabela = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de coluna ou literal em condição de seleção.');

// Condições
const condicoes = [];
if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.ONDE)) {
do {
const esquerda = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de coluna ou literal em condição de seleção.');
if (![
tiposDeSimbolos.IGUAL,
tiposDeSimbolos.MAIOR,
tiposDeSimbolos.MAIOR_IGUAL,
tiposDeSimbolos.MENOR,
tiposDeSimbolos.MENOR_IGUAL
].includes(this.simbolos[this.atual].tipo)) {
throw this.erro(this.simbolos[this.atual], 'Esperado operador válido após identificador em condição de seleção.');
}

const operador = this.simbolos[this.atual].tipo;
this.avancar();

if (![
tiposDeSimbolos.IDENTIFICADOR,
tiposDeSimbolos.NUMERO,
tiposDeSimbolos.TEXTO
].includes(this.simbolos[this.atual].tipo)) {
throw this.erro(this.simbolos[this.atual], 'Esperado operador válido após identificador em condição de seleção.');
}

const direita = this.simbolos[this.atual];
this.avancar();

condicoes.push(new Condicao(esquerda, operador, direita.literal || direita.lexema));
} while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.E));
}

// Ponto-e-vírgula opcional.
this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_VIRGULA);

return new Selecionar(-1, nomeTabela.lexema, colunas, condicoes, tudo);
}

private declaracao() {
switch (this.simbolos[this.atual].tipo) {
case tiposDeSimbolos.IDENTIFICADOR:
return new Identificador(
this.consumir(
tiposDeSimbolos.IDENTIFICADOR,
'Esperava-se um identificador'
)
);
case tiposDeSimbolos.PARENTESE_DIREITO:
return new ParenteseDireito(
this.consumir(
tiposDeSimbolos.PARENTESE_DIREITO,
'Esperava-se um parentese direito'
)
);
case tiposDeSimbolos.PARENTESE_ESQUERDO:
return new ParenteseEsquerdo(
this.consumir(
tiposDeSimbolos.PARENTESE_ESQUERDO,
'Esperava-se um parentese esquerdo'
)
);
case tiposDeSimbolos.VIRGULA:
return new Virgula(
this.consumir(
tiposDeSimbolos.VIRGULA,
'Esperava-se uma vírgula'
)
);
case tiposDeSimbolos.NUMERO:
return new Numero(
this.consumir(
tiposDeSimbolos.NUMERO,
'Esperava-se um número'
)
);
case tiposDeSimbolos.PONTO_VIRGULA:
return new PontoEVirgula(
this.consumir(
tiposDeSimbolos.PONTO_VIRGULA,
'Esperava-se um ponto e vírgula'
)
);
case tiposDeSimbolos.CRIAR:
return this.declaracaoCriar();
case tiposDeSimbolos.SELECIONAR:
return this.declaracaoSelecionar();
default:
console.log(
`O tipo ${this.simbolos[this.atual].tipo} não é válido`
);
this.atual++;
this.avancar();
return null;
}
}
analisar(retornoLexador: RetornoLexador): RetornoAvaliadorSintatico {

public analisar(retornoLexador: RetornoLexador): RetornoAvaliadorSintatico {
this.erros = [];
this.atual = 0;
this.bloco = 0;
this.simbolos = retornoLexador?.simbolos || [];

const declaracoes: Declaracao[] = [];
const declaracoes: Comando[] = [];
while (!this.estaNoFinal()) {
declaracoes.push(this.declaracao() as Declaracao);
declaracoes.push(this.declaracao());
}

return {
Expand Down
3 changes: 2 additions & 1 deletion fontes/avaliador-sintatico/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { ErroAvaliadorSintatico } from './erro-avaliador-sintatico';
export { AvaliadorSintatico } from './avaliador-sintatico';
export { ErroAvaliadorSintatico } from './erro-avaliador-sintatico';
export * from '../construtos/coluna';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Declaracao } from "./declaracao";
import { Comando } from "./comando";

export class Atualizar extends Declaracao {
export class Atualizar extends Comando {
tabela: string;
colunasEValores: any[];
condicoes: any[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export class Declaracao {
export class Comando {
linha: number;
assinaturaMetodo: string;

Expand Down
12 changes: 12 additions & 0 deletions fontes/comandos/criar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Coluna } from '../avaliador-sintatico';
import { Comando } from './comando';

export class Criar extends Comando {
public tabela: string;
public colunas: Coluna[];
constructor(linha: number, tabela: string, colunas: Coluna[]) {
super(linha);
this.tabela = tabela;
this.colunas = colunas;
}
}
Loading