class Compiler: def __init__(self): self.functions_table = FunctionsTable() self.current_function = Function("void", "global", [], {}, function_memory=Memory( MemoryConstants.GLOBAL_INITIAL)) self.semantic_cube = SemanticCube() self.quadruples = QuadruplesTable() self.operators_stack = [] self.operands_stack = [] self.jumps_stack = [] self.types_stack = [] self.temporal_memory = Memory(MemoryConstants.TEMPORAL_INITIAL) self.constant_memory = Memory(MemoryConstants.CONSTANT_INITIAL) self.constant_exec_memory = ExecMemory( MemoryConstants.CONSTANT_INITIAL) def add_function(self, function: Function): self.current_function.start_quadruple = self.quadruples.length() self.functions_table.add_function(function) if function.function_type != "void": self.functions_table.functions["global"].update_variables( function.function_type, function.function_name) def add_variable(self, variable_name): if variable_name in self.current_function.function_variables: variable = self.current_function.function_variables[variable_name] self.operands_stack.append(variable.variable_address) self.add_type(variable.variable_type) elif variable_name in self.functions_table.functions[ "global"].function_variables: variable = self.functions_table.functions[ "global"].function_variables[variable_name] self.operands_stack.append(variable.variable_address) self.add_type(variable.variable_type) elif variable_name in self.functions_table.functions: if self.functions_table.functions[ variable_name].function_type == 'void': print('ERROR: No se puede asignar una función void ' + variable_name + ' a una variable') else: self.operands_stack.append(variable_name) self.add_type(self.functions_table.functions[variable_name]. function_type) else: print('ERROR: La variable ' + str(variable_name) + ' no está declarada') def add_operator(self, operator): self.operators_stack.append(operator) # print('Operator: ', operator, self.operators_stack) def add_type(self, type): self.types_stack.append(type) # print('Type: ', type, self.types_stack) def add_constant_operand(self, operand, type): address = self.constant_memory.get_address(type) constant = Variable(type, operand, operand, address) self.constant_exec_memory.save_value(address, operand) self.operands_stack.append(constant.variable_address) self.types_stack.append(type) # print('Operand: ', operand, self.operators_stack) def left_parenthesis(self): self.operators_stack.append('(') # print('Parenthesis: (', self.operators_stack) def right_parenthesis(self): self.operators_stack.pop() # print('Parenthesis: )') def operation_quadruple(self): # print("Operation Quad Gen: ", self.operands_stack, self.operators_stack, self.types_stack) right_operand = self.operands_stack.pop() left_operand = self.operands_stack.pop() operator = self.operators_stack.pop() right_operand_type = self.types_stack.pop() left_operand_type = self.types_stack.pop() result_type = SemanticCube().check_operation(left_operand_type, right_operand_type, operator) if result_type == Types.ERROR: print( 'ERROR: Los tipos de datos de la operación no son compatibles.' ) else: # Create quadruple and add its type and and result to type and operand stacks result_address = self.temporal_memory.get_address(result_type) self.quadruples.append(operator, left_operand, right_operand, result_address) self.types_stack.append(result_type) self.operands_stack.append(result_address) def read_quadruple(self, operand): result_type = self.types_stack.pop() self.operands_stack.pop() if (operand in self.current_function.function_variables) or ( operand in self.functions_table.functions["global"].function_variables): result_address = self.temporal_memory.get_address(result_type) self.quadruples.append("read", operand, None, result_address) else: print('ERROR: La variable ' + str(operand) + ' no está declarada') def write_quadruple(self): # print("Write Quad Gen: ", self.operands_stack[len(self.operands_stack)-1]) if len(self.operands_stack) == 0: print( 'ERROR: Se quiere hacer un print pero no hay operandos en el stack' ) else: printed_operand = self.operands_stack.pop() self.types_stack.pop() self.quadruples.append("print", None, None, printed_operand) def assign_quadruple(self): # print("Assign Quad Gen: ", self.operators_stack[len(self.operators_stack)-1], self.operands_stack) if self.operators_stack[len(self.operators_stack) - 1] == '=': right_operand = self.operands_stack.pop() left_operand = self.operands_stack.pop() operator = self.operators_stack.pop() right_operand_type = self.types_stack.pop() left_operand_type = self.types_stack.pop() result_type = SemanticCube().check_operation( left_operand_type, right_operand_type, operator) if result_type == Types.ERROR: print( 'ERROR: Los tipos de datos de la asignación no son compatibles.' ) self.quadruples.append(operator, right_operand, None, left_operand) else: print( 'ERROR: Se entró a crear un quad de asignación pero no está el operando = en el stack.', self.operators_stack) def check_for_mult_or_div(self): # print("Mult/Div Check", len(self.operators_stack), self.operators_stack[-1:]) if len(self.operators_stack) is not 0 and self.operators_stack[ len(self.operators_stack) - 1] in [Operations.MULTIPLICATION, Operations.DIVISION]: self.operation_quadruple() def check_for_add_or_subs(self): # print("Add/Sub Check", len(self.operators_stack), self.operators_stack[-1:]) if len(self.operators_stack) > 0 and self.operators_stack[ len(self.operators_stack) - 1] in [Operations.ADDITION, Operations.SUBTRACTION]: self.operation_quadruple() def check_for_relational_operators(self): # print("Relational Check", len(self.operators_stack), self.operators_stack[-1:]) if len(self.operators_stack) > 0 and self.operators_stack[ len(self.operators_stack) - 1] in [ Operations.EQUAL, Operations.NOT_EQUAL, Operations.GREATER_OR_EQUAL, Operations.LESS_OR_EQUAL, Operations.GREATER, Operations.LESS ]: self.operation_quadruple() def check_for_logic_operators(self): # print("Logic Check", len(self.operators_stack), self.operators_stack[-1:]) if len(self.operators_stack) > 0 and self.operators_stack[ len(self.operators_stack) - 1] in [Operations.AND, Operations.OR]: self.operation_quadruple() def check_for_assignment(self): # print("Asignment Check", len(self.operators_stack), self.operators_stack[-1:]) if len(self.operators_stack) > 0 and self.operators_stack[ len(self.operators_stack) - 1] == Operations.ASSIGN: self.operation_quadruple() def if_statement(self): if len(self.operands_stack) != 0: # Check if while statement is valid condition_var = self.operands_stack.pop() type_condition_var = self.types_stack.pop() # print(self.operands_stack, self.operators_stack, self.types_stack, self.jumps_stack) if type_condition_var == Types.BOOL: # Create GOTOF and save quad in jumps stack to fill when we know false jump location self.jumps_stack.append(self.quadruples.length()) self.quadruples.append("GOTOF", condition_var, None, None) else: print('ERROR: ' + str(condition_var) + ' no es un boolean, es ' + str(type_condition_var)) def else_statement(self): self.quadruples.quads[ self.jumps_stack.pop()].result = self.quadruples.length() + 1 # Create GOTO and save quad in jumps stack to fill when we know jump location self.jumps_stack.append(self.quadruples.length()) self.quadruples.append("GOTO", None, None, None) def end_if_else_function(self): # Fill if's GOTOF quad with current index self.quadruples.quads[ self.jumps_stack.pop()].result = self.quadruples.length() def while_statement(self): # Save while statement quad in jumps stack to fill when we know jump location self.jumps_stack.append(self.quadruples.length()) def while_statutes(self): if len(self.operands_stack) != 0: condition_var = self.operands_stack.pop() type_condition_var = self.types_stack.pop() if type_condition_var == Types.BOOL: # Save begin statutes quad in jumps stack to fill when we know jump location self.jumps_stack.append(self.quadruples.length()) self.quadruples.append("GOTOF", condition_var, None, None) else: print('ERROR: ' + condition_var + ' es ' + type_condition_var + 'en vez de boolean.') def while_end(self): # Fill while statutes quad with ending of while while_statutes_index = self.jumps_stack.pop() self.quadruples.quads[ while_statutes_index].result = self.quadruples.length() + 1 # Get while statement index to generate GOTO quad to loop in while while_statement_index = self.jumps_stack.pop() self.quadruples.append("GOTO", None, None, while_statement_index) def from_initialize(self, operand): var_operand = None if operand in self.current_function.function_variables: var_operand = self.current_function.function_variables[operand] elif operand in self.functions_table.functions[ "global"].function_variables: var_operand = self.functions_table.functions[ "global"].function_variables[operand] # From variable was already declared locally or globally if var_operand: # Check if variable is INT to procede if (var_operand.variable_type == Types.INT): # Pop variable value and save from_variable_value = self.operands_stack.pop() self.types_stack.pop() self.quadruples.append("=", from_variable_value, None, var_operand.variable_address) self.current_function.function_variables[ 'from_variable'] = Variable(Types.INT, 'from_variable', from_variable_value, var_operand.variable_address) else: print('ERROR: La variable ' + operand + 'no es un entero') else: print('ERROR: La variable ' + operand + ' no está declarada') def from_statutes(self): if len(self.operands_stack) != 0: # Get the initial and limit values of the from loop try: from_variable = self.current_function.function_variables[ 'from_variable'] except: print('ERROR: No se encontró la variable del loop desde-hasta') from_variable_limit_value = self.operands_stack.pop() from_variable_limit_type = self.types_stack.pop() if from_variable_limit_type == Types.INT: res_address = self.temporal_memory.get_address(Types.BOOL) self.jumps_stack.append(self.quadruples.length()) self.quadruples.append("<", from_variable.variable_address, from_variable_limit_value, res_address) # Add point to jump stack and create GOTOF self.jumps_stack.append(self.quadruples.length()) self.quadruples.append("GOTOF", res_address, None, None) self.add_constant_operand("1", Types.INT) self.types_stack.pop() self.quadruples.append("+", from_variable.variable_address, self.operands_stack.pop(), from_variable.variable_address) else: print( 'ERROR: La expresión asignada a la variable del from debe de ser un entero' ) def end_from(self): # Fill from statutes quad with ending of while from_statutes_index = self.jumps_stack.pop() self.quadruples.quads[ from_statutes_index].result = self.quadruples.length() + 1 # Get from statutes index to generate GOTO quad to loop back to from from_statement_index = self.jumps_stack.pop() self.quadruples.append("GOTO", None, None, from_statement_index) def add_function_operand_type(self, operand): if self.functions_table.functions[operand].function_type == 'void': print('ERROR: No se le puede asignar a la función void ' + operand + ' un valor.') else: self.operands_stack.append(operand) self.add_type( self.functions_table.functions[operand].function_type) def goto_main(self): self.jumps_stack.append(0) self.quadruples.append("GOTO", None, None, "_") def start_main(self): mainQuad = self.jumps_stack.pop() self.quadruples.quads[mainQuad].result = self.quadruples.length() def goto_function(self, id): self.quadruples.append( 'GOSUB', None, None, self.functions_table.functions[id].start_quadruple) if self.functions_table.functions[id].function_type != "void": ret_type = self.functions_table.functions[id].function_type ret_address = self.temporal_memory.get_address(ret_type) self.quadruples.append( '=', self.functions_table.functions["global"]. function_variables[id].variable_address, None, ret_address) self.operands_stack.append(ret_address) self.types_stack.append(ret_type) def create_era(self, function_name): self.quadruples.append("ERA", None, None, function_name) def add_parameters(self, function_name): for parameter in reversed( self.functions_table.functions[function_name]. function_parameters): parameter_operand = self.operands_stack.pop() self.types_stack.pop() self.quadruples.append( "PARAM", parameter_operand, None, self.functions_table.functions[function_name]. function_variables[parameter.variable_name].variable_address) def end_function(self): self.current_function.end_quadruple = self.quadruples.length() self.quadruples.append('ENDPROC', None, None, None) def return_end_function(self): if self.current_function.function_type != "void": self.current_function.end_quadruple = self.quadruples.length() return_address = self.functions_table.functions[ "global"].function_variables[ self.current_function.function_name].variable_address self.types_stack.pop() self.quadruples.append('RETURN', self.operands_stack.pop(), None, return_address) else: print('ERROR: La función void ' + self.current_function.function_name + ' no puede tener un estatuto regresa.') def void_end_function(self): if self.current_function.function_type == "void": self.current_function.end_quadruple = self.quadruples.length() self.quadruples.append('GOTO', None, None, '_') else: print('ERROR: No se encontró valor de retorno en la función' + self.current_function.name + 'de tipo ' + self.current_function.function_type) def finish_program(self): self.quadruples.append("END", None, None, None) print("Quadruplos del Programa: ") self.quadruples.print() print('Stack de operandos: ', self.operands_stack) print('Stack de operadores: ', self.operators_stack) print('Stack de tipos', self.types_stack) print('Stack de saltos', self.jumps_stack) vm = VirtualMachine(self.quadruples, self.constant_exec_memory) vm.execute()
class StatementManager: in_local_scope = False def __init__(self): self.table = SymbolTable() self.oracle = SemanticCube() self.quads = QuadGenerator() self.memory = Memory() self.flow = FlowManager(self.quads, self.memory) # Creating the quad for the initial functions jump self.create_initial_jump() def get_symbol_from_name(self, id): ''' Function that checks if an id exists in current scope or above ''' return self.table.lookup(id) def create_initial_jump(self): ''' Function that creates the initial jump where the main functions are being executed ''' # We create a new GOTO quad self.quads.store_jump() # Current index quad is at 2, we store the previous quad by adding -1 self.flow.generate_goto() def start_class_scope(self, class_name, parent_name, params): ''' Function that starts a new class scope in symbol table and enters it ''' # We first have be sure that the class isn't already defined class_exists = self.get_symbol_from_name(class_name) # Cannot redeclare class if class_exists: raise Exception('Class name already defined') # Fetching the current number index of the quad quad_number = self.quads.current_index # Checks if it has a parent, if it does then it copies every attribute and function from it if parent_name: # Get parent address from symbol parent_symbol = self.table.get_class(parent_name) p_addr = parent_symbol.address # Storing the class in the symbol table and creating scope self.table.store_with_parent_symbols( parent_name, class_name, ClassSymbol(quad_number, class_name, parent_name, params), 'class') # Generating the quad self.quads.generate(OpIds.inherit, 0, 0, p_addr) else: # Store the class symbol in the symbol table and creating scope self.table.store( class_name, ClassSymbol(quad_number, class_name, parent_name, params), 'class') # Add params to new scope self.store_params(params, 'instance', OpIds.attr) # Creating a quad that indicates that its the end of the class' attributes self.quads.generate(OpIds.endattr, 0, 0, 0) def store_params(self, params, address_type, operation): ''' Function that stores the params with a VariableSymbol that contains its address type -instace, local- ''' params.reverse() for param in params: # Assigns a new address for the current param new_address = self.memory.get_address(address_type, param[1]) # Stores the variable symbol in the symbol table self.table.store(param[0], VariableSymbol(new_address, param[1])) # Generates a new quad with the given operation and the new address self.quads.generate(operation, 0, 0, new_address) def check_class_exists(self, class_name): ''' Function that checks if a class, that is being inherited from, exists, if it doesn't it throws and exception ''' class_exists = self.table.get_class(class_name) if not class_exists: raise Exception('Class ' + class_name + ' doesn\'t exist') def start_function_scope(self, function_name, return_type, parameters): # Stores the function element self.memory.locals.expand() self.table.store( function_name, FunctionSymbol(self.quads.current_index, return_type, parameters), 'function') self.in_local_scope = True self.store_params(parameters, 'local', OpIds.grab) def close_function_scope(self): ''' Function that closes a function scope ''' self.memory.locals.end_function() self.table.close_scope() self.in_local_scope = False self.quads.generate(OpIds.func_return, 0, 0, 0) def get_attrs_dict_for_class(self, class_name, args): # Gets symbol of the class class_symbol = self.table.get_class(class_name) # Make sure args are same type as params argument_types = list(map(lambda x: x[1], args)) accepts = class_symbol.accepts_arguments(argument_types) if not accepts: raise Exception('Arguments do not match constructor for class \'' + class_name + '\'.') attrs = {} # Matches class param with passed args temp_args = list(args) temp_args.reverse() class_attributes = zip(class_symbol.params, temp_args) for (param, arg) in class_attributes: attrs[param[0]] = arg return attrs def instantiate(self, class_name, args): class_symbol = self.table.get_class(class_name) attrs = self.get_attrs_dict_for_class(class_name, args) obj = self.new_var_of_type(class_name, 'temp', attrs) for arg in args: self.quads.generate(OpIds.param, 0, 0, arg[0]) self.quads.generate(OpIds.instance, class_symbol.address, 0, obj[0]) self.foo = obj return obj def end_class_scope(self): ''' Function that closes a class scope, by default it returns a quad of type RETURN ''' self.table.close_scope() def assign(self, variable, value): # Make sure value can be assigned to variable self.oracle.can_assign(variable[1], value[1]) if len(value) == 3: variable = self.assign_variable(variable, value) else: variable = self.assign_temp(variable, value) # If trying to copy existing variable # if len(value) == 3 and isinstance(value[2], VariableSymbol): # new_symbol = copy.deepcopy(value[2]) # new_attrs = self.copy_attributes(new_symbol) # new_symbol.address = variable[0] # print(new_symbol) # for name,attr in new_symbol.attrs.items(): # new_address = self.memory.get_address('local' if self.in_local_scope else 'global', attr.type) # self.table.replace_symbol(variable[2], new_symbol) # self.quads.generate(OpIds.assign, value[0], 0, variable[0]) return variable def assign_variable(self, variable, value): if isinstance(value[2], StackSymbol): return self.assign_temp(variable, value) return self.replicate(variable, value) def assign_temp(self, variable, value): self.quads.generate(OpIds.assign, value[0], 0, variable[0]) self.free_temp_memory(value[0]) return variable def copy_attributes(self, symbol): # If it's an object instance for key, attr in symbol.attrs.items(): if isinstance(attr, VariableSymbol): prev = attr.address new = attr.address = self.memory.get_address( 'local' if self.in_local_scope else 'global', attr.type) self.quads.generate(OpIds.assign, prev, 0, new) if attr.type not in ['int', 'float', 'bool', 'str']: self.copy_attributes_aux(attr) def copy_attributes_aux(self, symbol): symbol.address = self.memory.get_address( 'local' if self.in_local_scope else 'global', symbol.type) for key, attr in symbol.attrs.items(): if isinstance(attr, VariableSymbol): prev = attr.address new = attr.address = self.memory.get_address( 'local' if self.in_local_scope else 'global', attr.type) self.quads.generate(OpIds.assign, prev, 0, new) if attr.type not in ['int', 'float', 'bool', 'str']: self.copy_attributes_aux(attr) def this_property(self, prop_id): ''' Function that handles the this.property functionallity ''' # returns tuple with the address of the attribute and str of type # First we check if user is in a class scope in_class_scope = self.table.check_class_scope() # We are in a class scope if in_class_scope: class_has_property = self.table.check_class_property(prop_id) if class_has_property: if isinstance(class_has_property, StackSymbol): raise Exception('Cannot use stack ' + prop_id + ' outside a stack call.') # Returns the symbol return class_has_property.to_tuple() else: raise Exception('Property ' + prop_id + ' does not exist in class ' + in_class_scope + '.') # If we are not inside a class scope, then the keyword this is not available else: raise Exception( 'Keyword this is not available outside a class scope') def var_property(self, var_id, property_id): ''' Function that handles the id.id functionallity ''' variable_exists = self.id_property(var_id)[2] if isinstance(variable_exists, FunctionSymbol): raise Exception('Cannot access property of function ' + var_id + '.') if variable_exists: self.quads.generate(OpIds.context, 0, 0, variable_exists.address) symbol = variable_exists.get_attribute(property_id) if not symbol: raise Exception('Variable ' + var_id + ' does not have attribute ' + property_id + '.') return symbol def id_property(self, property_id): class_property = self.table.check_property(property_id) if isinstance(class_property, StackSymbol): raise Exception('Cannot use stack ' + property_id + ' outside a stack call.') if class_property: return class_property.to_tuple() else: raise Exception('Variable ' + property_id + ' is not defined.') def print_output(self, expression): self.quads.generate(OpIds.io_print, 0, 0, expression[0]) self.free_temp_memory(expression[0]) return expression def return_value(self, return_value): # Validates that the return object is the same type as the function return type has_correct_return = self.table.check_return(return_value[1]) if has_correct_return: self.quads.generate(OpIds.func_return, 0, 0, return_value[0]) else: raise Exception('Cannot return ' + return_value[1] + ' in function of type ' + self.table.scope().symbol.type) def return_void(self): has_correct_return = self.table.check_return('void') if has_correct_return: self.quads.generate(OpIds.func_return, 0, 0, 0) else: raise Exception('Cannot return void in function of type ' + self.table.scope().symbol.type) def float_constant(self, value): address = self.memory.get_constant_address('float', value) return (address, 'float') def int_constant(self, value): address = self.memory.get_constant_address('int', value) return (address, 'int') def string_constant(self, value): address = self.memory.get_constant_address('str', value) return (address, 'str') def free_temp_memory(self, memory_address): self.memory.free_if_temp(memory_address) def read(self): #Return temporal temp_addr = self.memory.get_address('temp', 'str') self.quads.generate(OpIds.io_read, 0, 0, temp_addr) return (temp_addr, 'str') def operate(self, operator, left_op, right_op): # left_op & right_op = tuple(address, type) res_type = self.oracle.is_valid(operator, left_op, right_op) new_address = self.memory.get_address('temp', res_type) self.quads.generate(OpIds.get(operator), left_op[0], right_op[0], new_address) # liberar memoria temporal de left_op y right_op self.memory.free_if_temp(left_op[0]) self.memory.free_if_temp(right_op[0]) return (new_address, res_type) def check_call_validity(self, prop, arguments, context=0): if isinstance(prop, tuple): prop = prop[2] symbol = prop argument_types = list(map(lambda x: x[1], arguments)) if not symbol.is_callable: raise Exception('Cannot call a non callable object') if not symbol.accepts_arguments(argument_types): raise Exception('Arguments do not match function parameters.') new_address = self.memory.get_address('temp', symbol.type) # arguments.reverse() for param in arguments: self.quads.generate(OpIds.param, 0, 0, param[0]) self.quads.generate(OpIds.call, symbol.address, 0, new_address) return (new_address, symbol.type) def call_stack(self, stack_symbol, call): if call[0] == 'push': return self.push_stack(stack_symbol, call[1]) elif call == 'peek': return self.peek_stack(stack_symbol) elif call == 'size': return self.size_stack(stack_symbol) else: return self.pop_stack(stack_symbol) def push_stack(self, symbol, tuple_expr): if symbol.type != tuple_expr[1]: raise Exception('Cannot push element of type ' + tuple_expr[1] + ' into a stack of type ' + symbol.type) self.quads.generate(OpIds.push, tuple_expr[0], 0, symbol.address) return tuple_expr def size_stack(self, symbol): new_address = self.memory.get_address('temp', 'int') self.quads.generate(OpIds.size, symbol.address, 0, new_address) return (new_address, 'int') def pop_stack(self, symbol): new_address = self.memory.get_address('temp', symbol.type) self.quads.generate(OpIds.pop, symbol.address, 0, new_address) return (new_address, symbol.type) def peek_stack(self, symbol): new_address = self.memory.get_address('temp', symbol.type) self.quads.generate(OpIds.peek, symbol.address, 0, new_address) return (new_address, symbol.type) def is_stack_type(self, variable): symbol = self.table.lookup(variable) if not isinstance(symbol, StackSymbol): raise Exception( 'Cannot perform stack methods on non-stack property ' + variable + '.') return symbol def clear_instance_memory(self): self.memory.clear_instance_memory() def id_does_not_exist(self, identifier): id_exist = self.table.lookup(identifier) if id_exist: raise Exception('Identifier ' + identifier + ' already exists') def fill_goto(self): self.quads.fill_jump() # TODO : move to quad_generator def create_quads_txt(self, filename): file = open(filename, "w+") for addr, value in self.memory.consts.ints.items(): if addr > 0: file.write(str(addr) + ',' + str(value) + '\n') for addr, value in self.memory.consts.floats.items(): if addr > 0: file.write(str(addr) + ',' + str(value) + '\n') for addr, value in self.memory.consts.bools.items(): if addr > 0: file.write(str(addr) + ',' + str(value) + '\n') for addr, value in self.memory.consts.strs.items(): if addr > 0: file.write(str(addr) + ',' + str(value) + '\n') file.write(str(OpIds.endconst) + '\n') for index, quad in self.quads.quads.items(): file.write(str(quad) + '\n') file.close() # # Var instantiation # def var_type_is_obj(self, type_name): return self.mem_type_from_var_type(type_name) == 'obj' def mem_type_from_var_type(self, type_name): return type_name if type_name in ['int', 'float', 'bool', 'str' ] else 'obj' def new_var_of_type(self, type_name, scope, args={}): is_stack = isinstance(type_name, tuple) and type_name[0] == 'stack' if is_stack: type_name = type_name[1] mem_type = self.mem_type_from_var_type(type_name) new_address = self.memory.get_address(scope, mem_type) self.quads.generate(OpIds.declare, 0, 0, new_address) if is_stack: return StackSymbol(new_address, type_name).to_tuple() new_attributes = {} if self.var_type_is_obj(type_name): new_attributes = self.get_attributes_for_class( type_name, scope, args) new_symbol = VariableSymbol(new_address, type_name, new_attributes) return new_symbol.to_tuple() def get_attributes_for_class(self, type_name, scope, args={}): class_scope = self.table.get_class_scope(type_name) attrs = {} for name, symbol in class_scope.symbols.items(): if isinstance(symbol, VariableSymbol): arg = args.get(name, None) symbol = self.new_var_of_type(symbol.type, scope) self.quads.generate(OpIds.relate, symbol[0], 0, class_scope.symbols[name].address) attrs[name] = symbol return attrs def replicate(self, target, origin): if isinstance(target, FunctionSymbol): return target self.quads.generate(OpIds.assign, origin[0], 0, target[0]) self.free_temp_memory(origin[0]) if len(origin) == 3: for name, target_attr in target[2].attrs.items(): self.replicate(target_attr, origin[2].attrs[name]) return target def declare(self, var_tuple): scope = 'local' if self.in_local_scope else 'global' var_name = var_tuple[0] # Checks it doesnt exist self.table.local_neg_lookup(var_name) var_type = var_tuple[1] var = self.new_var_of_type(var_type, scope) self.table.store(var_name, var[2]) return var