def end_for(self): """ Completa saltos necesarios al final del ciclo for """ if len(self.jumps_stack) >= 2 and self.operands_stack: control = self.get_var(self.operands_stack.pop()) temp = "_temp_" + str( self.temp_vars_index ) # Pedir dirección de memoria para el resultado self.temp_vars_index += 1 tipo_res = self.semantic_cube.type_match(control.type, VarType.INT, Operator.PLUS) temp_address = self.add_temp(temp, tipo_res) self.quad_list.append( Quadruple(Operator('+'), control.address, self.get_const(1, VarType.INT), temp_address)) self.quad_list.append( Quadruple(Operator.ASSIGN, temp_address, None, control.address)) end = self.jumps_stack.pop() ret = self.jumps_stack.pop() self.quad_list.append(Quadruple(Operator('goto'), None, None, ret)) self.finish_jump(end, len(self.quad_list)) else: raise Exception("Operation stack error: Not enough operands")
def valor_final_for(self): """ Establece valor final del ciclo for con valor de expresion """ if len(self.operands_stack) >= 2: exp = self.get_var(self.operands_stack.pop()) if exp.type == VarType.INT or exp.type == VarType.FLOAT: control = self.get_var(self.operands_stack.pop()) if control.type == VarType.INT or control.type == VarType.FLOAT: final = "_final_" + control.name final_address = self.add_temp(final, exp.type) self.quad_list.append( Quadruple(Operator.ASSIGN, exp.address, None, final_address)) temp = "_temp_" + str(self.temp_vars_index) self.temp_vars_index += 1 temp_address = self.add_temp(temp, "bool") self.quad_list.append( Quadruple(Operator('<'), control.address, final_address, temp_address)) self.jumps_stack.append(len(self.quad_list) - 1) self.quad_list.append( Quadruple(Operator('gotof'), temp_address, None, None)) self.jumps_stack.append(len(self.quad_list) - 1) self.operands_stack.append(control.name) else: raise TypeError( "Type mismatch: Control variable is not numeric but " + str(control.type)) else: raise TypeError( "Type mismatch: Final expression for for cycle is not numeric but " + str(exp.type)) else: raise Exception("Operation stack error: Not enough operands")
def valor_inicial_for(self): """ Inicializa variable de control del ciclo for con valor de expresion """ if len(self.operands_stack) >= 2: exp = self.get_var(self.operands_stack.pop()) if exp.type == VarType.INT or exp.type == VarType.FLOAT: control = self.get_var(self.operands_stack.pop()) tipo_res = self.semantic_cube.type_match( control.type, exp.type, Operator.ASSIGN) if tipo_res == VarType.INT or tipo_res == VarType.FLOAT: self.quad_list.append( Quadruple(Operator.ASSIGN, exp.address, None, control.address)) self.operands_stack.append(control.name) else: raise TypeError( "Type mismatch: Cannot perform operation " + str(Operator.ASSIGN) + " between " + str(control.type) + " and " + str(exp.type)) else: raise TypeError( "Type mismatch: Initial expression for for cycle is not numeric but " + str(exp.type)) else: raise Exception("Operation stack error: Not enough operands")
def generate_quad_assign(self, name_var="", array=False): """ Función para generar un cuadruplo de asignación utilizando la pila de operandos :param name_var: nombre de la variable donde se va a asignar el valor """ if self.operands_stack: right_operand = self.get_var(self.operands_stack.pop()) if array: left_operand = self.get_var(self.operands_stack.pop()) else: left_operand = self.get_var(name_var) result_type = self.semantic_cube.type_match( left_operand.type, right_operand.type, Operator.ASSIGN) if result_type != "error": self.quad_list.append( Quadruple(Operator.ASSIGN, right_operand.address, None, left_operand.address)) else: raise TypeError("Type mismatch: Cannot perform operation " + str(Operator.ASSIGN) + " between " + str(left_operand.type) + " and " + str(right_operand.type)) else: raise Exception("Operation stack error: not enough operands")
def generate_quad(self): """ Función para generar un cuadruplo utilizando las pilas de operadores, operandos y tipos """ if len(self.operands_stack) >= 2 and len( self.operators_stack) >= 1 and self.operators_stack[-1] != '(': right_operand = self.get_var(self.operands_stack.pop()) left_operand = self.get_var(self.operands_stack.pop()) operator = Operator(self.operators_stack.pop()) result_type = self.semantic_cube.type_match( left_operand.type, right_operand.type, operator) if result_type != "error": result_id = "_temp_" + str(self.temp_vars_index) result_addr = self.add_temp(result_id, result_type) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator(operator), left_operand.address, right_operand.address, result_addr)) self.operands_stack.append(result_id) else: raise TypeError("Type mismatch: Cannot perform operation " + str(operator) + " between " + str(left_operand.type) + " and " + str(right_operand.type)) else: raise Exception("Operation stack error: not enough operands")
def generar_lectura(self, var_name): """ Genera cuadruplo con operando de read y direccion de la variable que recibe el valor :var_name: Variable donde se guardara el valor a leer """ var = self.get_var(var_name) self.quad_list.append(Quadruple(Operator.READ, None, None, var.address))
def fun_call(self, fun_name, arg_list, needs_return=False): """ Genera las acciones necesarias para llamar a una función. Verifica coherencia en tipos y número de argumentos. :param fun_name: Nombre o identificador de la función a llamar. :param arg_list: Lista de argumentos de la llamada a función. """ arg_list.reverse() # Verify that the function exists into the DirFunc fun = self.get_fun(fun_name) if needs_return and fun.return_type == ReturnType.VOID: raise Exception('Semantic Error: ' + fun.name + " is void but a return is requested.") # Verify coherence in number of parameters if len(fun.param_table) != len(arg_list): raise Exception( 'Incorrect number of arguments in function call: ' + fun.name) # Generate action ERA size self.quad_list.append(Quadruple(Operator.ERA, None, None, fun.name)) for index, (param, arg_name) in enumerate(zip(fun.param_table, arg_list)): arg = self.get_var(arg_name) # Verify coherence in types if param[1] == arg.type: self.quad_list.append( Quadruple(Operator.PARAMETER, arg.address, None, param[0])) else: raise TypeError('Type mismatch: ' + str(fun_name) + ' requires argument to be ' + str(param[1]) + " but got " + str(arg.type)) # Generate action GOSUB self.quad_list.append( Quadruple(Operator.GOSUB, fun.name, None, fun.start_addr)) # Save return value in a temp value if fun.return_type != ReturnType.VOID: fun_var = self.get_var("_fun_" + fun_name) temp_id = "_temp_" + str(self.temp_vars_index) temp_addr = self.add_temp(temp_id, fun_var.type) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.ASSIGN, fun_var.address, None, temp_addr)) self.operands_stack.append(temp_id)
def end_while(self): """ Completa saltos necesarios al final del ciclo while """ if len(self.jumps_stack) >= 2: end = self.jumps_stack.pop() ret = self.jumps_stack.pop() self.quad_list.append(Quadruple(Operator.GOTO, None, None, ret)) self.finish_jump(end, len(self.quad_list)) else: raise Exception("Jump stack error")
def start_else(self): """ Genera cuadruplos necesarios al principio de un else """ self.quad_list.append(Quadruple(Operator.GOTO, None, None, None)) if self.jumps_stack: false = self.jumps_stack.pop() self.jumps_stack.append(len(self.quad_list) - 1) self.finish_jump(false, len(self.quad_list)) else: raise Exception("Jump stack error")
def generar_escritura(self): """ Genera cuadruplo con operando de write y el valor a escribir """ addr: int if self.operands_stack: var_name = self.operands_stack.pop() var = self.get_var(var_name) self.quad_list.append( Quadruple(Operator.WRITE, None, None, var.address)) else: raise Exception("Operation stack error: Not enough operands")
def end_fun(self): """ Guarda los tamaños de las particiones de la memoria local (necesarios para ejecutar la instucción ERA en VM). Genera el cuadruplo con la instrucción ENDFUN. """ # Save partition sizes for ERA instruction. fun = self.get_fun(self.current_scope) fun.local_partition_sizes = self.v_memory_manager.local_addr.get_partition_sizes( ) fun.temp_partition_sizes = self.v_memory_manager.temp_addr.get_partition_sizes( ) self.quad_list.append(Quadruple(Operator.ENDFUN, None, None, None)) self.set_global_scope()
def expresion_while(self): """ Genera cuadruplos necesarios al final de la expresion del while """ if self.operands_stack: res = self.get_var(self.operands_stack.pop()) if res.type == VarType.BOOL: self.quad_list.append( Quadruple(Operator.GOTOF, res.address, None, None)) self.jumps_stack.append(len(self.quad_list) - 1) else: raise TypeError( "Type mismatch: Needed BOOL type for while conditional") else: raise Exception("Operation stack error: Not enough operands")
def return_stmt(self): """ Metodo para añadir el indice del cuadruplo equivalente a la primera instrucción de una función. """ if self.operands_stack: return_exp = self.operands_stack.pop() return_var = self.get_var(return_exp) fun_var = self.get_var("_fun_" + self.current_scope) result_type = self.semantic_cube.type_match( fun_var.type, return_var.type, Operator.ASSIGN) if result_type != "error": self.quad_list.append( Quadruple(Operator.ASSIGN, return_var.address, None, fun_var.address)) else: raise TypeError("Type mismatch: Function " + str(self.current_scope) + " returns " + str(fun_var.type) + " but got " + str(return_var.type)) else: raise Exception("Operation stack error: Not enough operands")
def array_usage(self, var_id, dims): """ Metodo adquirir direccion real de arreglo indexado y agregarlo al stack de operandos """ var = self.get_var(var_id) if dims == 1: # Una dimension if var.dims[0] > 0: if self.operands_stack: dim = self.operands_stack.pop() dim_var = self.get_var(dim) if dim_var.type == VarType.INT: self.quad_list.append( Quadruple(Operator.VERIFY, dim_var.address, self.get_const(0, VarType.INT), self.get_const(var.dims[0], VarType.INT))) temp_id = "_temp_" + str(self.temp_vars_index) temp_addr = self.add_temp(temp_id, var.type) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.PLUS, dim_var.address, self.get_const(var.address, VarType.INT), temp_addr)) # pointer_id tiene la direccion del arreglo indexado pointer_id = "_pointer_" + str(self.temp_vars_index) pointer_addr = self.add_pointer(pointer_id, var.type) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.ASSIGNPTR, temp_addr, '', pointer_addr)) self.operands_stack.append(pointer_id) else: raise Exception( "Index type error: Needed var type INT") else: raise Exception( "Operation stack error: Not enough operands") else: raise Exception("Var " + str(var_id) + " is not an array of 1 dimension") else: # Dos dimensiones if var.dims[0] > 0 and var.dims[1] > 0: if self.operands_stack: dim2 = self.operands_stack.pop() dim2_var = self.get_var(dim2) dim1 = self.operands_stack.pop() dim1_var = self.get_var(dim1) if dim1_var.type == VarType.INT and dim2_var.type == VarType.INT: self.quad_list.append( Quadruple(Operator.VERIFY, dim1_var.address, self.get_const(0, VarType.INT), self.get_const(var.dims[0], VarType.INT))) temp1_id = "_temp_" + str(self.temp_vars_index) temp1_addr = self.add_temp(temp1_id, VarType.INT) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.TIMES, dim1_var.address, self.get_const(var.dims[1], VarType.INT), temp1_addr)) temp2_id = "_temp_" + str(self.temp_vars_index) temp2_addr = self.add_temp(temp2_id, VarType.INT) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.PLUS, temp1_addr, self.get_const(var.address, VarType.INT), temp2_addr)) self.quad_list.append( Quadruple(Operator.VERIFY, dim2_var.address, self.get_const(0, VarType.INT), self.get_const(var.dims[1], VarType.INT))) temp3_id = "_temp_" + str(self.temp_vars_index) temp3_addr = self.add_temp(temp3_id, VarType.INT) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.PLUS, temp2_addr, dim2_var.address, temp3_addr)) # pointer_id tiene la direccion del arreglo indexado pointer_id = "_pointer_" + str(self.temp_vars_index) pointer_addr = self.add_pointer(pointer_id, var.type) self.temp_vars_index += 1 self.quad_list.append( Quadruple(Operator.ASSIGNPTR, temp3_addr, '', pointer_addr)) self.operands_stack.append(pointer_id) else: raise Exception( "Index type error: Needed var type INT") else: raise Exception( "Operation stack error: Not enough operands") else: raise Exception("Var " + str(var_id) + " is not an array of 2 dimensions")
def set_jump_main(self): """ Genera quad de salto a main al inicio del programa """ self.quad_list.append(Quadruple(Operator('goto'), None, None, None)) self.jumps_stack.append(len(self.quad_list) - 1)
def append(self, operator, left_operand, right_operand, result=None): # print(operator, left_operand, right_operand, result) quadruple = Quadruple(operator, left_operand, right_operand, result) self.quads.append(quadruple)