diff options
author | Frederick Yin <fkfd@fkfd.me> | 2022-09-01 12:56:25 +0800 |
---|---|---|
committer | Frederick Yin <fkfd@fkfd.me> | 2022-09-01 12:56:25 +0800 |
commit | bed429a1d17b43678a70bc286aac12a0bd6e387d (patch) | |
tree | cb691145f5daf3c7f19b5ac0b2e3c83deb4722d9 | |
parent | 1328887bb78ba034fe3d496ad8029382c1ec678e (diff) |
hackc: more terms
-rw-r--r-- | projects/hackc/classes.py | 3 | ||||
-rw-r--r-- | projects/hackc/expressions.py | 62 | ||||
-rw-r--r-- | projects/hackc/utils.py | 2 |
3 files changed, 62 insertions, 5 deletions
diff --git a/projects/hackc/classes.py b/projects/hackc/classes.py index b300d98..bd83cc4 100644 --- a/projects/hackc/classes.py +++ b/projects/hackc/classes.py @@ -180,7 +180,7 @@ class ParamList: if tokens[0] == RIGHT_PAREN: # empty param list, i.e. '(' ')' - return (ParamList([]), 2) + return (ParamList([]), 0) t = 0 params = [] @@ -313,3 +313,4 @@ class Subroutine: variable.print_verbose() for statement in self.statements: statement.print_verbose() + print(f"End of {self.category} {self.name}") diff --git a/projects/hackc/expressions.py b/projects/hackc/expressions.py index 3bc83d2..f4623da 100644 --- a/projects/hackc/expressions.py +++ b/projects/hackc/expressions.py @@ -17,8 +17,26 @@ class Term: if tokens[0].type in ["integer", "string"] or tokens[0] in CONSTANTS: return (ConstantTerm(tokens[0]), 1) if tokens[0].token in UNARY_OPS: + """Format: <unary op> <term>""" term, dt = Term.from_tokens(tokens[1:]) return (UnaryTerm(tokens[0], term), dt + 1) + if tokens[0] == LEFT_PAREN: + """Format: '(' <expression> ')'""" + 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] + ) + return (expr, dt + 2) + if tokens[0].type == "identifier": + if tokens[1] in [LEFT_PAREN, "."]: + # subroutine(...) or Class.subroutine(...) + return SubroutineCall.from_tokens(tokens) + if tokens[1] == LEFT_BRACKET: + # array[index] + return SubscriptTerm.from_tokens(tokens) + return (VarTerm(tokens[0]), 1) + return (None, 0) class ConstantTerm: @@ -29,17 +47,53 @@ class ConstantTerm: return self.term.token -class VarTerm: - def __init__(self, var: Token, subscript=None): +class SubscriptTerm: + def __init__(self, var: Token, subscript: Token): self.var = var self.subscript = subscript + @classmethod + def from_tokens(cls, tokens: list) -> tuple: + """Construct a subscripted array term. + + Format: + <var> '[' <subscript> ']' + """ + if tokens[0].type != "identifier" or tokens[1] != LEFT_BRACKET: + return (None, 0) + + var = tokens[0] + t = 2 + sub, dt = Expression.from_tokens(tokens[2:]) + if sub is None: + 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] + ) + return (SubscriptTerm(var, sub), t + 1) + + def __str__(self): + return f"{self.var}[{self.subscript}]" + + +class VarTerm: + def __init__(self, var: Token): + self.var = var + + def __str__(self): + return self.var.token + class UnaryTerm: def __init__(self, op: Token, term: Term): self.op = op self.term = term + def __str__(self): + return f"({self.op}{self.term})" + class SubroutineCall: def __init__(self, name: Token, exprs: list): @@ -72,7 +126,7 @@ class Expression: return (Expression(lhs), t) t += 1 - rhs, dt = Term.from_tokens(tokens[t]) + rhs, dt = Term.from_tokens(tokens[t:]) if rhs is None: raise JSE(f"Expected other term, got `{rhs}` instead", rhs) t += dt @@ -81,6 +135,6 @@ class Expression: def __str__(self): if self.op is not None: - return f"({self.lhs}) {self.op} ({self.rhs})" + return f"({self.lhs} {self.op} {self.rhs})" else: return str(self.lhs) diff --git a/projects/hackc/utils.py b/projects/hackc/utils.py index 58888ac..d375953 100644 --- a/projects/hackc/utils.py +++ b/projects/hackc/utils.py @@ -8,6 +8,8 @@ EXIT_CODE_EOF = 7 # vim autoindent misbehaves if I type these verbatim in strings LEFT_BRACE = "{" RIGHT_BRACE = "}" +LEFT_BRACKET = "[" +RIGHT_BRACKET = "]" LEFT_PAREN = "(" RIGHT_PAREN = ")" |