您的位置:首页 > 理论基础

计算机系统要素:第七章 虚拟机I:堆栈运算

2014-09-05 10:30 274 查看
这一章的项目和第六章类似,都是用高级语言实现文本翻译的过程。但是,这一章对于VM语言和汇编语言的理解要求较上一章要高得多。所以这一章的学习要点在于,充分理解VM语言实现过程中计算机内存所做的每一个步骤。

HACK机器语言要点复习:

1,@X的意义为把X存入A寄存器,M代表的是Memory[A],即A所代表的地址中所存的数值,A=MM=D两句并列意味着将D中数据存入Memory[A],这是这一章中用得最多的逻辑语句。

2,在实现eq,gt,lt时,需要用汇编语言实现If的选择功能,这里需要用到两个lable,一个有条件jump,一个无条件jump,代码实现为:

// Compare R1=R2 set result in R3
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
D=D-M
@RET_TRUE
D;JEQ
D=0         // need to return False
@CONTINUE
0;JMP
(RET_TRUE)
D=-1        // need to return True
(CONTINUE)
@SP
A=M
M=D
@SP
M=M+1


学习步骤:

1,按照书中7.5所推荐的实现顺序依次实现5个vm文件的转化。

2,对于每一个文件,先在VMEmulator中运行.vm文件和xxxxVME.tst,通过观察其每一步是如何实现的,深入理解VM语言中push,pop和各个参数的实际意义。

3,自己手写相关的HACK机器语言代码,一定要从简到繁,从push constant这种最简单的语句开始一步一步来。

4,将转换过程用高级语言实现,测试并修改

注意点:

1,第七章中的机器语言和第六章中的机器语言在结构上略有不同,这一章中的语言更加向高级语言靠拢,在有些地方显得“啰嗦”,例如,push constant 7这么一句话,需要@7 D=A @SP A=M M=D @SP M=M+1这么多汇编语言来实现,但是其中每一句话都是有意义的,所以一定要理解每一句VM语言究竟做了哪些事。

2,因为一个vm文件中可能会同时出现许多eq,lt这样的涉及jump的语句,如果每一个lable都相同的话,那么lable就会产生重复冲突,如

@Lable



(lable)



@lable



(lable)

当机器到达第一个@lable点时,就会跳到最后一处(lable)。为了避免这种情况,需要给不同的lable依次加上编号,如lable1, lable2,这儿可以使用定义全局变量来实现。

3,翻译pop segment index的过程中,首先需要获取segment中存储的地址,然后将index加在这个地址上,得到目标地址。最后把当前SP所指向的地址中的值弹入这个目标地址。这个过程是无法用机器语言直接实现的,因为当中涉及两次调用寄存器D。唯一的解决方案就是在翻译过程中用index控制循环语句,让其自动添加index次A=A+1,这样的话就免去了多次调用D寄存器的困难。

Vmtranslator.py,Parser.py这两个文件的实现和第六章类似

Vmtranslator.py

#!/usr/bin/python
import sys,os
import Parser
import CodeWriter

filename=sys.argv[1]
rfile = open(filename,'r')
wfile = CodeWriter.setFileName(filename)
wfile.write('@256\nD=A\n@SP\nM=D\n')
line=Parser.advance(rfile)
flag=Parser.hasMoreCommands(line)
while flag:
while line == '\n' or line.startswith('//'):
line=rfile.readline()
ctype=Parser.commandType(line)
if ctype == 'C_ARITHMATIC':
attribute1=Parser.arg1(line).strip()
CodeWriter.writeArithmatic(wfile,attribute1)
elif ctype in ('C_PUSH','C_POP'):
attribute1=Parser.arg1(line).strip()
attribute2=Parser.arg2(line).strip()
CodeWriter.writePushPop(wfile,ctype,attribute1,attribute2,filename)
line=Parser.advance(rfile)
flag=Parser.hasMoreCommands(line)

rfile.close()
CodeWriter.Close(wfile)


Parser.py

#!/usr/bin/python
Arith=('add','sub','neg','eq','gt','lt','and','or','not')

