学习要点:
1.软件的模块化:下层为上层提供服务,code->parser->assembler
2.学习思路:先写出没有符号表的编译器,再写有符号表的编译器
3.汇编编译器只是做文本的转换,选用Python简单便利
3.python相关知识:
1)字典以及相关操作
2)Python字符串操作
str.startswith()//以某字符串开头
str.strip() // 清除字符
str.find() //查找字符
str.split()//拆分字符串为list
3)二进制
a= bin(int('12'))[2:] //可得字符串‘12’对应的二进制字符串
b=a.zfill(12) //补足12位
注意:
1)代码只是把机器代码打印出来,并没有写入.hack文件
2)标签符号只需要存入符号表中,形如(loop)不需要机器码
代码实现
code.py
def dest(s):
dest_dict={'null':'000','M':'001','D':'010','MD':'011','A':'100','AM':'101','AD':'110','AMD':'111'}
return dest_dict[s]
def comp(s):
comp_dict={'0':'0101010','1':'0111111','-1':'0111010','D':'0001100','A':'0110000',
'!D':'0001101','!A':'0110001','-D':'0001111','-A':'0110011','D+1':'0011111',
'A+1':'0110111','D-1':'0001110','A-1':'0110010','D+A':'0000010','D-A':'0010011',
'A-D':'0000111','D&A':'0000000','D|A':'0010101','M':'1110000','!M':'1110001',
'-M':'1110011','M+1':'1110111','M-1':'1110010','D+M':'1000010','D-M':'1010011',
'M-D':'1000111','D&M':'1000000','D|M':'1010101'}
return comp_dict[s]
def jump(s):
jump_dict={'null':'000','JGT':'001','JEQ':'010','JGE':'011','JLT':'100','JNE':'101', 'JLE':'110','JMP':'111'}
return jump_dict[s]
parser.py
import code
def hasMoreCommands(i,list):
if i>=len(list):
return 0
else:
return 1
def advance(i):
return i+1
def commandType(line):
if line.find('@')>=0:
return 'A'
elif line.find('=')>=0 or line.find(';')>=0:
return 'C'
elif line.find('(')>=0:
return 'L'
def symbol(line):
symbolflag=line.strip(' @()\n\r')
return symbolflag
def dest(line):
if line.find('=')>=0:
destlist=line.split('=')
return code.dest(destlist[0].strip(' '))
elif line.find(';')>=0:
return code.dest('null')
def comp(line):
if line.find('=')>=0:
complist1=line.split('=')
return code.comp(complist1[1].strip('\n'))
elif line.find(';')>=0:
complist2=line.split(';')
return code.comp(complist2[0].strip(' '))
def jump(line):
if line.find('=')>=0:
return code.jump('null')
elif line.find(';')>=0:
jumplist=line.split(';')
return code.jump(jumplist[1].strip(' \n'))
assembler.py
import sys
import parser
import symboltable
filename = sys.argv[1]
ifile = open(filename,'r')
strfile = ifile.read()
instr=strfile.split('\n')
i=0
l1=['','\r','\n']
instr_str=[]
for x in instr:
if not x.startswith('//'):
if x not in l1:
instr_str.append(x.strip('\r'))
address = 16
sym=symboltable.Constructor()
for x in instr_str:
if x.find('@') >=0 or x.find('(')>=0:
symbol=parser.symbol(x)
if not symboltable.contains(symbol,sym) and not symbol.isdigit():
sym=symboltable.addEntry(symbol,address,sym)
address=address+1
while parser.hasMoreCommands(i,instr_str):
c_type=parser.commandType(instr_str[i])
if c_type=='A':
str1=parser.symbol(instr_str[i])
if str1.isdigit():
str1=bin(int(str1))[2:]
address = str1.zfill(16)
print address
else:
if symboltable.contains(str1,sym):
str2=bin(symboltable.GetAddress(str1,sym))[2:]
address1=str2.zfill(16)
print address1
if c_type=='C':
c_str=parser.comp(instr_str[i])
d_str=parser.dest(instr_str[i])
j_str=parser.jump(instr_str[i])
print '111'+c_str+d_str+j_str
i=i+1
symboltable.py
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]