From 75811ebbd166b3cd271bb730323cc7ab4fdcb3a5 Mon Sep 17 00:00:00 2001 From: Frederick Yin Date: Tue, 30 Aug 2022 22:26:13 +0800 Subject: hackc: Subroutine takes care of parens --- projects/hackc/classes.py | 53 +++++++++++++++++++++++++++++++++-------------- projects/hackc/parser.py | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/projects/hackc/classes.py b/projects/hackc/classes.py index 1875ce7..14b3105 100644 --- a/projects/hackc/classes.py +++ b/projects/hackc/classes.py @@ -44,23 +44,33 @@ class Class: tokens_consumed = 3 + variables = [] while tokens_consumed < tokens_total: - variables, token_cnt = Variable.from_tokens( + variable, token_cnt = Variable.from_tokens( tokens[tokens_consumed:], context="class" ) - if variables is None: + if variable is None: break - variables.print_verbose() + variables.append(variable) tokens_consumed += token_cnt + subroutines = [] while tokens_consumed < tokens_total: subroutine, token_cnt = Subroutine.from_tokens(tokens[tokens_consumed:]) if subroutine is None: break - subroutine.print_verbose() + subroutines.append(subroutine) tokens_consumed += token_cnt - return Class(name, variables, []) + return Class(name, variables, subroutines) + + def print_verbose(self): + print(f"Define class {self.name}") + for variable in self.variables: + variable.print_verbose() + for subroutine in self.subroutines: + subroutine.print_verbose() + print(f"End of class {self.name}") class Variable: @@ -156,21 +166,20 @@ class ParamList: """Construct parameter list of subroutine from tokens. Format: - '(' ( (, )*)? ')' + ( (, )*)? = int | char | boolean | """ - if len(tokens) < 2 or tokens[0] != LEFT_PAREN: + if not tokens: return (None, 0) - if tokens[1] == RIGHT_PAREN: + if tokens[0] == RIGHT_PAREN: # empty param list, i.e. '(' ')' return (ParamList([]), 2) - tokens_consumed = 1 + tokens_consumed = 0 params = [] - for type, name, delim in zip(tokens[1::3], tokens[2::3], tokens[3::3]): - tokens_consumed += 3 + for type, name, delim in zip(tokens[0::3], tokens[1::3], tokens[2::3]): if type not in VAR_TYPES and type.type != "identifier": raise JackSyntaxError(f"Expected datatype, got `{type}` instead", type) if not name: @@ -183,9 +192,11 @@ class ParamList: if not delim: raise JackSyntaxError(f"Expected `,` or `{RIGHT_PAREN}`", name) if delim == ",": + tokens_consumed += 3 params.append((type, name)) continue elif delim == RIGHT_PAREN: + tokens_consumed += 2 params.append((type, name)) break else: @@ -195,6 +206,11 @@ class ParamList: return (ParamList(params), tokens_consumed) + def print_verbose(self): + print(f"Subroutine takes {len(self.params)} parameter(s):") + for param in self.params: + print(param[0], param[1]) + class Subroutine: def __init__( @@ -211,7 +227,7 @@ class Subroutine: """Construct subroutine from tokens. Format: - + '(' ')' '{' '}' = constructor | method | function = int | char | boolean | void | @@ -233,13 +249,20 @@ class Subroutine: f"Expected {category} name, got `{name}` instead", name ) - tokens_consumed = 3 + if tokens[3] != LEFT_PAREN: + raise JackSyntaxError( + f"Expected `{LEFT_PAREN}`, got `{tokens[3]}`", tokens[3] + ) + + tokens_consumed = 4 params, token_cnt = ParamList.from_tokens(tokens[tokens_consumed:]) if params is None: raise JackSyntaxError("Expected parameter list", tokens[tokens_consumed]) - tokens_consumed += token_cnt + # it can be safely assumed that the next token is ')' + tokens_consumed += token_cnt + 1 return (Subroutine(category, return_type, name, params, None), tokens_consumed) def print_verbose(self): - print(f"Define {self.category} {self.name}, returns {self.type}") + print(f"Define {self.category} {self.type} {self.name}") + self.params.print_verbose() diff --git a/projects/hackc/parser.py b/projects/hackc/parser.py index 2fc30ee..8375d52 100644 --- a/projects/hackc/parser.py +++ b/projects/hackc/parser.py @@ -96,6 +96,7 @@ class Parser: def parse(self): try: syntax_tree = Class.from_tokens(self.tokens) + syntax_tree.print_verbose() except JackSyntaxError as err: print_err(f"{self._fp}:{err.token.line_no + 1}") print_err(self.lines[err.token.line_no]) -- cgit v1.2.3