From b1794edb3d76db7c1a86fc14a60bc95b833bc7c7 Mon Sep 17 00:00:00 2001 From: Frederick Yin Date: Sat, 3 Sep 2022 11:22:20 +0800 Subject: hackc: more statements; UnexpectedToken --- projects/hackc/expressions.py | 96 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 17 deletions(-) (limited to 'projects/hackc/expressions.py') diff --git a/projects/hackc/expressions.py b/projects/hackc/expressions.py index f4623da..2e08cef 100644 --- a/projects/hackc/expressions.py +++ b/projects/hackc/expressions.py @@ -24,9 +24,7 @@ class Term: """Format: '(' ')'""" expr, dt = Expression.from_tokens(tokens[1:]) if tokens[dt + 1] != RIGHT_PAREN: - raise JackSyntaxError( - f"Expected `{RIGHT_PAREN}`, got `{tokens[dt]}` instead", tokens[dt] - ) + raise UnaryTerm(RIGHT_PAREN, tokens[dt]) return (expr, dt + 2) if tokens[0].type == "identifier": if tokens[1] in [LEFT_PAREN, "."]: @@ -69,9 +67,7 @@ class SubscriptTerm: raise JackSyntaxError(f"Expected subscript", tokens[2]) t += dt if tokens[t] != RIGHT_BRACKET: - raise JackSyntaxError( - f"Expected `{RIGHT_BRACKET}`, got `{tokens[t]}` instead", tokens[t] - ) + raise UnexpectedToken(RIGHT_BRACKET, tokens[t]) return (SubscriptTerm(var, sub), t + 1) def __str__(self): @@ -95,16 +91,6 @@ class UnaryTerm: return f"({self.op}{self.term})" -class SubroutineCall: - def __init__(self, name: Token, exprs: list): - self.name = name - self.exprs = exprs - - @classmethod - def from_tokens(cls, tokens: list) -> tuple: - pass - - class Expression: def __init__(self, lhs: Term, op=None, rhs=None): self.lhs = lhs @@ -119,6 +105,8 @@ class Expression: ( )? """ lhs, dt = Term.from_tokens(tokens) + if lhs is None: + return (None, 0) t = dt op = tokens[t] @@ -128,7 +116,7 @@ class Expression: t += 1 rhs, dt = Term.from_tokens(tokens[t:]) if rhs is None: - raise JSE(f"Expected other term, got `{rhs}` instead", rhs) + raise UnexpectedToken("other term", rhs) t += dt return (Expression(lhs, op, rhs), t) @@ -138,3 +126,77 @@ class Expression: return f"({self.lhs} {self.op} {self.rhs})" else: return str(self.lhs) + + +class ExpressionList: + def __init__(self, exprs: list[Expression]): + self.exprs = exprs + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct list of expressions. + + Format: + ( (',' )*)? + """ + t = 0 + exprs = [] + while True: + expr, dt = Expression.from_tokens(tokens[t:]) + if expr is None: + if t == 0: + # only allow lack of expression right after paren + break + else: + # expect expression after comma + raise JackSyntaxError(f"Expected expression", tokens[t]) + t += dt + exprs.append(expr) + if tokens[t] != ",": + break + t += 1 + + return (ExpressionList(exprs), t) + + def __str__(self): + return ", ".join([str(expr) for expr in self.exprs]) + + +class SubroutineCall: + def __init__(self, jack_class: Token, name: Token, exprs: ExpressionList): + self.jack_class = jack_class + self.name = name + self.exprs = exprs + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct invocation of subroutine. + + Format: + ( '.')? '(' ')' + """ + t = 0 + jack_class = None + if tokens[1] == ".": + jack_class = tokens[0] + t = 2 + + name = tokens[t] + if name.type != "identifier": + raise UnexpectedToken("subroutine name", name) + t += 1 + + if tokens[t] != LEFT_PAREN: + raise UnexpectedToken(LEFT_PAREN, tokens[t]) + t += 1 + + exprs, dt = ExpressionList.from_tokens(tokens[t:]) + t += dt + if tokens[t] != RIGHT_PAREN: + raise UnexpectedToken(RIGHT_PAREN, tokens[t]) + return (SubroutineCall(jack_class, name, exprs), t + 1) + + def __str__(self): + if self.jack_class is None: + return f"{self.name}({self.exprs})" + return f"{self.jack_class}.{self.name}({self.exprs})" -- cgit v1.2.3