-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquad_generator.py
More file actions
307 lines (267 loc) · 11 KB
/
quad_generator.py
File metadata and controls
307 lines (267 loc) · 11 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
'''Modulo que define el funcionamiento de la clase QuadGenerator.
Clase encargada de la generacion de cuadruplos.'''
from stack import Stack
from cube import semantic_cube
from variable import Variable
from quadruple import Quadruple
def get_var_type(var_type):
if var_type == 'int':
return 'i'
elif var_type == 'double':
return 'd'
elif var_type == 'string':
return 's'
elif var_type == 'bool':
return 'b'
else:
return 'v'
def get_var_scope(scope):
if scope == 'global':
return 'g'
elif scope == 'main':
return 'l'
else:
return 't'
def createParam(param):
res = ''
res = get_var_type(param.get_type())+ 't' + param.get_name()
return res
class QuadGenerator(object):
'''Clase encargada de la generacion de cuadruplos'''
def __init__(self, filename):
'''Metodo de inicializacion de la clase'''
# Operands pile
self.pile_o = Stack()
# Operators pile
self.popper = Stack()
# Pending jumps
self.pjumps = Stack()
# Pending cycle returns
self.pcycles = Stack()
# Pending loop vars stack
self.ploop_vars = Stack()
# Pila dimensionada
self.pdim = Stack()
# File to write list of quadruples
self.file = filename
# Id of temporal vars
self.temporal_id = 1
# List of quadruples
self.quadruples = []
# Quadruple counter
self.cont = 0
# Scope for quads
self.scope = 'global'
# Diccionary for initial quadruple of each function
self.func_counter = {}
# Last verified dimension
self.last_verified = ''
def printeame(self):
'''Funcion auxiliar para imprimir contenidos de la clase'''
for i in self.quadruples:
print (i.printeame())
def read_operand(self, operand):
'''Push de una variable a la pila de operandos'''
self.pile_o.push(operand)
def read_operator(self, operator):
'''Push de operador a pila de operadores'''
self.popper.push(operator)
def reset_temporal_id(self):
'''Reset al contador de temporales para cuando sale de funciones'''
self.temporal_id = 1
def generate_quad(self):
'''Metodo para genera cuadruplos'''
# Checa si el op es uno de los siguientes operadores'''
op = self.popper.top
if op in ['+=', '-=', '*=', '/=']:
self.generate_assignment_op_quad()
return
op = self.popper.pop()
# Voltea operandos para un cuadruplo de asignacion simple
if op == '=':
left_operand = self.pile_o.pop()
right_operand = self.pile_o.pop()
else:
right_operand = self.pile_o.pop()
left_operand = self.pile_o.pop()
# Verfica la validez sematica
res = semantic_cube[right_operand.get_type()][left_operand.get_type()][op]
# Si la sematica es valida
if res != 'Error':
# Obtiene el nombre o valor de los operandoss
name_left = left_operand.get_name()
name_right = right_operand.get_name()
if name_left == 'constant':
name_left = left_operand.get_value()
if name_right == 'constant':
name_right = right_operand.get_value()
# Genera cuadruplo
if op == '=':
quad = Quadruple(self.cont, op, name_left, '', name_right)
else:
# Genera variable temporal
temp_name = get_var_type(res) + get_var_scope(self.scope) + 't' + str(self.temporal_id)
temp = Variable(temp_name, None, res, self.scope, 1)
# Aumenta id de temporales
self.temporal_id += 1
quad = Quadruple(self.cont, op, name_left, name_right, temp.get_name())
# pushea temporal a pila de operandos
self.pile_o.push(temp)
# Insert cuadruplo en la lista de cuadruplos
self.quadruples.append(quad)
self.cont += 1
else:
left_type = left_operand.get_type()
right_type = right_operand.get_type()
msg = 'Error 4001: Type missmatch ' + left_type + ' and ' + right_type + ' for operator: ' + str(op)
raise TypeError(msg)
def generate_assignment_op_quad(self):
'''Funcion para generar dos cuadruplos con operadores de asignacion'''
op = self.popper.pop()
if op in ['+=', '-=', '*=', '/=']:
self.popper.push('=')
self.popper.push(op[0])
# Saca A y B de la pila para ponerlos en la siguiente forma
# a += b -> a = a + b
b = self.pile_o.pop()
a = self.pile_o.pop()
self.pile_o.push(a)
self.pile_o.push(a)
self.pile_o.push(b)
# genera el cuadruplo para +, -, * o /
self.generate_quad()
# genera el cuadruplo para el =
self.generate_quad()
def generate_print(self, modifier='\\n'):
'''Funcion para generar el cuadruplo de un print'''
last_operand = self.pile_o.pop()
if last_operand.get_name() == 'constant':
last_operand = last_operand.get_value()
else:
last_operand = last_operand.get_name()
#s = self.pile_o.top.get_value()
quad = Quadruple(id=self.cont, op='Print', left_operand=last_operand, right_operand=modifier, res='')
self.cont += 1
self.quadruples.append(quad)
def generate_read(self, var, is_dim=False):
'''Funcion para generar cuadruplo de read'''
if var.get_name() == 'constant':
name = var.get_value()
else:
name = var.get_name()
if is_dim:
name = str(name) + '.' + str(self.last_verified)
quad = Quadruple(self.cont, 'Read', None, None, name)
self.quadruples.append(quad)
self.cont += 1
# TODO: agregar a donde van a saltar la operacion gosub
def generate_era(self, function_id):
func_type = self.func_counter.get(function_id, 'void')[1]
res_type = get_var_type(func_type)
quad = Quadruple(self.cont, 'ERA', res_type + 'g' + function_id, '', '')
self.quadruples.append(quad)
self.cont += 1
def generate_gosub(self, name, func_type):
res_type = get_var_type(func_type)
initial_address = self.func_counter.get(name, '_')[0]
quad = Quadruple(self.cont, 'Gosub', res_type + 'g' + name, '', initial_address)
self.quadruples.append(quad)
self.cont += 1
def generate_endproc(self):
quad = Quadruple(self.cont, 'EndProc', '', '', '')
self.quadruples.append(quad)
self.cont += 1
def generate_param(self, argument, param):
if argument.get_name() == 'constant':
argument = argument.get_value()
else:
argument = argument.get_name()
quad = Quadruple(self.cont, 'Param', argument, '', createParam(param))
self.quadruples.append(quad)
self.cont += 1
def generate_gotoF(self):
'''Funcion para generar cuadruplos de gotoF'''
last_operand = self.pile_o.pop()
if last_operand.get_type() != 'bool':
raise TypeError('Error 4002: Type missmatch. Non bool variables in condition')
else:
quad = Quadruple(self.cont, 'GotoF', last_operand.get_name(), None, None)
self.quadruples.append(quad)
self.pjumps.push(self.cont)
self.cont += 1
def generate_goto(self):
'''Funcion para generar cuadruplos de goto'''
quad = Quadruple(self.cont, 'Goto', None, None, None)
self.quadruples.append(quad)
self.pjumps.push(self.cont)
self.cont += 1
def generate_func_assign(self, func_name, func_type, value):
'''Funcion que asigna variablo global de funcion a temporal'''
res_type = get_var_type(func_type)
curr_scope = get_var_scope(self.scope)
temp_name = res_type + curr_scope + 't' + str(self.temporal_id)
func_var = Variable(res_type + 'g' + func_name, value, func_type, 'global', 1)
tmp_var = Variable(temp_name, None, func_type, self.scope, 1)
self.temporal_id += 1
quad = Quadruple(self.cont, '=', func_var.get_name(), None, tmp_var.get_name())
self.quadruples.append(quad)
self.pile_o.push(tmp_var)
self.cont += 1
def generate_return(self):
'''Genera cuadruplo de retorno'''
var = self.pile_o.pop()
if var.get_name() == 'constat':
name = var.get_value()
else:
name = var.get_name()
quad = Quadruple(self.cont, 'Return', name, None, None)
self.quadruples.append(quad)
self.cont += 1
return var.get_value()
def generate_verify(self):
'''Crea cuadruplo de verificacion'''
var = self.pdim.top[1]
tmp = self.pile_o.pop()
if tmp.get_name() == 'constant':
tmp_name = tmp.get_value()
else:
tmp_name = tmp.get_name()
self.last_verified = tmp_name
quad = Quadruple(self.cont, 'Verify', tmp_name, 0, var.size)
self.quadruples.append(quad)
self.cont += 1
# Concatena el nombre de la variable junto con la temporal o constante de resultado para acceso al arreglo
aux = Variable(var.name, var.value, var.type, var.scope, var.size, var.is_dim)
aux.name = var.name + '.' + str(tmp_name)
self.pile_o.push(aux)
self.popper.pop()
self.pdim.pop()
def fill_goto(self):
'''Funcion que llena los cuadruplos de goto pendientes'''
# Obtiene indice de cuadruplo pendiente en la lista de cuadruplos
pending = self.pjumps.pop()
# Dependiendo de si es un cuadruplo de gotoF o goto llena con un valor de contador
self.quadruples[pending].res = self.cont
def fill_goto_plus(self):
'''Funcion que llena los cuadruplos de goto pendiente cuando hay un else'''
pending = self.pjumps.pop()
# Dependiendo de si es un cuadruplo de gotoF o goto llena con un valor de contador
self.quadruples[pending].res = self.cont + 1
def generate_pending_goto(self):
'''Genera cuadruplo pendiente de goto para ciclos'''
pending = self.pcycles.pop()
quad = Quadruple(self.cont, 'Goto', None, None, pending)
self.quadruples.append(quad)
self.cont += 1
def finish(self):
'''Crea el ultimo cuadruplo del programa'''
quad = Quadruple(self.cont, 'END', '', '', '')
self.quadruples.append(quad)
def export(self):
'''Funcion para exportar cuadruplos a un archivo al terminar de generar cuadruplos'''
f = open(self.file, 'w')
for q in self.quadruples:
f.write(q.printeame() + '\n')
f.close() # you can omit in most cases as the destructor will call it
def add_function(self, name, func_type):
self.func_counter[name] = (self.cont, func_type)