summaryrefslogtreecommitdiff
path: root/projects/hackc/syntax.py
diff options
context:
space:
mode:
authorFrederick Yin <fkfd@fkfd.me>2022-08-30 15:21:25 +0800
committerFrederick Yin <fkfd@fkfd.me>2022-08-30 15:21:25 +0800
commit43df98ea8f491b31b580fd909e92d5fea486599d (patch)
tree1358545301a13413428859bbbe67cf0c279e7e75 /projects/hackc/syntax.py
parentb439d663a3f3d4d275f07339c1c0e794808f67d9 (diff)
hackc: print syntax error message
Diffstat (limited to 'projects/hackc/syntax.py')
-rw-r--r--projects/hackc/syntax.py31
1 files changed, 21 insertions, 10 deletions
diff --git a/projects/hackc/syntax.py b/projects/hackc/syntax.py
index c9be157..a07e69e 100644
--- a/projects/hackc/syntax.py
+++ b/projects/hackc/syntax.py
@@ -41,8 +41,15 @@ class Class:
f"Expected `{LEFT_BRACE}`, got `{tokens[2]}` instead", tokens[2]
)
- variables = Variable.from_tokens(tokens[3:])
- variables.print_verbose()
+ tokens_consumed = 3
+
+ while True:
+ variables, token_cnt = Variable.from_tokens(tokens[tokens_consumed:])
+ if variables is None:
+ break
+ variables.print_verbose()
+ tokens_consumed += token_cnt
+
return Class(name, variables, [])
@@ -53,10 +60,9 @@ class Variable:
self.names = names
@classmethod
- def from_tokens(cls, tokens: list):
+ def from_tokens(cls, tokens: list) -> tuple:
"""Construct variable declaration statement.
-
- You can declare multiple variables of one scope and type on the same line.
+ Return a tuple of a Variable instance and number of tokens consumed.
Format:
<scope> <type> <one or more names, joined with a comma>;
@@ -66,7 +72,7 @@ class Variable:
"""
if len(tokens) < 4 or tokens[0] not in SCOPES:
# not variable declaration
- return None
+ return (None, 0)
scope = tokens[0]
@@ -77,10 +83,12 @@ class Variable:
type = tokens[1]
+ tokens_consumed = 2
names = [] # names of variables
expecting_identifier = True
for token in tokens[2:]:
+ tokens_consumed += 1
if token.type == "identifier":
if expecting_identifier:
names.append(token)
@@ -94,19 +102,22 @@ class Variable:
expecting_identifier = True
else:
raise JackSyntaxError(
- f"Expected identifier, got `,` instead", token
+ f"Expected variable name, got `,` instead", token
)
elif token == ";":
if expecting_identifier:
raise JackSyntaxError(
- f"Expected identifier, got `;` instead", token
+ f"Expected variable name, got `;` instead", token
)
break
+ else:
+ expected = "variable name" if expecting_identifier else "`,` or `;`"
+ raise JackSyntaxError(f"Expected {expected}, got `{token}` instead", token)
- return Variable(scope, type, names)
+ return (Variable(scope, type, names), tokens_consumed)
def print_verbose(self):
- print(f"Declare {len(self.names)} variables:")
+ print(f"Declare {len(self.names)} variable(s):")
for name in self.names:
print(self.scope, self.type, name)