From a55cd744c6dae4bba01ec83c6d3603e4ec0627a3 Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Tue, 15 Nov 2022 00:34:55 -0600 Subject: Primeras fases de análisis sintáctico MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arbol.py | 26 ++++++++ lexer.py | 45 +++++++------- main.py | 2 +- parser.py | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shared.py | 7 +++ symbol.py | 70 ---------------------- tabla.py | 70 ++++++++++++++++++++++ 7 files changed, 330 insertions(+), 93 deletions(-) create mode 100644 arbol.py create mode 100644 parser.py create mode 100644 shared.py delete mode 100644 symbol.py create mode 100644 tabla.py diff --git a/arbol.py b/arbol.py new file mode 100644 index 0000000..7abcbe0 --- /dev/null +++ b/arbol.py @@ -0,0 +1,26 @@ +class Nodo: + def __init__(self, dato = None): + self.dato = dato + self.hijos = [] + + def print(self, n = 0): + s = ' ' * n + 'Nodo:' + "\n" + s += ' ' * n + "dato = " + str(self.dato) + "\n" + s += ' ' * n + "hijos =\n" + for h in self.hijos: + s += h.print(n + 1) + s += "\n" + return s + + def __str__(self): + return self.print() + + +class Arbol: + def __init__(self, raiz: Nodo = Nodo()): + self.raiz = raiz + + def __str__(self): + if self.raiz: + return str(self.raiz) + return "None" diff --git a/lexer.py b/lexer.py index 248dc52..1952a16 100644 --- a/lexer.py +++ b/lexer.py @@ -1,10 +1,13 @@ from enum import Enum -from symbol import LexToken, TablaLex, tokens +from tabla import LexToken, TablaLex, tokens +from parser import Parser +from shared import Control op_compuestos = ['>=', '<=', '==', '!=', '&&', '||', '++', '--'] op_simples_a = ['=', '+', '-', '&', '|'] # pueden ir al final del op compuesto op_simples_b = ['!', '<', '>'] # solo pueden ir al inicio del op compuesto op_simples = op_simples_a + op_simples_b +otros_tokens = ['{', '}', '(', ')', ',', '.', ';'] reservadas = { 'booleano': 'BOOLEAN', 'detener': 'BREAK', @@ -29,24 +32,21 @@ class Selector(Enum): COMMENT = 4 ENTERO = 5 -class Control(Enum): - SIGUIENTE = 0 - REPETIR = 1 - ERROR = 2 - class Lexer: - tabla = TablaLex() - numlinea = 1 - selector = Selector.NINGUNO - recol_string = '' - recol_caracter = '' - recol_comentario = '' - recol_operador = '' - recol_ident = '' - recol_entero = '' - - def inicio_lexer(self, data): - for l in data.splitlines(): + def __init__(self, data): + self.tabla = TablaLex() + self.numlinea = 1 + self.selector = Selector.NINGUNO + self.recol_string = '' + self.recol_caracter = '' + self.recol_comentario = '' + self.recol_operador = '' + self.recol_ident = '' + self.recol_entero = '' + self.data = data + + def inicio(self): + for l in self.data.splitlines(): for c in l + "\n": r = self.procesar(c) if r == 2: return @@ -57,10 +57,12 @@ class Lexer: # Imprimir tabla de símbolos print (str(self.tabla)) + Parser(self.tabla).inicio() + def procesar(self, c): - if c != "\t" and c != "\n": - print (c + ' (' + str(self.selector) + ')') + # if c != "\t" and c != "\n": + # print (c + ' (' + str(self.selector) + ')') if self.selector == Selector.NINGUNO: # Entrada a string @@ -89,8 +91,7 @@ class Lexer: self.recol_operador = c return Control.SIGUIENTE # Entrada a tokens simples - elif (c == '{' or c == '}' or c == '(' or c == ')' or - c == ',' or c == '.' or c == ';' or (c == '*' and self.recol_comentario == '')): + elif c in otros_tokens or (c == '*' and self.recol_comentario == ''): self.insertar_tabla(c, None, None) return Control.SIGUIENTE diff --git a/main.py b/main.py index 119336a..c541b16 100644 --- a/main.py +++ b/main.py @@ -27,7 +27,7 @@ class Main: def compilar_programa(self): self.output_file = filedialog.asksaveasfilename() data = self.text.get('1.0', 'end-1c') - Lexer().inicio_lexer(data) + Lexer(data).inicio() def ejecutar_programa(self): print('ejecutar_programa()') diff --git a/parser.py b/parser.py new file mode 100644 index 0000000..7b48bbd --- /dev/null +++ b/parser.py @@ -0,0 +1,203 @@ +from enum import Enum +from tabla import LexToken, TablaLex, tokens +from arbol import Arbol, Nodo +from shared import Control +from pprint import pprint + +valores = ['IDENT', 'BOOLEAN_LIT', 'CHAR_LIT', 'INT_LIT'] + +operadores = [ + '>=', '<=', '==', '!=', '&&', '||', '++', '--', + '=', '+', '-', '&', '|', '!', '<', '>' +] + +class Selector(Enum): + NINGUNO = 0 + DEF_VARIABLE = 1 + DIRECTIVA = 2 + EXPRESION = 3 + IF = 4 + FOR = 5 + WHILE = 6 + FUNCION = 7 + +class Parser: + def __init__(self, tabla): + self.arbol = Arbol() + self.pila_selector = [ + [Selector.NINGUNO, []] # selector, recolector + ] + self.pila_arbol = [self.arbol.raiz] + self.expresion = None + self.tabla = tabla + + def inicio (self): + for t in self.tabla.tabla: + r = self.procesar(t) + if r == 2: return + while r != Control.SIGUIENTE: + r = self.procesar(t) + if r == Control.ERROR: return + + print(str(self.arbol)) + + def procesar (self, t: LexToken): + if len(self.pila_selector) == 0: + return Control.SIGUIENTE + + # pprint (self.pila_selector[-1]) + + cima = self.pila_selector[-1] + + if cima[0] == Selector.NINGUNO: + # Entrada a definición de variable (o función) + if t.tipo in ['BOOLEAN', 'CHAR', 'INT', 'VOID']: + self.pila_selector.pop() + self.pila_selector.append([Selector.DEF_VARIABLE, [t]]) + return Control.SIGUIENTE + # Entrada a directiva del lenguaje + elif t.tipo in ['PRINT', 'READ', 'RETURN']: + self.pila_selector.pop() + self.pila_selector.append([Selector.DIRECTIVA, [t]]) + return Control.SIGUIENTE + # Entrada a expresión + elif t.tipo in valores: + self.pila_selector.pop() + self.pila_selector.append([Selector.EXPRESION, [t]]) + return Control.SIGUIENTE + # Entrada a if + elif t.tipo == 'IF': + self.pila_selector.pop() + self.pila_selector.append([Selector.IF, []]) + return Control.SIGUIENTE + # Entrada a for + elif t.tipo == 'FOR': + self.pila_selector.pop() + self.pila_selector.append([Selector.FOR, []]) + return Control.SIGUIENTE + # Entrada a while + elif t.tipo == 'WHILE': + self.pila_selector.pop() + self.pila_selector.append([Selector.WHILE, []]) + return Control.SIGUIENTE + + if cima[0] == Selector.DEF_VARIABLE: + return self.procesar_def_variable(t) + + if cima[0] == Selector.DIRECTIVA: + return self.procesar_directiva(t) + + if cima[0] == Selector.EXPRESION: + return self.procesar_expresion(t) + + if cima[0] == Selector.IF: + return self.procesar_if(t) + + if cima[0] == Selector.FOR: + return self.procesar_for(t) + + if cima[0] == Selector.WHILE: + return self.procesar_while(t) + + if cima[0] == Selector.FUNCION: + return self.procesar_funcion(t) + + return Control.SIGUIENTE + + def procesar_def_variable(self, t): + recol = self.pila_selector[-1][1] + + # tipo + if len(recol) == 1: + if t.tipo != 'IDENT': + print('Error: se esperaba identificador') + return Control.ERROR + recol.append(t) + return Control.SIGUIENTE + + # tipo + ident + if len(recol) == 2: + if t.tipo == ';': + self.pila_arbol[-1].hijos.append(Nodo({ + 'selector': Selector.DEF_VARIABLE, + 'tipo': recol[0].tipo, + 'nombre': recol[1].nombre + })) + self.pila_selector.pop() + elif t.tipo == '=': + recol.append(t) + else: + print('Error: se esperaba `;` o `=`') + return Control.ERROR + return Control.SIGUIENTE + + # tipo + ident + = + if len(recol) == 3: + if t.tipo in valores: + self.pila_selector.append([Selector.EXPRESION, [t]]) + recol.append(t) + else: + print('Error: se esperaba una expresión') + return Control.ERROR + return Control.SIGUIENTE + + # tipo + ident + = + expr + if len(recol) == 4: + if t.tipo == ';': + self.pila_arbol[-1].hijos.append(Nodo({ + 'selector': Selector.DEF_VARIABLE, + 'tipo': recol[0].tipo, + 'nombre': recol[1].nombre, + 'valor': self.expresion + })) + self.expresion = None + self.pila_selector.pop() + self.pila_selector.append([Selector.NINGUNO, []]) + else: + print('Error: se esperaba `;`') + return Control.ERROR + + return Control.SIGUIENTE + + def procesar_directiva(self, t): + return + + def procesar_expresion(self, t): + recol = self.pila_selector[-1][1] + tipo_ultimo = recol[-1].tipo + + if len(recol) == 1: + if tipo_ultimo in valores: + recol.append(recol[-1]) + else: + print('Error: se esperaba un identificador o una literal') + return Control.ERROR + + if tipo_ultimo in valores and t in operadores: + recol.append(t) + elif tipo_ultimo in operadores and t in valores: + recol.append(t) + elif tipo_ultimo in valores and t in valores: + print('Error: se esperaba un operador') + return Control.ERROR + elif tipo_ultimo in operadores and t in operadores: + print('Error: se esperaba un identificador o una literal') + return Control.ERROR + else: + self.expresion = recol + self.pila_selector.pop() + return Control.REPETIR + + return Control.SIGUIENTE + + def procesar_if(self, t): + return + + def procesar_for(self, t): + return + + def procesar_while(self, t): + return + + def procesar_funcion(self, t): + return diff --git a/shared.py b/shared.py new file mode 100644 index 0000000..e356255 --- /dev/null +++ b/shared.py @@ -0,0 +1,7 @@ +from enum import Enum + +class Control(Enum): + ERROR = -1 + SIGUIENTE = 0 + REPETIR = 1 + TERMINAR = 2 diff --git a/symbol.py b/symbol.py deleted file mode 100644 index c8ca424..0000000 --- a/symbol.py +++ /dev/null @@ -1,70 +0,0 @@ -from enum import Enum -from dataclasses import dataclass -from typing import Any - -reservadas = [ - 'BOOLEAN', - 'BREAK', - 'CHAR', - 'DOUBLE', - 'ELSE', - 'FOR' - 'IDENT', - 'IF', - 'INT', - 'PRINT', - 'READ', - 'RETURN', - 'STRING', - 'VOID', - 'WHILE' -] - -literales = [ - 'BOOLEAN_LIT', - 'CHAR_LIT', - 'DOUBLE_LIT', - 'INT_LIT', - 'STRING_LIT' -] - -tokens = reservadas + literales + [ - '{', '}', '(', ')', ',', '\'', - '"', ';', '=', '*', '/', '+', - '-', '>', '<', '>=', '<=', '&&', - '||', '==', '!=', '++', '--', '//' -] - -@dataclass -class LexToken: - tipo: str - nombre: str - valor: Any - numlinea: int - - def __str__(self): - return "LexToken(%s,%s,%s,%i)" % ( - self.tipo, self.nombre, self.valor, self.numlinea - ) - -class TablaLex: - def __init__(self): - self.tabla = [] - - def insertar(self, tok: LexToken): - self.tabla.append(tok) - - def buscar(self, nombre: str): - return [t for t in self.tabla if t.nombre == nombre][0] - - def actualizar(self, nombre: str, tok: LexToken): - for i, t in enumerate(self.tabla): - if t.nombre == nombre: - self.tabla[i] = tok - return - - def __str__(self): - output = "" - for t in self.tabla: - output += str(t) + "\n" - return output diff --git a/tabla.py b/tabla.py new file mode 100644 index 0000000..c8ca424 --- /dev/null +++ b/tabla.py @@ -0,0 +1,70 @@ +from enum import Enum +from dataclasses import dataclass +from typing import Any + +reservadas = [ + 'BOOLEAN', + 'BREAK', + 'CHAR', + 'DOUBLE', + 'ELSE', + 'FOR' + 'IDENT', + 'IF', + 'INT', + 'PRINT', + 'READ', + 'RETURN', + 'STRING', + 'VOID', + 'WHILE' +] + +literales = [ + 'BOOLEAN_LIT', + 'CHAR_LIT', + 'DOUBLE_LIT', + 'INT_LIT', + 'STRING_LIT' +] + +tokens = reservadas + literales + [ + '{', '}', '(', ')', ',', '\'', + '"', ';', '=', '*', '/', '+', + '-', '>', '<', '>=', '<=', '&&', + '||', '==', '!=', '++', '--', '//' +] + +@dataclass +class LexToken: + tipo: str + nombre: str + valor: Any + numlinea: int + + def __str__(self): + return "LexToken(%s,%s,%s,%i)" % ( + self.tipo, self.nombre, self.valor, self.numlinea + ) + +class TablaLex: + def __init__(self): + self.tabla = [] + + def insertar(self, tok: LexToken): + self.tabla.append(tok) + + def buscar(self, nombre: str): + return [t for t in self.tabla if t.nombre == nombre][0] + + def actualizar(self, nombre: str, tok: LexToken): + for i, t in enumerate(self.tabla): + if t.nombre == nombre: + self.tabla[i] = tok + return + + def __str__(self): + output = "" + for t in self.tabla: + output += str(t) + "\n" + return output -- cgit v1.2.3