Spaces:
Runtime error
Runtime error
| class Parser: | |
| def __init__(self, tokens): | |
| self.tokens = tokens | |
| self.pos = 0 | |
| self.errors = [] | |
| def peek(self): | |
| if self.pos >= len(self.tokens): | |
| return ('EOF', None) | |
| return self.tokens[self.pos] | |
| def consume(self, expected_type=None): | |
| token = self.peek() | |
| if expected_type and token[0] != expected_type: | |
| self.errors.append(f"Syntax Error: Expected {expected_type} but got {token[0]}") | |
| if token[0] != 'EOF': | |
| self.pos += 1 | |
| return token | |
| def parse(self): | |
| nodes = [] | |
| while self.peek()[0] != 'EOF': | |
| stmt = self.statement() | |
| if stmt: | |
| nodes.append(stmt) | |
| return nodes | |
| def statement(self): | |
| t_type, val = self.peek() | |
| if t_type == 'LBRACE': | |
| return self.block() | |
| # --- FIXED HERE: Accept all primitive data types --- | |
| if t_type == 'KEYWORD' and val in ('int', 'float', 'char', 'bool'): | |
| return self.declaration() | |
| if t_type == 'ID': | |
| return self.assignment() | |
| if t_type == 'KEYWORD' and val == 'print': | |
| return self.print_stmt() | |
| if t_type != 'EOF': | |
| self.errors.append(f"Syntax Error: Invalid statement start '{val}'") | |
| self.consume() | |
| return None | |
| def block(self): | |
| self.consume('LBRACE') | |
| statements = [] | |
| while self.peek()[0] != 'RBRACE' and self.peek()[0] != 'EOF': | |
| stmt = self.statement() | |
| if stmt: | |
| statements.append(stmt) | |
| self.consume('RBRACE') | |
| return ('BLOCK', statements) | |
| def declaration(self): | |
| self.consume('KEYWORD') # Dynamically consumes 'int', 'float', 'char', or 'bool' | |
| name = self.consume('ID')[1] | |
| if self.peek()[0] == 'ASSIGN': | |
| self.consume('ASSIGN') | |
| expr = self.expression() | |
| self.consume('SEMI') | |
| return ('DECL_ASSIGN', name, expr) # Keeps the exact same tuple shape | |
| self.consume('SEMI') | |
| return ('DECL', name) | |
| def assignment(self): | |
| name = self.consume('ID')[1] | |
| self.consume('ASSIGN') | |
| expr = self.expression() | |
| self.consume('SEMI') | |
| return ('ASSIGN', name, expr) | |
| def print_stmt(self): | |
| self.consume('KEYWORD') | |
| self.consume('LPAREN') | |
| expr = self.expression() | |
| self.consume('RPAREN') | |
| self.consume('SEMI') | |
| return ('PRINT', expr) | |
| def expression(self): | |
| node = self.term() | |
| while self.peek()[1] in ('+', '-'): | |
| op = self.consume()[1] | |
| right = self.term() | |
| node = ('BINOP', op, node, right) | |
| return node | |
| def term(self): | |
| node = self.factor() | |
| while self.peek()[1] in ('*', '/'): | |
| op = self.consume()[1] | |
| right = self.factor() | |
| node = ('BINOP', op, node, right) | |
| return node | |
| def factor(self): | |
| token = self.peek() | |
| if token[0] == 'NUMBER' or token[0] == 'ID': | |
| return self.consume()[1] | |
| elif token[0] == 'LPAREN': | |
| self.consume('LPAREN') | |
| node = self.expression() | |
| self.consume('RPAREN') | |
| return node | |
| self.errors.append(f"Syntax Error: Expected Number or ID but got {token[0]}") | |
| self.consume() | |
| return None |