コード例 #1
0
	def generate_address(self):
		# Load last value as it is
		register = expr_node.generate_code(self.expr_list[-1])

		# Get new register to calculate product
		for x in range(len(self.expr_list) - 2, -1, -1):
			product_reg = expr_node.generate_code(self.expr_list[x])
			constant_reg = ice9_parser_global.get_next_register()
			ice9_parser_global.emit_code('LDC', constant_reg, get_follow_product(self.value, x + 1), 0, \
				'Array index : Load constant')
			ice9_parser_global.emit_code('MUL', product_reg, product_reg, constant_reg, \
				'Array index : Multiply')
			ice9_parser_global.emit_code('ADD', register, register, product_reg, 'Array index : Add')
			ice9_parser_global.reclaim_register()
				
		# Check array bounds for -ve index
		ice9_parser_global.emit_code('JGE', register, 1, 7, 'If non-negative array index, skip halt')
		ice9_parser_global.emit_code('LDC', 7, 5, 0, 'Array index out of bounds, write error and halt')

		# Check array bounds for index overflow
		max_reg = ice9_parser_global.get_next_register()
		ice9_parser_global.emit_code('LDC', max_reg, get_follow_product(self.value, 0), 0, 'Array index get Max value')
		ice9_parser_global.emit_code('SUB', max_reg, max_reg, register, 'Subtract index from maximum')
		ice9_parser_global.emit_code('JGT', max_reg, 1, 7, 'If non-negative array index, skip halt')
		ice9_parser_global.emit_code('LDC', 7, 5, 0, 'Array index out of bounds, write error and halt')

		if ice9_parser_global.scope[-1] != 'GLOBAL':
			temp_reg = ice9_parser_global.get_next_register()
			ice9_parser_global.emit_code('LDC', temp_reg, -1, 0, 'Array variable: Load -1')
			ice9_parser_global.emit_code('MUL', register, register, temp_reg, 'Array variable: Multilply index with -1')
			ice9_parser_global.emit_code('LDC', temp_reg, ice9_st_var.st_var[self.value][-1].address, \
				0, "Array variable in procedure: Load offset from symbol tab")
			ice9_parser_global.emit_code('ADD', register, register, temp_reg, "Array variable in procedure")
			ice9_parser_global.emit_code('ADD', register, register, 6, "Array variable in procedure: Add to FP")

		return register							
