aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2022-11-25 21:29:55 -0600
committerIván Ávalos <avalos@disroot.org>2022-11-25 21:29:55 -0600
commit6b27930ef9c3eaede8d0c283ffa8376c40145f80 (patch)
treee2f2f8a25defb68283910edea33768054f435bc9
parent4b2fad150a292f882cee408d7f9746715225f7cb (diff)
downloadjavanol-6b27930ef9c3eaede8d0c283ffa8376c40145f80.tar.gz
javanol-6b27930ef9c3eaede8d0c283ffa8376c40145f80.tar.bz2
javanol-6b27930ef9c3eaede8d0c283ffa8376c40145f80.zip
¡Otra vez hay renderizador de AST!
-rw-r--r--compilador/astree/decl.py31
-rw-r--r--compilador/astree/expr.py151
-rw-r--r--compilador/astree/ident.py1
-rw-r--r--compilador/astree/type.py32
-rw-r--r--compilador/astree/unit.py14
-rw-r--r--compilador/parse/base.py4
-rw-r--r--compilador/parse/expr.py15
-rw-r--r--compilador/parse/type.py2
-rw-r--r--compilador/parser.py7
-rw-r--r--pruebas/sintaxis2.es1
10 files changed, 212 insertions, 46 deletions
diff --git a/compilador/astree/decl.py b/compilador/astree/decl.py
index 1e6de1d..99f5f75 100644
--- a/compilador/astree/decl.py
+++ b/compilador/astree/decl.py
@@ -1,6 +1,9 @@
+import uuid
+import graphviz as gv
from dataclasses import dataclass
-from typing import Optional
+from typing import Optional, cast
+from astree.graphable import Graphable
from astree.type import Type
from astree.ident import Ident
from astree.expr import Expr
@@ -9,19 +12,41 @@ from astree.expr import Expr
#
# entero a = 0;
@dataclass
-class DeclGlobal:
+class DeclGlobal(Graphable):
ident: Ident
_type: Type
init: Expr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'DeclGlobal')
+ dot.edge(parent, name, label = edge)
+ name_ident = uuid.uuid1().hex
+ dot.node(name_ident, self.ident)
+ dot.edge(name, name_ident, label = 'ident')
+ if isinstance(self.init, Graphable):
+ self.init.graph(dot, name, 'init')
+
# A function declaration.
#
# funcion vacio main() { ... }
@dataclass
-class DeclFunc:
+class DeclFunc(Graphable):
ident: Ident
prototype: Type
body: Optional[Expr]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'DeclFunc')
+ dot.edge(parent, name, label = edge)
+ name_ident = uuid.uuid1().hex
+ dot.node(name_ident, self.ident)
+ dot.edge(name, name_ident, label = 'ident')
+ if isinstance(self.prototype, Graphable):
+ self.prototype.graph(dot, name, 'prototype')
+ if self.body and isinstance(self.body, Graphable):
+ self.body.graph(dot, name, 'body')
+
# A Javañol declaration
Decl = DeclGlobal | DeclFunc
diff --git a/compilador/astree/expr.py b/compilador/astree/expr.py
index 527e606..b696d51 100644
--- a/compilador/astree/expr.py
+++ b/compilador/astree/expr.py
@@ -1,7 +1,10 @@
+import uuid
+import graphviz as gv
from dataclasses import dataclass
from enum import Enum, auto
from typing import List, Optional
+from astree.graphable import Graphable
from astree.type import Type
from astree.ident import Ident
@@ -10,7 +13,14 @@ Expr = None
# An identifier access expression.
#
# a
-AccessIdentifier = Ident
+@dataclass
+class AccessIdentifier(Graphable):
+ ident: Ident
+
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, self.ident)
+ dot.edge(parent, name, label = edge)
# An access expression.
AccessExpr = AccessIdentifier
@@ -19,10 +29,18 @@ AccessExpr = AccessIdentifier
#
# a = 10
@dataclass
-class AssignExpr:
- _object: Expr
+class AssignExpr(Graphable):
+ _object: AccessExpr
value: Expr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'AssignExpr')
+ dot.edge(parent, name, label = edge)
+ self._object.graph(dot, name, 'object')
+ if isinstance(self.value, Graphable):
+ self.value.graph(dot, name, 'value')
+
# A binary arithmetic operator.
class BinarithmOp(Enum):
BAND = '&'
@@ -44,26 +62,51 @@ class BinarithmOp(Enum):
#
# a * b
@dataclass
-class BinarithmExpr:
+class BinarithmExpr(Graphable):
op: BinarithmOp
lvalue: Expr
rvalue: Expr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'BinarithmExpr')
+ dot.edge(parent, name, label = edge)
+ name_op = uuid.uuid1().hex
+ dot.node(name_op, self.op.value)
+ dot.edge(name, name_op, 'op')
+ if isinstance(self.lvalue, Graphable):
+ self.lvalue.graph(dot, name, 'lvalue')
+ if isinstance(self.rvalue, Graphable):
+ self.rvalue.graph(dot, name, 'rvalue')
+
# A break expression.
#
# detener
@dataclass
-class BreakExpr:
- pass
+class BreakExpr(Graphable):
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'BreakExpr')
+ dot.edge(parent, name, label = edge)
# A function call expression.
#
# foo(bar)
@dataclass
-class CallExpr:
+class CallExpr(Graphable):
lvalue: Expr
args: List[Expr]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'CallExpr')
+ dot.edge(parent, name, label = edge)
+ if isinstance(self.lvalue, Graphable):
+ self.lvalue.graph(dot, name, 'lvalue')
+ for a in self.args:
+ if isinstance(a, Graphable):
+ a.graph(dot, name, 'arg')
+
# A compound expression.
#
# {
@@ -72,53 +115,84 @@ class CallExpr:
# // ...
# }
@dataclass
-class CompoundExpr:
+class CompoundExpr(Graphable):
exprs: List[Expr]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'CompoundExpr')
+ dot.edge(parent, name, label = edge)
+ for e in self.exprs:
+ if isinstance(e, Graphable):
+ e.graph(dot, name, 'expr')
+
# A continue expression.
#
# continuar
@dataclass
-class ContinueExpr:
- pass
+class ContinueExpr(Graphable):
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'ContinueExpr')
+ dot.edge(parent, name, label = edge)
# A scalar value.
-Value = bool | str | int | type(None)
+@dataclass
+class Value(Graphable):
+ value: bool | str | int
+
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, str(self.value))
+ dot.edge(parent, name, label = edge)
# An integer constant.
@dataclass
-class NumberConstant:
+class NumberConstant(Graphable):
value: int
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, str(self.value))
+ dot.edge(parent, name, label = edge)
+
# A constant expression.
ConstantExpr = Value | NumberConstant
-# A for loop.
-#
-# porcada (entero a = 0; a < b; a++) {}
-@dataclass
-class ForExpr:
- bindings: Optional[Expr]
- cond: Expr
- afterthought: Optional[Expr]
- body: Expr
-
# An if or if..else expression.
#
# si (a) { } sino { }
@dataclass
-class IfExpr:
+class IfExpr(Graphable):
cond: Expr
tbranch: Expr
fbranch: Optional[Expr]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'IfExpr')
+ dot.edge(parent, name, label = edge)
+ if isinstance(self.cond, Graphable):
+ self.cond.graph(dot, name, 'cond')
+ if isinstance(self.tbranch, Graphable):
+ self.tbranch.graph(dot, name, 'tbranch')
+ if self.fbranch and isinstance(self.fbranch, Graphable):
+ self.fbranch.graph(dot, name, 'fbranch')
+
# A print statement.
#
# imprimir a
@dataclass
-class PrintExpr:
+class PrintExpr(Graphable):
expr: Expr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'PrintExpr')
+ dot.edge(parent, name, label = edge)
+ if isinstance(self.expr, Graphable):
+ self.expr.graph(dot, name, 'expr')
+
# A read statement.
#
# leer a
@@ -126,6 +200,12 @@ class PrintExpr:
class ReadExpr:
expr: AccessExpr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'ReadExpr')
+ dot.edge(parent, name, label = edge)
+ self.expr.graph(dot, name, 'expr')
+
# A return statement.
#
# retorna a
@@ -133,16 +213,31 @@ class ReadExpr:
class ReturnExpr:
expr: Optional[Expr]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'ReturnExpr')
+ dot.edge(parent, name, label = edge)
+ if self.expr and isinstance(self.expr, Graphable):
+ self.expr.graph(dot, name, 'expr')
+
# A while expression.
#
# mientras (cond) { }
@dataclass
-class WhileExpr:
+class WhileExpr(Graphable):
cond: Expr
body: Expr
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'WhileExpr')
+ dot.edge(parent, name, label = edge)
+ if isinstance(self.cond, Graphable):
+ self.cond.graph(dot, name, 'cond')
+ if isinstance(self.body, Graphable):
+ self.body.graph(dot, name, 'body')
+
# A Javañol expression.
Expr = (AccessExpr | AssignExpr | BinarithmExpr | BreakExpr |
- CallExpr | ConstantExpr | ContinueExpr | ForExpr |
- IfExpr | CompoundExpr | PrintExpr | ReadExpr |
- ReturnExpr)
+ CallExpr | ConstantExpr | ContinueExpr | IfExpr |
+ CompoundExpr | PrintExpr | ReadExpr | ReturnExpr)
diff --git a/compilador/astree/ident.py b/compilador/astree/ident.py
index 936b745..ecc7edf 100644
--- a/compilador/astree/ident.py
+++ b/compilador/astree/ident.py
@@ -1,3 +1,4 @@
from typing import List
+from dataclasses import dataclass
Ident = str
diff --git a/compilador/astree/type.py b/compilador/astree/type.py
index 5389702..b254b91 100644
--- a/compilador/astree/type.py
+++ b/compilador/astree/type.py
@@ -1,7 +1,11 @@
+import uuid
+import graphviz as gv
+from pprint import pformat
from dataclasses import dataclass
from typing import List
from enum import Enum
+from astree.graphable import Graphable
from tabla import Token
Type = None
@@ -14,16 +18,40 @@ class BuiltinType(Enum):
INT = Token.INT
VOID = Token.VOID
+ def __str__(self):
+ return self.value.value
+
# A parameter to a function type.
@dataclass
-class FuncParam:
+class FuncParam(Graphable):
name: str
_type: Type
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'FuncParam')
+ dot.edge(parent, name, label = edge)
+ name_name = uuid.uuid1().hex
+ dot.node(name_name, self.name)
+ dot.edge(name, name_name, 'name')
+ name_type = uuid.uuid1().hex
+ dot.node(name_type, str(self._type))
+ dot.edge(name, name_type, 'type')
+
# funcion vacio ... (a: int, b: int ...)
@dataclass
-class FuncType:
+class FuncType(Graphable):
result: Type
params: List[FuncParam]
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'FuncType')
+ dot.edge(parent, name, label = edge)
+ name_result = uuid.uuid1().hex
+ dot.node(name_result, str(self.result))
+ dot.edge(name, name_result, 'result')
+ for p in self.params:
+ p.graph(dot, name, 'param')
+
Type = BuiltinType
diff --git a/compilador/astree/unit.py b/compilador/astree/unit.py
index 8ffdf19..c089214 100644
--- a/compilador/astree/unit.py
+++ b/compilador/astree/unit.py
@@ -1,9 +1,21 @@
+import uuid
+import graphviz as gv
from dataclasses import dataclass
from typing import List
+from astree.graphable import Graphable
from astree.decl import Decl
# A single compilation unit, representing all of the members of a namespace.
@dataclass
-class Unit:
+class Unit(Graphable):
decls: List[Decl]
+
+ def graph(self, dot: gv.Digraph, parent: str = None, edge: str = None) -> None:
+ name = uuid.uuid1().hex
+ dot.node(name, 'Unit')
+ if parent:
+ dot.edge(name, parent, label = edge)
+ for d in self.decls:
+ if isinstance(d, Graphable):
+ d.graph(dot, name, 'decl')
diff --git a/compilador/parse/base.py b/compilador/parse/base.py
index 9ee673b..bf9277d 100644
--- a/compilador/parse/base.py
+++ b/compilador/parse/base.py
@@ -61,10 +61,10 @@ class BaseParser:
def unlex(self):
self.iterador.back()
- def synassert(self, cond: bool, msg: str) -> (Error | NoReturn):
+ def synassert(self, cond: bool, msg: str, numlinea: int) -> (Error | NoReturn):
'''Returns a syntax error if cond is false and void
otherwise.
'''
if not cond:
- return Error(msg = msg)
+ return Error(msg = msg, numlinea = numlinea)
diff --git a/compilador/parse/expr.py b/compilador/parse/expr.py
index 6608f6a..2401f30 100644
--- a/compilador/parse/expr.py
+++ b/compilador/parse/expr.py
@@ -33,7 +33,8 @@ class ParseExpr:
error = self.parser.synassert(
isinstance(obj, AccessExpr),
- "Se esperaba un objeto como destino de la asignación.")
+ "Se esperaba un objeto como destino de la asignación.",
+ numlinea = tok.numlinea)
if type(error) is Error:
return error
@@ -88,7 +89,7 @@ class ParseExpr:
# Expresión
expr = self.expr()
if type(expr) is Error:
- return epr
+ return expr
args.append(expr)
@@ -136,12 +137,10 @@ class ParseExpr:
def constant(self) -> (Expr | Error):
tok: LexToken = self.parser.lex()
expr: Optional[ConstantExpr] = None
- if tok.tipo == Token.STRING_LIT:
- expr: str = tok.valor
+ if tok.tipo in [Token.STRING_LIT, Token.BOOLEAN_LIT]:
+ expr = Value(value = tok.valor)
elif tok.tipo == Token.INT_LIT:
expr = NumberConstant(value = tok.valor)
- elif tok.tipo == Token.BOOLEAN_LIT:
- expr: bool = tok.valor
else:
return Error(msg = "Se esperaba una constante.", numlinea = tok.numlinea)
return expr
@@ -260,7 +259,7 @@ class ParseExpr:
if type(ident) is Error:
return ident
- return ReadExpr(expr = ident)
+ return ReadExpr(expr = AccessExpr(ident = ident))
def plain_expression(self) -> (Expr | Error):
tok: LexToken = self.parser.peek()
@@ -281,7 +280,7 @@ class ParseExpr:
ident = ParseIdent(self.parser).ident()
if type(ident) is Error:
return ident
- return ident
+ return AccessIdentifier(ident = ident)
def unarithm(self) -> (Expr | Error):
if self.parser._try(Token.L_BRACKET):
diff --git a/compilador/parse/type.py b/compilador/parse/type.py
index 06c68d0..1fd0957 100644
--- a/compilador/parse/type.py
+++ b/compilador/parse/type.py
@@ -36,7 +36,7 @@ class ParseType:
if type(name) is Error:
return name
- params.append(FuncParam(name = name,
+ params.append(FuncParam(name = name.nombre,
_type = __type))
# ,
diff --git a/compilador/parser.py b/compilador/parser.py
index 99cabe7..e7f86db 100644
--- a/compilador/parser.py
+++ b/compilador/parser.py
@@ -1,4 +1,5 @@
import sys
+import graphviz as gv
from pprint import pprint
from tabla import TablaLex
@@ -8,6 +9,7 @@ from parse.unit import ParseUnit
class Parser:
def __init__(self, input_file: str):
+ self.input_file = input_file
self.tabla = TablaLex()
self.tabla.importar(input_file + '.tab')
self.iterador = self.tabla.iterar()
@@ -19,5 +21,8 @@ class Parser:
print (unit.message, file=sys.stderr)
return 1
- pprint(unit)
+ dot = gv.Digraph()
+ dot.attr('node', fontname='monospace')
+ unit.graph(dot)
+ dot.render(self.input_file + '.gv')
return 0
diff --git a/pruebas/sintaxis2.es b/pruebas/sintaxis2.es
index 09e5f1f..93cfdb7 100644
--- a/pruebas/sintaxis2.es
+++ b/pruebas/sintaxis2.es
@@ -5,6 +5,7 @@ caracter d;
funcion entero a (entero a, cadena b) {
b = ((40 - 2) + 10) * 2 + b(10);
imprimir ("Hola");
+ imprimir (1 + 2);
si (a >= 10) {
imprimir (b + 20);
} sino b;