File size: 3,611 Bytes
753d525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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