aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2022-11-25 16:33:08 -0600
committerIván Ávalos <avalos@disroot.org>2022-11-25 16:33:08 -0600
commitc7f014aef2c86d7a17f2642180732a6ba9b2a125 (patch)
treed3439be25bf3ef025abb67144fc9c2fe1114530b
parent43ca3b1370fcb9e7cb8c3126ebf4e6ed7833fc13 (diff)
downloadjavanol-c7f014aef2c86d7a17f2642180732a6ba9b2a125.tar.gz
javanol-c7f014aef2c86d7a17f2642180732a6ba9b2a125.tar.bz2
javanol-c7f014aef2c86d7a17f2642180732a6ba9b2a125.zip
¡Ya hay funciones y (algunas) expresiones!
-rw-r--r--compilador/astree/expr.py29
-rw-r--r--compilador/errors.py7
-rw-r--r--compilador/parse/decl.py6
-rw-r--r--compilador/parse/expr.py255
-rw-r--r--pruebas/sintaxis2.es11
5 files changed, 290 insertions, 18 deletions
diff --git a/compilador/astree/expr.py b/compilador/astree/expr.py
index 1bb7f4f..d5a2cb0 100644
--- a/compilador/astree/expr.py
+++ b/compilador/astree/expr.py
@@ -3,10 +3,19 @@ from enum import Enum, auto
from typing import List, Optional
from astree.type import Type
+from astree.ident import Ident
Expr = None
-# An assignment expression
+# An identifier access expression.
+#
+# a
+AccessIdentifier = Ident
+
+# An access expression.
+AccessExpr = AccessIdentifier
+
+# An assignment expression.
#
# a = 10
@dataclass
@@ -14,7 +23,7 @@ class AssignExpr:
_object: Expr
value: Expr
-# A binary arithmetic operator
+# A binary arithmetic operator.
class BinarithmOp(Enum):
BAND = '&'
BOR = '|'
@@ -92,19 +101,23 @@ class IfExpr:
# A print statement.
#
# imprimir a
-PrintExpr = Expr
+@dataclass
+class PrintExpr:
+ expr: Expr
# A read statement.
#
# leer a
-ReadExpr = Expr
+@dataclass
+class ReadExpr:
+ expr: AccessExpr
# A return statement.
#
# return a
ReturnExpr = Optional[Expr]
-# A Javañol expression
-Expr = (AssignExpr | BinarithmExpr | CallExpr | ConstantExpr |
- ForExpr | IfExpr | CompoundExpr | PrintExpr |
- ReadExpr | ReturnExpr)
+# A Javañol expression.
+Expr = (AccessExpr | AssignExpr | BinarithmExpr | CallExpr |
+ ConstantExpr | ForExpr | IfExpr | CompoundExpr |
+ PrintExpr | ReadExpr | ReturnExpr)
diff --git a/compilador/errors.py b/compilador/errors.py
index 5a4e7a2..6bb05b8 100644
--- a/compilador/errors.py
+++ b/compilador/errors.py
@@ -15,8 +15,11 @@ class Error:
'S_ESPERA_PC': 'Se esperaba `;`',
}
- def __init__(self, msg: str = None):
- self.message = msg
+ def __init__(self, msg: str = None, numlinea: int = None):
+ if numlinea:
+ self.message = "Error en la línea %d: %s" % (numlinea, msg)
+ else:
+ self.message = msg
@classmethod
def lex(self, error, numlinea: int):
diff --git a/compilador/parse/decl.py b/compilador/parse/decl.py
index 93666fc..aa9e23a 100644
--- a/compilador/parse/decl.py
+++ b/compilador/parse/decl.py
@@ -58,9 +58,13 @@ class ParseDecl:
if type(proto) is Error:
return proto
+ init = ParseExpr(self.parser).compound_expr()
+ if type(init) is Error:
+ return init
+
return DeclFunc(ident = ident,
prototype = proto,
- body = None)
+ body = init)
# Parses a declaration.
def decl(self) -> (Decl | Error):
diff --git a/compilador/parse/expr.py b/compilador/parse/expr.py
index 23b1a61..492b4e6 100644
--- a/compilador/parse/expr.py
+++ b/compilador/parse/expr.py
@@ -1,12 +1,257 @@
+from typing import NoReturn, Optional, cast
+
+from tabla import Token, LexToken
from parse.base import BaseParser
+from parse.ident import ParseIdent
from errors import Error
-from astree.expr import Expr
+from astree.expr import Expr, BinarithmOp, ConstantExpr, NumberConstant, CallExpr, PrintExpr, BinarithmExpr, CompoundExpr, ReadExpr, AccessExpr, AssignExpr
class ParseExpr:
def __init__(self, parser: BaseParser):
self.parser = parser
- def expr(self) -> Expr | Error:
- self.parser.iterador.next()
- return
-
+ def expr(self) -> (Expr | Error):
+ obj = self.binarithm(None, 0)
+
+ # =
+ tok = self.parser._try(Token.EQUAL)
+ if not tok:
+ return obj
+
+ error = self.parser.synassert(
+ isinstance(obj, AccessExpr),
+ "Se esperaba un objeto como destino de la asignación.")
+ if type(error) is Error:
+ return error
+
+ # Expresión
+ expr = self.expr()
+ if type(expr) is Error:
+ return expr
+
+ return AssignExpr(_object = obj,
+ value = expr)
+
+ # WIP
+ def binarithm(self, lvalue: Expr, i: int) -> (Expr | Error):
+ print(f'binarithm({lvalue}, {i})')
+ _lvalue = lvalue
+ if not lvalue:
+ _lvalue = self.cast(lvalue)
+ if type(_lvalue) is Error:
+ return _lvalue
+ print(f'lvalue = {_lvalue}')
+
+ tok = self.parser.lex()
+ print(f'tok = {tok}')
+ j: int = self.precedence(tok.tipo)
+ while j >= i:
+ op = self.binop_for_tok(tok.tipo)
+
+ rvalue = self.cast(_lvalue)
+ if type(rvalue) is Error:
+ return rvalue
+
+ tok = self.parser.lex()
+ k: int = self.precedence(tok.tipo)
+ while k > j:
+ self.parser.unlex()
+ rvalue = self.binarithm(rvalue, k)
+ if type(rvalue) is Error:
+ return rvalue
+ tok = self.parser.lex()
+
+ k = self.precedence(tok.tipo)
+
+ _lvalue = BinarithmExpr(op = op,
+ lvalue = _lvalue,
+ rvalue = rvalue)
+
+ j = self.precedence(tok.tipo)
+
+ self.parser.unlex()
+ return _lvalue
+
+ def call(self, lvalue: Expr) -> (Expr | Error):
+ args: List[Expr] = []
+
+ while not self.parser._try(Token.R_PAREN):
+ # Expresión
+ expr = self.expr()
+ if type(expr) is Error:
+ return epr
+
+ args.append(expr)
+
+ # ,
+ if self.parser._try(Token.COMMA):
+ continue
+
+ # )
+ if self.parser._try(Token.R_PAREN):
+ break
+
+ return CallExpr(lvalue = lvalue,
+ args = args)
+
+ def compound_expr(self) -> (Expr | Error):
+ items: List[Expr] = []
+
+ # {
+ lbracket = self.parser.want(Token.L_BRACKET)
+ if type(lbracket) is Error:
+ return lbracket
+
+ while True:
+ # }
+ item = self.parser.peek(Token.R_BRACKET)
+ if item: break
+
+ item = self.expr()
+ if type(item) is Error:
+ return item
+
+ items.append(item)
+
+ # ;
+ semicolon = self.parser.want(Token.SEMICOLON)
+ if type(semicolon) is Error:
+ return semicolon
+
+ # }
+ rbracket = self.parser.want(Token.R_BRACKET)
+ if type(rbracket) is Error:
+ return rbracket
+
+ return CompoundExpr(exprs = items)
+
+ def builtin(self) -> (Expr | Error):
+ tok: LexToken = self.parser.peek(Token.PRINT, Token.READ)
+ if not tok:
+ return self.postfix(None)
+
+ if tok.tipo == Token.PRINT:
+ return self.print_expr()
+ elif tok.tipo == Token.READ:
+ return self.read_expr()
+
+
+ def postfix(self, lvalue: Optional[Expr]) -> (Expr | Error):
+ _lvalue: Optional[Expr] = lvalue
+ if not lvalue:
+ _lvalue = self.plain_expression()
+ if type(_lvalue) == Error:
+ return _lvalue
+
+ tok: LexToken = self.parser._try(Token.L_PAREN)
+ if not tok:
+ return _lvalue
+
+ _next: Optional[LexToken] = None
+ if tok == Token.L_PAREN:
+ return self.call(_lvalue)
+
+ return self.postfix(_next)
+
+ def print_expr(self) -> (Expr | Error):
+ _print = self.parser.want(Token.PRINT)
+ if type(_print) is Error:
+ return _print
+
+ lparen = self.parser.want(Token.L_PAREN)
+ if type(lparen) is Error:
+ return lparen
+
+ expr = self.expr()
+ if type(expr) is Error:
+ return expr
+
+ rparen = self.parser.want(Token.R_PAREN)
+ if type(rparen) is Error:
+ return rparen
+
+ return PrintExpr(expr = expr)
+
+ def read_expr(self) -> (Expr | Error):
+ _read = self.parser.want(Token.READ)
+ if type(_read) is Error:
+ return _read
+
+ ident = ParseIdent(self.parser).ident()
+ if type(ident) is Error:
+ return ident
+
+ return ReadExpr(expr = ident)
+
+ # WIP
+ def cast(self, lvalue: Optional[Expr]) -> (Expr | Error):
+ return self.unarithm()
+
+ # WIP
+ def constant(self) -> (Expr | Error):
+ tok: LexToken = self.parser.lex()
+ expr: Optional[ConstantExpr] = None
+ if tok.tipo == Token.STRING_LIT:
+ expr: str = 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
+
+ # WIP
+ def plain_expression(self) -> (Expr | Error):
+ tok: LexToken = self.parser.peek()
+ if tok.tipo in [Token.BOOLEAN_LIT, Token.CHAR_LIT, Token.INT_LIT, Token.STRING_LIT]:
+ return self.constant()
+ elif tok.tipo == Token.L_PAREN:
+ lparen = self.parser.want(Token.L_PAREN)
+ if type(lparen) is Error:
+ return lparen
+ expr = self.expr()
+ if type(expr) is Error:
+ return expr
+ rparen = self.parser.want(Token.R_PAREN)
+ if type(rparen) is Error:
+ return rparen
+ elif tok.tipo == Token.IDENT:
+ ident = ParseIdent(self.parser).ident()
+ if type(ident) is Error:
+ return ident
+ return ident
+
+ def unarithm(self) -> (Expr | Error):
+ return self.builtin()
+
+ def binop_for_tok(self, tok: Token) -> (BinarithmOp | NoReturn):
+ if tok is Token.SLASH:
+ return BinarithmOp.DIV
+ elif tok is Token.GT:
+ return BinarithmOp.GT
+ elif tok is Token.GEQ:
+ return BinarithmOp.GTEQ
+ elif tok is Token.EQEQ:
+ return BinarithmOp.LEQUAL
+ elif tok is Token.LT:
+ return BinarithmOp.LESS
+ elif tok is Token.LEQ:
+ return BinarithmOp.LESSEQ
+ elif tok is Token.MINUS:
+ return BinarithmOp.MINUS
+ elif tok is Token.NOTEQ:
+ return BinarithmOp.NEQUAL
+ elif tok is Token.PLUS:
+ return BinarithmOp.PLUS
+ elif tok is Token.TIMES:
+ return BinarithmOp.TIMES
+
+ def precedence(self, tok: Token) -> int:
+ if tok in [Token.EQEQ, Token.NOTEQ]:
+ return 0
+ elif tok in [Token.PLUS, Token.MINUS]:
+ return 1
+ elif tok in [Token.TIMES, Token.SLASH]:
+ return 2
+ return -1
diff --git a/pruebas/sintaxis2.es b/pruebas/sintaxis2.es
index c89bee0..fdb9dd3 100644
--- a/pruebas/sintaxis2.es
+++ b/pruebas/sintaxis2.es
@@ -2,5 +2,12 @@ entero a = 10;
entero b = 20;
booleano c = verdadero;
caracter d;
-funcion entero a (entero a, cadena b);
-funcion caracter b (booleano a); \ No newline at end of file
+funcion entero a (entero a, cadena b) {
+ b = 40 + 2 * 10;
+ imprimir ("Hola");
+ leer d;
+};
+funcion caracter b (booleano a) {
+ imprimir ("Adiós");
+ leer x;
+}; \ No newline at end of file