-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodes.py
374 lines (295 loc) · 10.2 KB
/
nodes.py
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
__author__ = 'Dave and Alex'
from math import pow
#Builds a Node with a value, and a position in the sentence
class Node:
def __init__(self,value, pos):
self.value = value
self.pos = pos
def __repr__(self):
return 'Nodo({}, Caracteres={})'.format(self.value, self.pos)
#Parent of all the parsers
class Parser:
def __call__(self, tokens, pos):
return None
def __add__(self, other):
return Sum(self, other)
def __xor__(self, other):
return Process(self, other)
def __mul__(self, other):
return Exp(self, other)
def __or__(self, other):
return Compare(self, other)
#Validates a RESERVED word
class Reserved(Parser):
def __init__(self, value, tag):
self.value = value
self.tag = tag
def __call__(self, tokens, pos):
#tokens[pos][0] == value, tokens[pos][1] == tag
#tokens[pos][1] == value, tokens[pos][0] == tag
if pos < len(tokens) and tokens[pos][0] == self.value and tokens[pos][1] == self.tag:
#the token can be parsed
return Node(tokens[pos][0], pos + 1) #send the next position of token
else:
return None
#Validates a tag (INT, RESERVED WORD, OR VARIABLE)
class Tag(Parser):
def __init__(self, tag):
self.tag = tag
def __call__(self, tokens, pos):
if pos < len(tokens) and tokens[pos][1] is self.tag:
#the tag is equal
return Node(tokens[pos][0], pos + 1)
else:
return None
#Concatenates 2 or more expressions
class Sum(Parser):
def __init__(self, left, right):
self.left = left
self.right = right
def __call__(self, tokens, pos):
left = self.left(tokens, pos)
if left:
right = self.right(tokens, left.pos)
if right:
value = (left.value, right.value)
return Node(value, right.pos) #move the position to the end of the right result
return None
#Process a sentence, and then returns the result
class Process(Parser):
def __init__(self, parser, func):
self.parser = parser
self.func = func
def __call__(self, tokens, pos):
result = self.parser(tokens, pos) # process the lexed sentence
if result:
result.value = self.func(result.value)
return result
#Converts a parser to a Node
class Result(Parser):
def __init__(self, parser):
self.parser = parser
def __call__(self, tokens, pos):
results = []
result = self.parser(tokens,pos)
while result:
results.append(result.value)
pos = result.pos
result = self.parser(tokens,pos)
return Node(results, pos)
#Builds recursive expressions
class Recursive(Parser):
def __init__(self, func):
self.parser = None
self.func = func
def __call__(self, tokens, pos):
if not self.parser:
self.parser = self.func() # call the function passed as a parameter
return self.parser(tokens, pos)
#Validates the body of a sentence
class Validator(Parser):
def __init__(self, parser):
self.parser = parser
def __call__(self, tokens, pos):
result = self.parser(tokens, pos)
if result and result.pos == len(tokens): #check the end of the tokened sentence
return result
else:
return None
#Compares 2 parsers, if left doesn't exist, applies the right one
class Compare(Parser):
def __init__(self, left, right):
self.left = left
self.right = right
def __call__(self, tokens, pos):
left = self.left(tokens, pos)
if left:
return left
else:
right = self.right(tokens, pos)
return right
#Evaluates a list of expressions separated by ;
class Exp(Parser):
def __init__(self, parser, separator):
self.parser = parser
self.separator = separator
def __call__(self, tokens, pos):
result = self.parser(tokens, pos)
def process_next(parsed_sentence):
(func, right) = parsed_sentence
return func(result.value, right)
next_parser = self.separator + self.parser ^ process_next
next_sentence = result
while next_sentence:
next_sentence = next_parser(tokens, result.pos)
if next_sentence:
result = next_sentence
return result
class Opt(Parser):
def __init__(self, parser):
self.parser = parser
def __call__(self, tokens, pos):
result = self.parser(tokens, pos)
if result:
return result
else:
return Node(None, pos)
#Evaluates if it's a number
class IntExp:
def __init__(self, num):
self.num = num
def __repr__(self):
return 'Numero(%s)' % self.num
def evaluation(self, env):
return self.num
#Evaluates if it's a variable
class VarExp:
def __init__(self, variable):
self.variable = variable
def __repr__(self):
return 'Variable(%s)' % self.variable
def evaluation(self, env):
if self.variable in env:
return env[self.variable]
#Evaluates if it's an operator
class Operation:
def __init__(self, operation, left, right):
self.operation = operation
self.left = left
self.right = right
def __repr__(self):
return 'Operacion( %s, %s, %s)' % (self.operation, self.left, self.right)
def evaluation(self, env):
valor_izq = self.left.evaluation(env)
valor_der = self.right.evaluation(env)
if self.operation == '+':
valor = valor_izq + valor_der
elif self.operation == '-':
valor = valor_izq - valor_der
elif self.operation == '*':
valor = valor_izq * valor_der
elif self.operation == '/':
try:
valor = valor_izq / valor_der
except ZeroDivisionError:
print "No se puede dividir entre 0"
return
elif self.operation == '^':
valor = pow(valor_izq, valor_der)
elif self.operation == '%':
valor = valor_izq % valor_der
else:
raise RuntimeError('Error: Operador desconocido. Operador: ' + self.operation)
return valor
#Evaluates if it's a confition expression, such as for the ifs and loops
class RelExp:
def __init__(self, operation, left, right):
self.operation = operation
self.left = left
self.right = right
def evaluation(self, env):
valor_izq = self.left.evaluation(env)
valor_der = self.right.evaluation(env)
if self.operation == '<':
valor = valor_izq < valor_der
elif self.operation == '>':
valor = valor_izq > valor_der
elif self.operation == '<=':
valor = valor_izq <= valor_der
elif self.operation == '>=':
valor = valor_izq >= valor_der
elif self.operation == 'equal':
valor = valor_izq == valor_der
elif self.operation == 'not equal':
valor = valor_izq != valor_der
else:
raise RuntimeError('Error: Operador desconocido. Operador: ' + self.operation)
return valor
#Evaluates if it's an assignation of an expresion
class Assign:
def __init__(self, name, exp):
self.name = name
self.exp = exp
def __repr__(self):
return 'Asignacion(%s , %s)' % (self.name, self.exp)
def evaluation(self, env):
value = self.exp.evaluation(env)
env[self.name] = value
#Evaluates if it's a compound statement, such as for many operators and numbers
class Statement:
def __init__(self, left, right):
self.left = left
self.right = right
def __repr__(self):
return 'AsignacionComp(%s, %s)' % (self.left, self.right)
def evaluation(self, env):
self.left.evaluation(env)
self.right.evaluation(env)
#Evaluates if it's an if expression
class IfExp:
def __init__(self, condition, true, false):
self.condition = condition
self.true = true
self.false = false
def __repr__(self):
return 'AsignacionIf(%s, %s, %s)' % (self.condition, self.true, self.false)
def evaluation(self, env):
valor_condicional = self.condition.evaluation(env)
if valor_condicional:
self.true.evaluation(env)
else:
if self.false:
self.false.evaluation(env)
#Evaluates if it's a while expression
class WhileExp:
def __init__(self, condition, exp):
self.condition = condition
self.exp = exp
def __repr__(self):
return 'AsignacionWhile(%s, %s)' % (self.condition, self.exp)
def evaluation(self, env):
valor_condicional = self.condition.evaluation(env)
while valor_condicional:
self.exp.evaluation(env)
valor_condicional = self.condition.evaluation(env)
#Evaluates if it's a Function expression
class FuncExp:
def __init__(self, name, exp):
self.name = name
self.exp = exp
def __repr__(self):
return 'Funcion(%s, %s)' % (self.name, self.exp)
def evaluation(self, env):
env[self.name] = self.exp
#Evaluates if it's a 'Call' expression: calls a function.
class CallExp:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'LlamadaFuncion(%s)' % self.name
def evaluation(self, env):
exp = env[self.name]
exp.evaluation(env)
#Evaluates if it's a 'show' expression: the same as 'print' in Python
class PrintExp:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Show(%s)' % self.name
def evaluation(self, env):
try:
exp = env[self.name]
print exp
except Exception:
print "No existe la variable"
#Evaluates if it's a for expression: loop.
class ForExp:
def __init__(self, first, second, exp):
self.first = first
self.second = second
self.exp = exp
def __repr__(self):
return 'For(%s, %s, %s)' % (self.first, self.second, self.exp)
def evaluation(self, env):
for num in range(int(self.first), int(self.second)):
self.exp.evaluation(env)