-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.py
More file actions
327 lines (287 loc) · 12.3 KB
/
parser.py
File metadata and controls
327 lines (287 loc) · 12.3 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
from ast_tree import *
class SyntaxError(Exception): pass
class Parser:
def __init__(self, token_stream):
self.tokens = token_stream
def match(self, type_, *values):
tok = self.tokens.peek()
return tok and tok.type == type_ and (tok.value in values if values else True)
def parse_program(self):
namespaces = []
while self.tokens.peek() is not None:
namespaces.append(self.parse_namespace())
return Program(namespaces)
def parse_namespace(self):
self.tokens.expect("NAMESPACE")
name_tok = self.tokens.expect("IDENT")
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "{":
raise SyntaxError("Esperado '{'")
declarations = []
while True:
tok = self.tokens.peek()
if tok is None:
raise SyntaxError("Fim inesperado do namespace")
if tok.type == "OP" and tok.value == "}":
self.tokens.consume()
break
stmt = self.parse_declaration()
if isinstance(stmt, list):
declarations.extend(stmt)
else:
declarations.append(stmt)
return NamespaceDecl(name_tok.value, declarations)
def parse_declaration(self):
tok = self.tokens.peek()
if tok.type in {"INT", "FLOAT", "BOOL", "STRING"}:
if self.tokens.peek(2) and self.tokens.peek(2).value == "(":
return self.parse_function_decl()
return self.parse_decl_or_array()
elif tok.type == "AUTO":
return self.parse_auto_decl()
elif tok.type == "IF":
return self.parse_if()
elif tok.type == "OP" and tok.value == "{":
return self.parse_block()
elif tok.type == "IDENT":
return self.parse_assign()
elif tok.type == "RETURN":
return self.parse_return()
else:
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';' após expressão")
return ExprStmt(expr)
def parse_decl_or_array(self):
type_tok = self.tokens.consume()
name_tok = self.tokens.expect("IDENT")
if self.tokens.peek().type == "OP" and self.tokens.peek().value == "[":
self.tokens.consume()
size_expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "]":
raise SyntaxError("Esperado ']'")
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';'")
return ArrayDecl(name_tok.value, type_tok.value, size_expr)
else:
if self.tokens.peek().type == "OP" and self.tokens.peek().value == "=":
self.tokens.consume() # consome '='
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';'")
return [Decl(name_tok.value, type_tok.value), Assign(VarRef(name_tok.value), expr)]
else:
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';'")
return Decl(name_tok.value, type_tok.value)
def parse_function_decl(self):
return_type = self.tokens.consume().value
name = self.tokens.expect("IDENT").value
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "(":
raise SyntaxError("Esperado '(' após nome da função")
params = []
if self.tokens.peek().type in {"INT", "FLOAT", "BOOL", "STRING"}:
while True:
param_type = self.tokens.consume().value
param_name = self.tokens.expect("IDENT").value
params.append((param_name, param_type))
if self.tokens.peek().type == "OP" and self.tokens.peek().value == ",":
self.tokens.consume()
else:
break
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ")":
raise SyntaxError("Esperado ')' após parâmetros da função")
body = self.parse_block()
return FunctionDecl(name=name, params=params, return_type=return_type, body=body)
def parse_auto_decl(self):
self.tokens.consume()
name_tok = self.tokens.expect("IDENT")
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "=":
raise SyntaxError("Esperado '='")
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';'")
return AutoDecl(name_tok.value, expr)
def parse_assign(self):
tok = self.tokens.peek()
if tok.type != "IDENT":
raise SyntaxError("Esperado identificador no início da atribuição")
ident = self.tokens.consume().value
if self.tokens.peek() and self.tokens.peek().type == "OP" and self.tokens.peek().value == "[":
# Atribuição em array
self.tokens.consume()
index = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "]":
raise SyntaxError("Esperado ']' no acesso ao array")
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "=":
raise SyntaxError("Esperado '=' em atribuição")
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';' no final da atribuição")
return Assign(ArrayAccess(ident, index), expr)
else:
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "=":
raise SyntaxError("Esperado '='")
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';'")
return Assign(VarRef(ident), expr)
def parse_return(self):
self.tokens.expect("RETURN")
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ";":
raise SyntaxError("Esperado ';' após return")
return Return(expr)
def parse_block(self):
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "{":
raise SyntaxError("Esperado '{'")
statements = []
while True:
tok = self.tokens.peek()
if tok is None:
raise SyntaxError("Fim inesperado no bloco")
if tok.type == "OP" and tok.value == "}":
self.tokens.consume()
break
stmt = self.parse_declaration()
if isinstance(stmt, list):
statements.extend(stmt)
else:
statements.append(stmt)
return Block(statements)
def parse_if(self):
self.tokens.expect("IF")
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "(":
raise SyntaxError("Esperado '('")
condition = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ")":
raise SyntaxError("Esperado ')'")
then_branch = self.parse_block()
else_branch = None
if self.tokens.peek() and self.tokens.peek().type == "ELSE":
self.tokens.consume()
else_branch = self.parse_block()
return If(condition, then_branch, else_branch)
def parse_expr(self): return self.parse_logical_or()
def parse_logical_or(self):
expr = self.parse_logical_and()
while self.match("OP", "||"):
op = self.tokens.consume().value
right = self.parse_logical_and()
expr = BinaryOp(op, expr, right)
return expr
def parse_logical_and(self):
expr = self.parse_equality()
while self.match("OP", "&&"):
op = self.tokens.consume().value
right = self.parse_equality()
expr = BinaryOp(op, expr, right)
return expr
def parse_equality(self):
expr = self.parse_relational()
while self.match("OP", "==", "!="):
op = self.tokens.consume().value
right = self.parse_relational()
expr = BinaryOp(op, expr, right)
return expr
def parse_relational(self):
expr = self.parse_additive()
while self.match("OP", "<", ">", "<=", ">="):
op = self.tokens.consume().value
right = self.parse_additive()
expr = BinaryOp(op, expr, right)
return expr
def parse_additive(self):
expr = self.parse_multiplicative()
while self.match("OP", "+", "-"):
op = self.tokens.consume().value
right = self.parse_multiplicative()
expr = BinaryOp(op, expr, right)
return expr
def parse_multiplicative(self):
expr = self.parse_unary()
while self.match("OP", "*", "/"):
op = self.tokens.consume().value
right = self.parse_unary()
expr = BinaryOp(op, expr, right)
return expr
def parse_unary(self):
if self.match("OP", "-", "!"):
op = self.tokens.consume().value
expr = self.parse_unary()
return BinaryOp(op, Literal(0, "int"), expr)
return self.parse_primary()
def parse_primary(self):
tok = self.tokens.peek()
if tok.type == "INT_LITERAL":
self.tokens.consume()
return Literal(int(tok.value), "int")
elif tok.type == "FLOAT_LITERAL":
self.tokens.consume()
return Literal(float(tok.value), "float")
elif tok.type == "STRING_LITERAL":
self.tokens.consume()
return Literal(tok.value.strip('"'), "string")
elif tok.type == "BOOL_LITERAL":
self.tokens.consume()
return Literal(tok.value == "true", "bool")
elif tok.type == "IDENT" or tok.type in {"PRINT", "HALT"}:
ident = self.tokens.consume().value
if self.tokens.peek() and self.tokens.peek().type == "OP":
if self.tokens.peek().value == "(":
self.tokens.consume()
args = []
if self.tokens.peek().type != "OP" or self.tokens.peek().value != ")":
while True:
args.append(self.parse_expr())
if self.tokens.peek().type == "OP" and self.tokens.peek().value == ",":
self.tokens.consume()
else:
break
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ")":
raise SyntaxError("Esperado ')' após argumentos da função")
if tok.type == "PRINT":
return Print(name=ident, args=args)
if tok.type == "HALT":
return Halt(name=ident, args=args)
return Call(name=ident, args=args)
elif self.tokens.peek().value == ".":
self.tokens.consume()
name = self.tokens.expect("IDENT").value
return QualifiedRef(ident, name)
elif self.tokens.peek().value == "[":
self.tokens.consume()
index = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != "]":
raise SyntaxError("Esperado ']'")
return ArrayAccess(ident, index)
return VarRef(ident)
elif tok.type == "OP" and tok.value == "(":
self.tokens.consume()
expr = self.parse_expr()
self.tokens.expect("OP")
if self.tokens.peek(-1).value != ")":
raise SyntaxError("Esperado ')'")
return expr
else:
raise SyntaxError(f"Expressão primária inválida: {tok}")