def complete_method_call(self, method_scope: MethodScope, instance: str): """ Creates a GOSUB quad to the instruction address of the method to be called. Aditionally if the method has a return type generates quads to take the return value of the method from the global memory and store it in a temporal. Finally set the __current_param_index to 0 since by this point we are done assigning the parameters of the method. Arguments: - method_scope [MethodScope]: The method scope of the function to be called. - instance [str]: The name of the instance of the method to be called. """ # Handle weird case when the instance is detected as an operand. if instance != None and instance != "self": self.__operands.pop() self.__quads.append((Operations.GOSUB, method_scope.name, method_scope.instruction_pointer)) if method_scope.return_type != "void": next_address = CompilationMemory.next_temp_memory_space( method_scope.return_type) temp = Variable(next_address, method_scope.return_type, next_address) self.__quads.append( (Operations.ASSIGN, temp, method_scope.return_memory_address)) self.__operands.push(temp) if len(method_scope.ordered_arguments) != self.__current_param_index: raise Exception( f"Number of parameters do not match on {method_scope.name}") self.__current_param_index = 0
def read_quad(self): """ Generates a quad for the read operation. """ memory_address = CompilationMemory.next_temp_memory_space(Types.STRING) temp = Variable(memory_address, Types.STRING, memory_address) self.__quads.append((Operations.READ, temp)) self.__operands.push(temp)
def push_constant(self, type_: str, memory_space: int): """Adds a constant to the operands stack. Arguments: - type_ [str]: The type of the constant. - memory_space [int]: The memory address for the constant. """ new_variable = Variable(memory_space, type_, memory_space) self.__operands.push(new_variable)
def maybe_gen_not_quad(self) -> bool: """ Check if there is a pending not operation in the operators stack. """ if not self.__operators.isEmpty() and Operations.is_not_op( self.__operators.top()): op = self.__operators.pop() operand = self.__operands.pop() memory_address = CompilationMemory.next_temp_memory_space(operand) self.__quads.append((op, operand, memory_address)) self.__operands.push( Variable(memory_address, operand.var_type, memory_address))
def get_value_from_memory(self, variable: Variable, memory: MethodMemory): """ Retrieves the value of the variable from the provided memory. Arguments: - variable [Variable]: The variable to be retrieved. - memory [MethodMemory]: The memory to be used to retireved the variable. Returns: - The value in memory of the provieded variable. """ if variable.is_array_pointer(): address = memory.get_value(variable.memory_space) return memory.get_value(address) return memory.get_value(variable.memory_space)
def complete_dimension_access(self): """ Generates the quad to add the base memory of the dimensional address. """ dim_variable, dimension = self.__dim_operands.pop() memory_address = CompilationMemory.next_temp_memory_space( Types.ARRAY_POINTER) var_pointer = Variable(memory_address, Types.ARRAY_POINTER, memory_address) var_pointer.pointer_type = dim_variable.var_type if dimension > 1: index = self.__operands.pop() add_memory_address = CompilationMemory.next_temp_memory_space( Types.INT) self.__quads.append((Operations.ADD, index, self.__operands.pop(), add_memory_address)) self.__operands.push( Variable(add_memory_address, Types.INT, add_memory_address)) var = self.__operands.pop() self.__quads.append( (Operations.ADD_LIT, var, dim_variable.memory_space, var_pointer)) self.__operands.push(var_pointer)
def maybe_multiply_for_m(self, dim_tuple: Tuple[Variable, int]): """ Generate a quad to multipluy the current index to the corresponding dimensional variable. Arguments: - dim_tuple [Tuple[Variable, int]]: The tuple with the dimension variable. """ variable = dim_tuple[0] index = self.__operands.pop() memory_address = CompilationMemory.next_temp_memory_space(Types.INT) new_temp = Variable(memory_address, Types.INT, memory_address) self.__quads.append( (Operations.PROD_LIT, index, variable.getDimensionNumber(dim_tuple[1]).m, new_temp)) self.__operands.push(new_temp)
def gen_quad_for_next_op(self) -> bool: """ Perform the type check for the two next operands and creates the quads corresponding to the next operand. Raises: - Exception: If the two operands are not type compatible. """ r_op = self.__operands.pop() l_op = self.__operands.pop() op = self.__operators.pop() result = OperationsCube.verify(r_op.var_type, l_op.var_type, op) if result == Types.ERROR: raise ValueError( f'Cannot perform {op} operation with {r_op.var_type} {l_op.var_type} operands.' ) memory_address = CompilationMemory.next_temp_memory_space(result) self.__quads.append((op, l_op, r_op, memory_address)) self.__operands.push(Variable(memory_address, result, memory_address))