计算机系统要素:第六章 Part2 汇编编译器(symbol)

要给汇编编译器加入符号,首先要明确这个汇编编译器有哪些符号:

预定义符号:SP,LCL等,这些符号预先就在SymbleTable中定义好了对应内存的地址

变量variables:注意,变量是在第二遍读取阶段才依次从地址16开始计算的

标签符号lables:你会在机器码中见到(LOOP)@LOOP 这样的循环代码,这些就是标签代码,之所以要分两遍读取,就是因为(LOOP)这样的标签有可能出现在@LOOP之前,如果只读取一遍的话无法解决这个问题,因此第一遍读取的目的就是把所有标签的地址给确定。而标签的地址,按照书上的说法,是由(XXX)之前总的指令数决定的。

本书作者已经帮我们把问题最简化了,只要分别考虑这三类符号如何表示就能够在nonsymbol编译器的基础上完成这一部分的内容。


Parser和Code模块与nonsymbol编译器相同,不再列出。


SymbolTable.py

这个模块有些多此一举,因为很多函数在python中都有内置函数可以直接使用,但是为了遵守API规范,还是把这些函数都列出来了。

#!/usr/bin/python
def Constructor():
	symboldict={'SP' : 0,'LCL' : 1,'ARG' : 2,'THIS' : 3,'THAT' : 4,\
	'R0' : 0,'R1' : 1,'R2' : 2,'R3' : 3,'R4' : 4,'R5' : 5,'R6' : 6,'R7' : 7,\
	'R8' : 8,'R9' : 9,'R10' : 10,'R11' : 11,'R12' : 12,'R13' : 13,'R14' : 14,\
	'R15' : 15,'SCREEN' : 16384,'KBD' : 24576}
	return symboldict

def addEntry(symbol,address,symboldict):
	symboldict[symbol]=address
	return symboldict

def contains(symbol,symboldict):
	return symboldict.has_key(symbol)

def GetAddress(symbol,symboldict):
	return symboldict[symbol]


Assembler.py

#!/usr/bin/python
import sys
import Parser
import Code
import SymbolTable

filename=sys.argv[1]
#The first Loop, aiming to decide the lables' addresses
symboldict=SymbolTable.Constructor()
rfile = open(filename,'r')
i=0 #i is the sum of the construction numbers above lables
linepre=rfile.readline()
flag=Parser.hasMoreCommands(linepre)
while flag:
	#clean the line which starts with // or blank lines
	while linepre == '\n' or linepre.startswith('//'):
		linepre=rfile.readline()

	if linepre.find('(')>=0:
		symbol=linepre.strip('()\n')
		if not SymbolTable.contains(symbol,symboldict):
			symboldict=SymbolTable.addEntry(symbol,i,symboldict)
	else: 
		i+=1

	linepre=Parser.advance(rfile,linepre)
	flag=Parser.hasMoreCommands(linepre)

rfile.close()

#The second Loop
j=0 #j records the total number of previous variables
rfile = open(filename,'r')
wfile = open('prog.hack','w')
#main loop
line=rfile.readline()
flag=Parser.hasMoreCommands(line)
while flag:
	while line == '\n' or line.startswith('//'):
		line=rfile.readline()

	ctype=Parser.commandType(line)
	#compare command type
	if ctype is 'A_COMMAND':
		AS=Parser.symbol(line)
		if not AS.isdigit():
			if not SymbolTable.contains(AS,symboldict):
				symboldict=SymbolTable.addEntry(AS,j+16,symboldict)
				j+=1
			binAS=bin(SymbolTable.GetAddress(AS,symboldict))[2:]
		else:
			binAS=bin(int(AS))[2:]
		AString=binAS.zfill(15)
		wfile.write('0'+AString+'\n')

	#L_COMMAND should be deleted

	elif ctype is 'C_COMMAND':
		DestString=Code.dest(line)
		CompString=Code.comp(line)
		JumpString=Code.jump(line)
		wfile.write('111'+CompString+DestString+JumpString+'\n')

	line=Parser.advance(rfile,line)
	flag=Parser.hasMoreCommands(line)

rfile.close()
wfile.close()

注意点:

1,两次循环的问题

2,A指令中数字变量和字幕变量的分情况处理

相关文章
相关标签/搜索
每日一句
    每一个你不满意的现在,都有一个你没有努力的曾经。
公众号推荐
   一个历史类的公众号,欢迎关注
一两拨千金