コード例 #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')
コード例 #3
0
	def generate_code(self):
		#Default values
		operand2 = -1
		operand3 = -1

		# Special case for ASSIGN, array variables need address calculation to be dynamic
		# Operators that do not require a new register allocated
		if self.operation == 'ASSIGN':
			if self.pre_child.operation == 'ARRAY_REF':
				operand2 = expr_node.generate_address(self.pre_child)
				operand3 = expr_node.generate_code(self.post_child)
				ice9_parser_global.emit_code('ST', operand3, 0, operand2, "Store array")

			elif self.pre_child.return_data_type == 'string' \
				and self.pre_child.operation == 'SLIT' :
					operand2 = expr_node.generate_code(self.pre_child)
					operand3 = expr_node.generate_code(self.post_child)
		
					ice9_parser_global.emit_code('LDC', operand2, \
						ice9_parser_global.string_location_dict[self.post_child.value],	0, 'String literal assignment')
					ice9_parser_global.store_variable_to_memory(operand2)

			else:
				operand2 = expr_node.generate_code(self.pre_child)
				operand3 = expr_node.generate_code(self.post_child)
				ice9_parser_global.emit_code('LDA', operand2, 0, operand3, "Assignment")
				ice9_parser_global.store_variable_to_memory(operand2)

			# Re-use register
			register = operand2
			register -= 1

		# Normal case
		else:	
			if self.pre_child:
				operand2 = expr_node.generate_code(self.pre_child)

				if self.operation in ['PLUS_BOOL', 'STAR_BOOL']:
					bool_jump_line = ice9_parser_global.lno
					ice9_parser_global.lno += 2

			if self.post_child:
				operand3 = expr_node.generate_code(self.post_child)
				
			post_child_end_line = ice9_parser_global.lno

			# For boolean addition, jump on true
			if self.operation == 'PLUS_BOOL':
				ice9_parser_global.emit_code_at_line(bool_jump_line, 'JEQ', operand2, 1, 7, \
					'Short circuit : On false, evaluation continues')
				ice9_parser_global.emit_code_at_line(bool_jump_line + 1, 'LDC', 7, post_child_end_line, 0, \
					'Short circuit : Evaluation of pre_child is true, skip post_child')
	
			# For boolean multiplication, jump on false
			elif self.operation == 'STAR_BOOL':
				ice9_parser_global.emit_code_at_line(bool_jump_line, 'JNE', operand2, 1, 7, \
					'Short circuit : On true, evaluation continues')
				ice9_parser_global.emit_code_at_line(bool_jump_line + 1, 'LDC', 7, post_child_end_line, 0, \
					'Short circuit : Evaluation of pre_child is true, skip post_child')

			register = operand2
			
			if self.operation == 'PLUS':
				# If operation is PLUS, store the sum of left and right child in register
				ice9_parser_global.emit_code('ADD', register, operand2, operand3, "Addition")
			
			elif self.operation == 'PLUS_BOOL':
				# If operation is PLUS, store the sum of left and right child in register
				ice9_parser_global.emit_code('ADD', register, operand2, operand3, "Boolean addition")
	
			elif self.operation == 'MINUS':
				# If operation is PLUS, store the difference of left and right child in register
				ice9_parser_global.emit_code('SUB', register, operand2, operand3, "Subtraction")

			elif self.operation == 'STAR':
				# If operation is PLUS, store the product of left and right child in register
				ice9_parser_global.emit_code('MUL', register, operand2, operand3, "Multiplication")

			elif self.operation == 'STAR_BOOL':
				# If operation is PLUS, store the product of left and right child in register
				ice9_parser_global.emit_code('MUL', register, operand2, operand3, "Boolean multiplication")

			elif self.operation == 'SLASH':
				# If operation is PLUS, store the division of left and right child in register
				ice9_parser_global.emit_code('DIV', register, operand2, operand3, "Division")

			elif self.operation == 'QUEST':
				# If operation is Quest, ,compare result of left child with zero
				ice9_parser_global.emit_code('JNE', register, 2, 7, "Jump on less than")

				# When FALSE, jump over the TRUE line
				ice9_parser_global.emit_code('LDC', register, 0, 0, "Load constant - false")
				ice9_parser_global.emit_code('LDA', 7, 1, 7, "Unconditional jump")

				# When TRUE
				ice9_parser_global.emit_code('LDC', register, 1, 0, "Load constant - true")

			elif self.operation in ['LT', 'LE', 'GT', 'GE', 'EQ', 'NEQ']:
				# If operation is a logical operator, we first compute the difference on left and right child
				ice9_parser_global.emit_code('SUB', register, operand2, operand3, "Subtraction before comparison")
	
				# Depending upon the operation, do a comparison of register and 0
				if self.operation == 'LT':
					ice9_parser_global.emit_code('JLT', register, 2, 7, "Jump on less than")
				elif self.operation == 'LE':
					ice9_parser_global.emit_code('JLE', register, 2, 7, "Jump on less than or equal to")
				elif self.operation == 'GT':
					ice9_parser_global.emit_code('JGT', register, 2, 7, "Jump on greater than")
				elif self.operation == 'GE':
					ice9_parser_global.emit_code('JGE', register, 2, 7, "Jump on greater than or equal to")
				elif self.operation == 'EQ':
					ice9_parser_global.emit_code('JEQ', register, 2, 7, "Jump on equal to")
				elif self.operation == 'NEQ':
					ice9_parser_global.emit_code('JNE', register, 2, 7, "Jump on not equal to")

				# When FALSE, jump over the TRUE line
				ice9_parser_global.emit_code('LDC', register, 0, 0, "Load constant - false")
				ice9_parser_global.emit_code('LDA', 7, 1, 7, "Unconditional jump")
	
				# When TRUE
				ice9_parser_global.emit_code('LDC', register, 1, 0, "Load constant - true")
				
			elif self.operation == 'MOD':
				# Since no direct instruction present for %, use / * -
				temp_reg = ice9_parser_global.get_next_register()
				ice9_parser_global.emit_code('DIV', temp_reg, operand2, operand3, "Modulo: division step")
				ice9_parser_global.emit_code('MUL', operand3, temp_reg, operand3, "Modulo: multiplication step")
				ice9_parser_global.emit_code('SUB', operand2, operand2, operand3, "Modulo: subtraction step")
				ice9_parser_global.reclaim_register()

			elif self.operation == 'UN_MINUS':
				# If operation is Unary Minus, ,multiply result of left child with -1
				temp_reg = ice9_parser_global.get_next_register()
				ice9_parser_global.emit_code('LDC', temp_reg, -1, 0, "Unary minus: Load -1")
				ice9_parser_global.emit_code('MUL', operand2, operand2, temp_reg, "Unary minus: Multiply with -1")
				ice9_parser_global.reclaim_register()

			elif self.operation == 'NOT':
				ice9_parser_global.emit_code('LDA', operand2, -1, operand2, "Boolean NOT: Subtract 1")
				ice9_parser_global.emit_code('JEQ', operand2, 2, 7, "Boolean NOT: Jump if operand was True")
				ice9_parser_global.emit_code('LDC', operand2, 1, 0, "Boolean NOT: Load True")	
				ice9_parser_global.emit_code('JNE', operand2, 1, 7, "Boolean NOT: Unconditional jump, operand was False")
				ice9_parser_global.emit_code('LDC', operand2, 0, 0, "Boolean NOT: Load False")
			
			# Operators that do require a new register allocated	
			elif self.operation == 'ARRAY_REF':
				register = expr_node.generate_address(self)				
				ice9_parser_global.load_array_variable_from_memory(register)

			elif self.operation == 'PROC_CALL':
					register = handle_proc_call(self)

			else:			
				# Get a free register for use
				register = ice9_parser_global.get_next_register()
		
				if self.operation == 'INT':
					# If operation is a integer constant, load register with it
					ice9_parser_global.emit_code('LDC', register, self.value, 0, "Load constant")
		
				elif self.operation == 'SLIT':
					ice9_parser_global.emit_code_for_string('.DATA', self.length)
					ice9_parser_global.emit_code_for_string('.SDATA', self.value)
					ice9_parser_global.emit_code('LDC', register, \
						ice9_parser_global.string_location_dict[self.value], 0, "Load address of string length")
		
				elif self.operation == 'ID':
					# If operation is a variable, load a register with it from memory
					ice9_parser_global.load_variable_from_memory(register, self.value)
	
				elif self.operation == 'TRUE':
					# If operation is a true, load register with 1
					ice9_parser_global.emit_code('LDC', register, 1, 0, "Load constant True")

				elif self.operation == 'FALSE':
					# If operation is a false, load register with 0
					ice9_parser_global.emit_code('LDC', register, 0, 0, "Load constant False")

		ice9_parser_global.set_register(register)
		return register