def hasMoreCommands(line):
if not line:
return 0
else:
return 1

def advance(rfile):
line=rfile.readline()
return line

def commandType(line):
if line.find('push')>=0:
return 'C_PUSH'
elif line.find('pop')>=0:
return 'C_POP'
elif line.strip() in Arith:
return 'C_ARITHMATIC'

def arg1(line):
if commandType(line) is 'C_ARITHMATIC':
return line.strip()
else:
spline=line.split(' ')
return spline[1]

def arg2(line):
if commandType(line) in ('C_POP','C_PUSH','C_FUNCTION','C_CALL'):
spline=line.split(' ')
return spline[2]


CodeWriter是实现翻译过程的核心文件

CodeWriter.py

#!/usr/bin/python
import sys,os
import Parser
CODEFLAG1=0
CODEFLAG2=0

def setFileName(filename):
filetuple=os.path.splitext(filename)
wfile = open(filetuple[0]+'.asm','w')
return wfile

def writeArithmatic(wfile,command):
global CODEFLAG1,CODEFLAG2
if command == 'add':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D+M\n@SP\nM=M+1\n')
elif command == 'sub':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=M-D\n@SP\nM=M+1\n')
elif command == 'neg':
wfile.write('@SP\nM=M-1\nA=M\nM=-M\n@SP\nM=M+1\n')
elif command == 'and':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D&M\n@SP\nM=M+1\n')
elif command == 'or':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D|M\n@SP\nM=M+1\n')
elif command == 'not':
wfile.write('@SP\nM=M-1\nA=M\nM=!M\n@SP\nM=M+1\n')
elif command == 'eq':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=D-M\n@RET_TRUE'+str(CODEFLAG1)+'\
\nD;JEQ\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\
\n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
CODEFLAG1+=1
CODEFLAG2+=1
elif command == 'gt':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\
\nD;JGT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\
\n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
CODEFLAG1+=1
CODEFLAG2+=1
elif command == 'lt':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\
\nD;JLT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\
\n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
CODEFLAG1+=1
CODEFLAG2+=1

def writePushPop(wfile,command,segment,index,filename):
if command == 'C_PUSH':
if segment == 'constant':
wfile.write('@'+index+'\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif segment == 'local':
wfile.write('@LCL\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif segment == 'argument':
wfile.write('@ARG\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif segment == 'this':
wfile.write('@THIS\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif segment == 'that':
wfile.write('@THAT\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif segment == 'pointer':
if index == '0':
wfile.write('@3\n')
elif index == '1':
wfile.write('@4\n')
wfile.write('D=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
<span style="white-space:pre">		</span>elif segment == 'static':
<span style="white-space:pre">			</span>staticname=filename.strip('.vm')+'.'+index
<span style="white-space:pre">			</span>wfile.write('@'+staticname+'\nD=A\nA=D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n')
elif command =='C_POP':
if segment == 'local':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\n')
for i in range (0,int(index)):
wfile.write('A=A+1\n')
wfile.write('M=D\n')
if segment =='argument':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\n')
for i in range (0,int(index)):
wfile.write('A=A+1\n')
wfile.write('M=D\n')
if segment == 'this':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\n')
for i in range (0,int(index)):
wfile.write('A=A+1\n')
wfile.write('M=D\n')
if segment == 'that':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\n')
for i in range (0,int(index)):
wfile.write('A=A+1\n')
wfile.write('M=D\n')
if segment == 'pointer':
wfile.write('@SP\nM=M-1\nA=M\nD=M\n')
if index == '0':
wfile.write('@3\n')
else:
wfile.write('@4\n')
wfile.write('M=D\n')
<span style="white-space:pre"></span><span style="white-space:pre">		</span>if segment == 'static':
<span style="white-space:pre">			</span>staticname=filename.strip('.vm')+'.'+index
<span style="white-space:pre">			</span>wfile.write('@SP\nM=M-1\nA=M\nD=M\n@'+staticname+'\nM=D\n')

def Close(wfile):
wfile.close()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: