def vartype(): ice9_parser_global.logger.debug("Entering vartype") var_node_list = list() if ice9_parser_global.tok.type == "ID": identifier_list = idlist() else: print "Line", ice9_parser_global.tok.lineno, ": on token", ice9_parser_global.tok.value, "expecting id" sys.exit() if ice9_parser_global.tok.type == "COLON": ice9_parser_global.consume() ice9_parser_global.logger.debug(ice9_parser_global.tok) else: print "Line", ice9_parser_global.tok.lineno, ": on token", ice9_parser_global.tok.value, "expecting ':'" sys.exit() if ice9_parser_global.tok.type == "ID": type_node = typeid() else: print "Line", ice9_parser_global.tok.lineno, ": on token", ice9_parser_global.tok.value, "expecting id" sys.exit() for identifier in identifier_list: # Depending on the scope, calculate location for variable # If scope is GLOBAL, then location is in GLOBAL section # If scope is a procedure, then location is on stack, relative to FP if ice9_parser_global.scope[-1] == "GLOBAL": address = ice9_parser_global.get_next_global_address() ice9_parser_global.global_pointer += type_node.length - 1 else: address = ice9_st_proc.st_proc[ice9_parser_global.scope[-1]].local_variable_line ice9_st_proc.st_proc[ice9_parser_global.scope[-1]].local_variable_line -= type_node.length # Add entry to symbol table identifier_entry = ice9_st_var.st_var_entry( type_node.data_type, type_node.dimension, address, type_node.dimension_length ) ice9_st_var.add_entry_to_st_var(str(identifier), identifier_entry) id_node = ice9_node.id_node(str(identifier), type_node.data_type, type_node.dimension) id_node.set_basic_data_type() var_node_list.append(id_node) var_node = ice9_node.var_node(var_node_list, type_node) ice9_parser_global.logger.debug("Exiting vartype") return var_node
def generate_code(self): # Issue halt if self.rule == 'EXIT': ice9_parser_global.emit_code('HALT', 0, 0, 0, "Stop execution") elif self.rule == 'READ': if self.pre_child.operation == 'ID': register = self.pre_child.generate_code() ice9_parser_global.emit_code('IN', register, 0, 0, "Read value from stdin") ice9_parser_global.store_variable_to_memory(register) elif self.pre_child.operation == 'ARRAY_REF': operand = expr_node.generate_address(self.pre_child) register = ice9_parser_global.get_next_register() ice9_parser_global.emit_code('IN', register, 0, 0, "Read value from stdin") ice9_parser_global.emit_code('ST', register, 0, operand, "Store array") elif self.rule == 'BREAK': ice9_parser_global.break_stack[-1] = ice9_parser_global.lno ice9_parser_global.lno += 1 # Generate code for procedure definition elif self.rule == 'PROC': ice9_parser_global.emit_comment('---- Start of procedure definition for ' + str(self.pre_child) + ' ----') # Store the starting address of the procedure definition ice9_st_proc.st_proc[self.pre_child].starting_address = ice9_parser_global.lno for stmt in self.post_child: if stmt: stmt.generate_code() return_type = ice9_st_proc.st_proc[self.pre_child].return_type # Store the return address in a register address_register = ice9_parser_global.get_next_register() ice9_parser_global.emit_code('LD', address_register, 1, 6, 'Store the return instruction in a register') # Restore the FP ice9_parser_global.emit_code('LD', 6, 0, 6, 'Restore the FP to the previous value') # Get the length of local variables local_variable_length = -1 * ice9_st_proc.st_proc[self.pre_child].local_variable_line local_variable_length += 1 # Restore the SP ice9_parser_global.emit_code('LDA', 4, local_variable_length, 4, 'Restore the SP to the previous value') # Restore the PC ice9_parser_global.emit_code('LDA', 7, 0, address_register, 'Restore the PC to the caller') ice9_parser_global.emit_comment('---- End of procedure definition for ' + str(self.pre_child) + ' ----') # Do a OUT on the result of the expression elif self.rule in ['WRITE', 'WRITES']: # Determine opcode based on the return value of expression if self.pre_child.return_data_type == 'int': # Generate code for the expression register = self.pre_child.generate_code() ice9_parser_global.emit_code('OUT', register, 0, 0, "Write to stdout") elif self.pre_child.return_data_type == 'string': # Case for a string literal if self.pre_child.operation == 'SLIT': ice9_parser_global.emit_code_for_string('.DATA', self.pre_child.length) ice9_parser_global.emit_code_for_string('.SDATA', self.pre_child.value) length_address = ice9_parser_global.string_location_dict[self.pre_child.value] register = ice9_parser_global.get_next_register() # Set GP to first character ice9_parser_global.emit_code('LDC', 5, length_address, 0, 'Load address of string length') ice9_parser_global.emit_code('LDA', 5, 1, 5,'GP points to first character') # Load length ice9_parser_global.emit_code('LDC', register, length_address, 0, 'Load address of string length') ice9_parser_global.emit_code('LD', register, 0, register, 'Load string length') # Case for a variable elif self.pre_child.operation == 'ID': register = self.pre_child.generate_code() # Set GP to first character ice9_parser_global.emit_code('LDA', 5, 1, register, 'GP points to first character') # Load length ice9_parser_global.emit_code('LD', register, 0, register, 'Load string length') ice9_parser_global.set_register(register) content_reg = ice9_parser_global.get_next_register() ice9_parser_global.emit_code('JEQ', register, 5, 7, 'Check length, if zero jump') ice9_parser_global.emit_code('LD', content_reg, 0, 5, 'Load character from memory') ice9_parser_global.emit_code('OUTC', content_reg, 0, 0, 'Write character') ice9_parser_global.emit_code('LDA', 5, 1, 5, 'Increment GP') ice9_parser_global.emit_code('LDA', register, -1, register, 'Decrement length') ice9_parser_global.emit_code('LDA', 7, -6, 7, 'Jump back to start of loop') # If WRITES emit code for new line if self.rule == 'WRITES': ice9_parser_global.emit_code('OUTNL', 0, 0, 0, "New line") # Reuse register ice9_parser_global.reclaim_register() # Simply generate code for the pre_child elif self.rule in ['UN_MINUS', 'QUEST', 'INT', 'FALSE', 'TRUE', 'EXPR']: self.pre_child.generate_code() elif self.rule == 'FA': # Push -1 on the break stack ice9_parser_global.break_stack.append(-1) initial_value_register = self.pre_child.pre_child.generate_code() # VAR symbol table setup # Obtain the location to store the fa loop variable if ice9_parser_global.scope[-1] == 'GLOBAL': address = ice9_parser_global.get_next_global_address() else: address = ice9_st_proc.st_proc[ice9_parser_global.scope[-1]].local_variable_line ice9_st_proc.st_proc[ice9_parser_global.scope[-1]].local_variable_line -= 1 st_var_entry = ice9_st_var.st_var_entry('int', 0, address, None) st_var_entry.basic_data_type = 'int' # Bypass the checks in st_var.add_entry_to_st_var # If variable not previously used, make an entry for it if self.pre_child.value not in ice9_st_var.st_var: self.pre_child.value_stack = list() ice9_st_var.st_var[self.pre_child.value] = self.pre_child.value_stack ice9_st_var.st_var[self.pre_child.value].append(st_var_entry) # Store initial value of loop variable into memory loop_register = ice9_parser_global.get_next_register() ice9_parser_global.load_variable_from_memory(loop_register, self.pre_child.value) ice9_parser_global.emit_code('LDA', loop_register, 0, initial_value_register, 'Loop variable : Copy initial value') ice9_parser_global.store_variable_to_memory(loop_register) ice9_parser_global.set_register(initial_value_register - 1) # Jump back here at the end of the loop jump_back_line = ice9_parser_global.lno loop_register = ice9_parser_global.get_next_register() ice9_parser_global.set_register(loop_register) ice9_parser_global.load_variable_from_memory(loop_register, self.pre_child.value) final_value_register = self.pre_child.post_child.generate_code() ice9_parser_global.emit_code('LDA', final_value_register, 1, final_value_register, 'Increment final value, makes it easier for comparison') ice9_parser_global.emit_code('SUB', final_value_register, final_value_register, loop_register, \ 'Loop variable : Subtract current from final') ice9_parser_global.emit_code('JNE', final_value_register, 1, 7, 'Loop variable : If not equal, go to loop body') ice9_parser_global.reclaim_register() # Loop exit instruction line loop_exit_line = ice9_parser_global.lno ice9_parser_global.lno += 1 for stmt in self.post_child: stmt.generate_code() decrement_register = ice9_parser_global.get_next_register() ice9_parser_global.load_variable_from_memory(decrement_register, self.pre_child.value) ice9_parser_global.emit_code('LDA', decrement_register, 1, decrement_register, 'Loop variabe : Increment') ice9_parser_global.store_variable_to_memory(decrement_register) ice9_parser_global.reclaim_register() # Jump back to start of the loop ice9_parser_global.emit_code('LDC', 7, jump_back_line, 0, 'Loop variable : Uncondition jump back to start') exit_line = ice9_parser_global.lno ice9_parser_global.emit_code_at_line(loop_exit_line, 'LDC', 7, exit_line, 0, 'Loop variable : Exit loop') # VAR symbol table clean up ice9_st_var.st_var[self.pre_child.value].pop() if len(ice9_st_var.st_var[self.pre_child.value]) == 0: del ice9_st_var.st_var[self.pre_child.value] break_line = ice9_parser_global.break_stack.pop() if break_line != -1: ice9_parser_global.emit_code_at_line(break_line, 'LDC', 7, exit_line, 0, 'Break : Exit loop') elif self.rule == 'IF': # Generate code for expression condition_register = self.condition.generate_code() # Store the line number to jump if condition is false false_number = ice9_parser_global.lno ice9_parser_global.lno += 1 # Generate code for the 'then' part for stmt in self.pre_child: stmt.generate_code() # Store the line number to jump if condition is true and the block has been executed true_number = ice9_parser_global.lno ice9_parser_global.lno += 1 # Emit the jump statement when condition is false jump_offset = ice9_parser_global.lno - false_number - 1 ice9_parser_global.emit_code_at_line(false_number, 'JEQ', condition_register, jump_offset, 7, "If false, jump to the next if-else condition") #Reuse condition register ice9_parser_global.reclaim_register() #ice9_parser_global.set_register(false_number) # Generate code for any subsequent Else-If or Else if self.post_child: self.post_child.generate_code() self.end_line = self.post_child.end_line else: self.end_line = ice9_parser_global.lno # Emit missing unconditional jump to end of loop jump_offset = self.end_line - true_number - 1 ice9_parser_global.emit_code_at_line(true_number, 'LDA', 7, jump_offset, 7, "Jump to the end of if-else block") elif self.rule == 'DO': # Push -1 on the break stack ice9_parser_global.break_stack.append(-1) condition_start_line_no = ice9_parser_global.lno # Generate code for expression condition_register = self.condition.generate_code() # Store the line number to jump if condition is false false_number = ice9_parser_global.lno ice9_parser_global.lno += 1 # Generate code for the 'then' part for stmt in self.pre_child: stmt.generate_code() difference = condition_start_line_no - ice9_parser_global.lno - 1 ice9_parser_global.emit_code('LDA', 7, difference, 7, "Jump back to the start of the loop") # Emit the jump statement when condition is false jump_offset = ice9_parser_global.lno - false_number - 1 ice9_parser_global.emit_code_at_line(false_number, 'JEQ', condition_register, jump_offset, 7, "If false, jump to the end of do block") #Resure condition register ice9_parser_global.reclaim_register() end_line = ice9_parser_global.lno break_line = ice9_parser_global.break_stack.pop() if break_line != -1: ice9_parser_global.emit_code_at_line(break_line, 'LDC', 7, end_line, 0, 'Break : Exit loop')