From 0b32ceadeace2e5650ecb5fe1daaebc571bb756d Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Fri, 25 Nov 2022 18:27:22 -0600 Subject: ¡Expresiones if y while! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilador/astree/expr.py | 10 +++- compilador/parse/expr.py | 137 ++++++++++++++++++++++++++++++++++++---------- pruebas/sintaxis2.es | 6 ++ 3 files changed, 123 insertions(+), 30 deletions(-) diff --git a/compilador/astree/expr.py b/compilador/astree/expr.py index d5a2cb0..c074553 100644 --- a/compilador/astree/expr.py +++ b/compilador/astree/expr.py @@ -114,9 +114,17 @@ class ReadExpr: # A return statement. # -# return a +# retorna a ReturnExpr = Optional[Expr] +# A while expression. +# +# mientras (cond) { } +@dataclass +class WhileExpr: + cond: Expr + body: Expr + # A Javañol expression. Expr = (AccessExpr | AssignExpr | BinarithmExpr | CallExpr | ConstantExpr | ForExpr | IfExpr | CompoundExpr | diff --git a/compilador/parse/expr.py b/compilador/parse/expr.py index 806fb8d..fdd5ce1 100644 --- a/compilador/parse/expr.py +++ b/compilador/parse/expr.py @@ -4,14 +4,24 @@ from tabla import Token, LexToken from parse.base import BaseParser from parse.ident import ParseIdent from errors import Error -from astree.expr import Expr, BinarithmOp, ConstantExpr, NumberConstant, CallExpr, PrintExpr, BinarithmExpr, CompoundExpr, ReadExpr, AccessExpr, AssignExpr +from astree.expr import Expr, BinarithmOp, ConstantExpr, NumberConstant, CallExpr, PrintExpr, BinarithmExpr, CompoundExpr, ReadExpr, AccessExpr, AssignExpr, IfExpr, WhileExpr class ParseExpr: def __init__(self, parser: BaseParser): self.parser = parser def expr(self) -> (Expr | Error): - obj = self.binarithm(None, 0) + obj = None + tok = self.parser.peek(Token.IF, Token.WHILE) + if not tok: + obj = self.binarithm(None, 0) + elif tok.tipo == Token.IF: + obj = self.if_expr() + elif tok.tipo == Token.WHILE: + obj = self.while_expr() + + if type(obj) is Error: + return obj # = tok = self.parser._try(Token.EQUAL) @@ -32,7 +42,6 @@ class ParseExpr: return AssignExpr(_object = obj, value = expr) - # WIP def binarithm(self, lvalue: Expr, i: int) -> (Expr | Error): _lvalue = lvalue if not lvalue: @@ -91,6 +100,9 @@ class ParseExpr: return CallExpr(lvalue = lvalue, args = args) + def cast(self, lvalue: Optional[Expr]) -> (Expr | Error): + return self.unarithm() + def compound_expr(self) -> (Expr | Error): items: List[Expr] = [] @@ -99,16 +111,11 @@ class ParseExpr: if type(lbracket) is Error: return lbracket - while True: - # } - item = self.parser.peek(Token.R_BRACKET) - if item: break - + while not self.parser.peek(Token.R_BRACKET): # Expresión item = self.expr() if type(item) is Error: return item - items.append(item) # ; @@ -123,6 +130,19 @@ class ParseExpr: return CompoundExpr(exprs = items) + 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 + def builtin(self) -> (Expr | Error): tok: LexToken = self.parser.peek(Token.PRINT, Token.READ) if not tok: @@ -132,6 +152,43 @@ class ParseExpr: return self.print_expr() elif tok.tipo == Token.READ: return self.read_expr() + + def if_expr(self) -> (Expr | Error): + # si + _if = self.parser.want(Token.IF) + if type(_if) is Error: + return _if + + # ( + lparen = self.parser.want(Token.L_PAREN) + if type(lparen) is Error: + return lparen + + # Condición + cond = self.expr() + if type(cond) is Error: + return cond + + # ) + rparen = self.parser.want(Token.R_PAREN) + if type(rparen) is Error: + return rparen + + # Verdadero + tbranch = self.expr() + if type(tbranch) is Error: + return tbranch + + # Falso + fbranch = None + if self.parser._try(Token.ELSE): + fbranch = self.expr() + if type(fbranch) is Error: + return fbranch + + return IfExpr(cond = cond, + tbranch = tbranch, + fbranch = fbranch) def postfix(self, lvalue: Optional[Expr]) -> (Expr | Error): _lvalue: Optional[Expr] = lvalue @@ -180,23 +237,7 @@ class ParseExpr: 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): @@ -221,8 +262,40 @@ class ParseExpr: return ident def unarithm(self) -> (Expr | Error): + if self.parser._try(Token.L_BRACKET): + self.parser.unlex() + return self.compound_expr() return self.builtin() + def while_expr(self) -> (Expr | Error): + # mientras + _while = self.parser.want(Token.WHILE) + if type(_while) is Error: + return _while + + # ( + lparen = self.parser.want(Token.L_PAREN) + if type(lparen) is Error: + return lparen + + # Condición + cond = self.expr() + if type(cond) is Error: + return cond + + # ) + rparen = self.parser.want(Token.R_PAREN) + if type(rparen) is Error: + return rparen + + # Expresión + body = self.expr() + if type(body) is Error: + return body + + return WhileExpr(cond = cond, + body = body) + def binop_for_tok(self, tok: Token) -> (BinarithmOp | NoReturn): if tok is Token.SLASH: return BinarithmOp.DIV @@ -246,10 +319,16 @@ class ParseExpr: return BinarithmOp.TIMES def precedence(self, tok: Token) -> int: - if tok in [Token.EQEQ, Token.NOTEQ]: + if tok == Token.OR: return 0 - elif tok in [Token.PLUS, Token.MINUS]: + elif tok == Token.AND: return 1 - elif tok in [Token.TIMES, Token.SLASH]: + elif tok in [Token.EQEQ, Token.NOTEQ]: return 2 + elif tok in [Token.LT, Token.LEQ, Token.GT, Token.GEQ]: + return 3 + elif tok in [Token.PLUS, Token.MINUS]: + return 4 + elif tok in [Token.TIMES, Token.SLASH]: + return 5 return -1 diff --git a/pruebas/sintaxis2.es b/pruebas/sintaxis2.es index d1c49f9..c8cbb59 100644 --- a/pruebas/sintaxis2.es +++ b/pruebas/sintaxis2.es @@ -5,9 +5,15 @@ caracter d; funcion entero a (entero a, cadena b) { b = ((40 - 2) + 10) * 2 + b(10); imprimir ("Hola"); + si (a >= 10) { + imprimir (b + 20); + } sino b; leer d; }; funcion caracter b (booleano a) { imprimir ("Adiós"); + mientras (a < 10) { + imprimir ("Hola"); + }; leer x; }; \ No newline at end of file -- cgit v1.2.3