本章的内容完全基于第七章,其核心是理解堆栈如何处理函数,并对程序运行控制有更充分的认识。在这里我必须对本书作者致敬,因为这一章的编排实在是太完美了,对于如此抽象的程序调度的概念,作者居然能够由浅入深地将其讲得如此透彻,功力实在是深厚。所以,我仍然强烈推荐大家按照顺序把每一个项目都完成。下面是我个人再做这一章时总结的四个注意点,供大家参考。
首先需要明确的是全局堆栈的概念。一开始接触全局堆栈难免会头疼,因为它里面的参数实在太多了。但其实它的机理非常简单,当调用一个新函数时,就把原先函数的重要参数全部压入堆栈,然后把新函数的参数压入堆栈,接下来就相当于用新函数对参数进行计算,计算完毕后,再将结果返回给原函数,并恢复原先的堆栈。为了更形象的理解这个过程,我建议把图8.3、8.5和8.8结合起来看。
第二点需要说明的是图8.5中所提到的临时变量FRAME和RET,其实他们就是R13,R14,R13~15可以用作任何用途,一般就作存储临时变量使用。
第三点,在调用return_address标签时,一定要给它加上相应的数字标签,以确保不同的return_address不会产生标签冲突,从而影响进程。此外,在获取return_address的地址时,应该使用@return_address D=A 而非D=M,要知道我就是因为这么一处小错误,整整检错检了一个下午。。。。
最后要注意static的处理。根据书中所说,只要我们把每个VM文件XXX.vm中的静态变量j翻译为汇编符号XXX.j,那么汇编编译器便会自动为其分配存储空间,所以,我们无需手动为其分配RAM空间。为了实现把静态变量命名为XXX.j,我将主文件中的翻译过程单独定义为了Main函数,通过给其传递filename来完成这一过程。
Vmtranslator.py
#!/usr/bin/python
import sys,os
import Parser
import CodeWriter
DELETEFLAG=0
def Main(rfile,wfile,filename):
line=Parser.advance(rfile)
flag=Parser.hasMoreCommands(line)
while flag:
while line == '\n' or line.startswith('//'):
line=rfile.readline()
if '//' in line:
line=line[:line.find('//')]
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)
elif ctype =='C_LABEL':
attribute1=Parser.arg1(line).strip()
CodeWriter.writeLabel(wfile,attribute1)
elif ctype =='C_GOTO':
attribute1=Parser.arg1(line).strip()
CodeWriter.writeGoto(wfile,attribute