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
Exemplo n.º 2
0
	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')