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/statements.py | 156 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 8 deletions(-) (limited to 'projects/hackc/statements.py') diff --git a/projects/hackc/statements.py b/projects/hackc/statements.py index 16c123e..0e257ed 100644 --- a/projects/hackc/statements.py +++ b/projects/hackc/statements.py @@ -1,19 +1,42 @@ -from .expressions import Expression +from .expressions import Expression, SubroutineCall from .utils import * + class Statement: def __init__(self): pass @classmethod def from_tokens(cls, tokens: list) -> tuple: - for StatementClass in [LetStatement]: + for StatementClass in [LetStatement, DoStatement, ReturnStatement, IfStatement]: stmt, dt = StatementClass.from_tokens(tokens) if stmt is not None: return (stmt, dt) return (None, 0) + +class StatementList: + def __init__(self, statements: list[Statement]): + self.statements = statements + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + t = 0 + statements = [] + while True: + stmt, dt = Statement.from_tokens(tokens[t:]) + if stmt is None: + break + statements.append(stmt) + t += dt + return (StatementList(statements), t) + + def print_verbose(self): + for stmt in self.statements: + stmt.print_verbose() + + class LetStatement: def __init__(self, name, expr): self.name = name @@ -31,22 +54,139 @@ class LetStatement: name = tokens[1] if name.type != "identifier": - raise JackSyntaxError(f"Expected variable name, got `{name}` instead", name) + raise UnexpectedToken("variable name", name) if tokens[2] != "=": - raise JackSyntaxError(f"Expected `=`, got `{tokens[2]}` instead", tokens[2]) + raise UnexpectedToken("=", tokens[2]) t = 3 expr, dt = Expression.from_tokens(tokens[t:]) if expr is None: - raise JackSyntaxError(f"Expected expression", tokens[3]) + raise UnexpectedToken(f"Expected expression", tokens[3]) t += dt if tokens[t] != ";": - raise JackSyntaxError(f"Expected `;`, got `{tokens[t]}` instead", tokens[t]) + raise UnexpectedToken(";", tokens[t]) - t += 1 - return (LetStatement(name, expr), t) + return (LetStatement(name, expr), t + 1) def print_verbose(self): print(f"Let {self.name} be {self.expr}") + + +class DoStatement: + def __init__(self, subcall: SubroutineCall): + self.subcall = subcall + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct do statement. + + Format: + 'do' ';' + """ + if len(tokens) < 5 or tokens[0] != "do": + return (None, 0) + + t = 1 + subcall, dt = SubroutineCall.from_tokens(tokens[1:]) + if subcall is None: + raise UnexpectedToken("subroutine call", tokens[1]) + t += dt + + if tokens[t] != ";": + raise UnexpectedToken(";", tokens[t]) + + return (DoStatement(subcall), t + 1) + + def print_verbose(self): + print(f"Do {self.subcall}") + + +class ReturnStatement: + def __init__(self, expr: Expression): + self.expr = expr + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct return statement. + + Format: + 'return' ? ';' + """ + if len(tokens) < 3 or tokens[0] != "return": + return (None, 0) + + t = 1 + expr, dt = Expression.from_tokens(tokens[1:]) + t += dt + + if tokens[t] != ";": + raise UnexpectedToken(";", tokens[t]) + + return (ReturnStatement(expr), t + 1) + + def print_verbose(self): + print(f"Return {self.expr or 'null'}") + + +class IfStatement: + def __init__(self, condition: Expression, then: StatementList, else_then=None): + self.condition = condition + self.then = then + self.else_then = else_then + + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct if statement. + + Format: + 'if' '(' ')' '{' '}' ('else' '{'