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