diff options
author | Frederick Yin <fkfd@fkfd.me> | 2022-09-03 11:22:20 +0800 |
---|---|---|
committer | Frederick Yin <fkfd@fkfd.me> | 2022-09-03 11:22:20 +0800 |
commit | b1794edb3d76db7c1a86fc14a60bc95b833bc7c7 (patch) | |
tree | 582288c1618a74405d3c183410d7525b8d6aa31f /projects/hackc/statements.py | |
parent | bed429a1d17b43678a70bc286aac12a0bd6e387d (diff) |
hackc: more statements; UnexpectedToken
Diffstat (limited to 'projects/hackc/statements.py')
-rw-r--r-- | projects/hackc/statements.py | 156 |
1 files changed, 148 insertions, 8 deletions
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' <subroutine call> ';' + """ + 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' <expression>? ';' + """ + 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' '(' <expression> ')' '{' <statement list> '}' ('else' '{' <statement list '}')? + """ + if len(tokens) < 6 or tokens[0] != "if": + return (None, 0) + + if tokens[1] != LEFT_PAREN: + raise UnexpectedToken(LEFT_PAREN, tokens[1]) + + t = 2 + cond, dt = Expression.from_tokens(tokens[2:]) + if cond is None: + raise JackSyntaxError(f"Expected condition", tokens[2]) + t += dt + + if tokens[t] != RIGHT_PAREN: + raise UnexpectedToken(RIGHT_PAREN, tokens[t]) + if tokens[t + 1] != LEFT_BRACE: + raise UnexpectedToken(LEFT_BRACE, tokens[t + 1]) + t += 2 + + then, dt = StatementList.from_tokens(tokens[t:]) + t += dt + + if tokens[t] != RIGHT_BRACE: + raise UnexpectedToken(RIGHT_BRACE, tokens[t]) + t += 1 + + if tokens[t] != "else": + return (IfStatement(cond, then), t) + + if tokens[t + 1] != LEFT_BRACE: + raise UnexpectedToken(LEFT_BRACE, tokens[t + 1]) + + t += 2 + + else_then, dt = StatementList.from_tokens(tokens[t:]) + t += dt + + if tokens[t] != RIGHT_BRACE: + raise UnexpectedToken(RIGHT_BRACE, tokens[t]) + + return (IfStatement(cond, then, else_then), t + 1) + + def print_verbose(self): + print(f"If {self.condition} then:") + self.then.print_verbose() + if self.else_then is not None: + print("Else then:") + self.else_then.print_verbose() |