计算机系统要素:第十一章 编译器:代码生成

一,项目介绍

终于来到了编译器部分的最后一个章节——代码生成阶段。本章的目标就是将Jack语言转化为VM语言,完成Jack编译器的构建。


刚刚接触这章的内容时,会比较难上手,最主要的问题就在于,这章的内容看起来和第十章没有什么关系。刚开始做这个项目时,我就很疑惑,第十章输出的不是一个结构化的xml文件吗?这个文件在第十一章根本不需要输出,那么这章的内容从何开始呢?

 

的确,这个xml文件是不需要输出的,但是第十章的目的并不单纯是输出这个xml文件,它更重要的目的是为了让我们了解如何对jack程序文件进行语法分析,以完成CompilationEngine的构建。所以,我们需要关注的是CompilationEngine的函数结构,这个函数结构才是第十一章内容的基础。

 

二,操作步骤

总体而言,作者为我们设计的操作顺序是非常合理的。在此,我再提出几点预备步骤,这些步骤并不是必要的,但是通过这些操作,能够使得整个项目的实现更加流畅。

 

1,先给命令行加上-x选项,如果命令行中出现-x,则表示输出xml文件和VM文件,不加-x,则表示只输出VM文件。这样子就将两个不同“写入文件流”区分开来。

2,构建符号表模块。存储符号表时,我所用的数据结构是Python语言中的二维列表。这一阶段的任务是把每一个遇到的Identifier都加以标注并且输出相关信息。

3,进入输出VM语言的阶段。首先可以使用内置的JackCompiler将Jack语言转换为VM语言,(Windows上的JackCompiler需要自己设置配置文件才能够使用,具体教程在这儿)从简单的文件开始转换,自己认真分析代码的转换过程。例如,最简单的Seven函数的Jack代码和VM代码分别如下。

class Main {
  function void main() {
      do Output.printInt(1 + (2 * 3));
      return;
   }
}

function Main.main 0
push constant 1
push constant 2
push constant 3
call Math.multiply 2
add
call Output.printInt 1
pop temp 0
push constant 0
return

之后你便可以对照二者,分析转换规则了,例如第一句function Main.main 0肯定是在读取完了所有的ClassVarDev,知道了函数名之后才写入的,于是,写入语句必然就是在compileStatements之前。照这个步骤,逐步完善你的编译器。

 

三,注意点

我的建议是,先回过头去复习VM代码和Jack语言,了解高级代码转化为VM代码的具体过程,你可以通过看图11.6,图7.9来了解其中的逻辑。


在写编译器的过程中,注意点非常多,这一方面,书中11.2节阐述的非常清楚,在此我重申几个比较关键的问题:

1,constructor, method和function参数配置不同,method方法会默认带一个this的参数,需要加以区分。而讨论参数时,VM代码中function xxx n与call function m中的n与m也是不同的,前者指的是函数中的局部变量数(local),后者指的是调用函数时引入的参数(argument)。

2,Function和Method的调用方式不同,Function只需调用类名ClassName.Function就可以使用,但是method需要调用具体的类实例如abc.Method才可以调用,如果方法就在类中的话,也可直接使用method()。

3,数组只可能在两个地方出现,一是term中,用于引用,另外是Let语句的左边,用于数组赋值。要注意的是,这两处调用的VM代码是不同的,需要加以区分。

4,constructor是构造函数,在编译时,需要先分析Class中有多少个field变量,然后使用Memory.alloc(size)来给他们分配空间,最后再将其基地址存入this指针中。

 

上述这些注意点的具体代码都可以通过JackCompiler编译现有文件而得到,我就不再赘述了。


最后,debug的过程是痛苦的,也是无可避免的。如果代码出现问题,可以比对JackCompiler的输出文件与你的编译器输出文件的不同。这个过程能够是你对编译有更深的理解。


JackCompiler.py

#!/usr/bin/python
import CompilationEngine
import SymbolTable
import sys,os

'''
The command line of this module is : JackCompiler.py (-x) sourcename
The first option is -x, which decides whether to run xmlWriter() and to output the constructive xml file\
putting forward by CompilationEngine.
'''

option=sys.argv[1]
if option == '-x':
	filename=sys.argv[2]
else:
	filename=sys.argv[1]

#clear all the // /* ... notes, create a new file to save the result
readfile = open(filename,'r')
copyfile = open('copyfile','w')
line=readfile.readline()
while line:
	while line == '\n' or line.startswith('//'):
		line=readfile.readline()
	if '//' in line:
		line=line[:line.find('//')]
	if '/*' in line:
		aline=line[:line.find('/*')]
		while line.find('*/')<0:
			line=readfile.readline()
		bline=line[line.find('*/')+2:]
		line=aline+bline
	copyfile.write(line)
	line=readfile.readline()
copyfile.close()
readfile.close()

#Main Function
readCopyFile=open('copyfile','r')
writeXmlFile=open(filename.strip('.jack')+'.xml','w')
writeVmFile=open(filename.strip('.jack')+'.vm','w')

outputCompile=CompilationEngine.Compile(readCopyFile,writeXmlFile,writeVmFile)
outputCompile.compileClass()

readCopyFile.close()
writeXmlFile.close()
writeVm
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值