关于Cool Compiler

来源:互联网 发布:温什么知什么的成语 编辑:程序博客网 时间:2024/05/21 14:09

这个Project其实是斯坦福cs143课程的一个assignment,这个作业的工作量确实很大。我花了大概整整二十天才完成了大部分的工作。没看错,是整整二十天,如果你没有一整段的时间来完成这个作业的话,我估计这个时间可能会延长个2~3倍的样子。但是如果光上课不做assignment的话,说实话,课程的效果会大打折扣,所以还是非常推荐大家来做一做这个Project的。好吧,随着我终于完成了这个assignment,非常矫情的说一句,我研一的生涯也随之结束了。

这堂课曾经在coursearea上出现过,但是现在coursearea上的课程现在已经下线了,我估计也不会再上线了,好在斯坦福自己弄了一个mooc网站,这里是compiler课程的链接地址:https://lagunita.stanford.edu/courses/Engineering/Compilers/Fall2014/info

你要注册了才能看到课程的完整信息,包括教学视频,ppt,以及作业。

class

我稍微来说一下我做的这个Project吧。我采用的是Java语言来编写,用Java的话,没有什么特殊的原因,纯粹是因为我想熟悉一下Java,另外Javalinux下有一个强大的IDE,会给代码的编写带来很多的便利。貌似在windows上编写的话,光是环境的配置都够人折腾了,我是个比较懒的人,所以直接在ubuntu下开干了。

虽然说,作业提供了一个虚拟机文件,你可以直接在虚拟机上完成你的工作,不过,我想吐槽的一点是,虚拟机的性能是在是太弱了,里面几乎无法流畅地运行IDE,除非你对C++/Java的语言特性非常熟悉,能够徒手用emacs或者vim这样的编辑器来书写代码的话,我还是推荐你直接在linux真机上书写你的代码。IDE你可以采用IntelliJ或者CLion,当然,现在巨硬貌似又出了黑科技,可以在windows上使用vs远程书写linux端的程序,你也可以试一试,当然,所有的这一切努力,都是为了写起来会舒心一点。对于Java来说,还是IntelliJ大法好!

IntelliJ

第一次和第二次的作业非常简单,第一次是要你写正则表达式,来匹配字符,第二次作业是要你写一些文法,构造出parser,第一次和第二次的代码量都不是很大,但是要求你阅读的东西却非常多,包括各种工具的使用文档,我开始也是一头雾水,但是读了读了之后就好了很多,作业其实不能啦,难的是每次编码前都要读一堆的文档,所以这两次作业,我每次作业花费了大概三天。

从第三次作业开始,代码量陡然增加,第三次要求你进行语义分析,对AST进行遍历来标注各个表达式的类型,虽然题目给了一个框架,但是没有写死,所以这次的作业非常开放,你想怎么来实现你的结构都行,但是自由度的放开,带来了难度的增加,以前从来没有写过的同学在这里可能会感到有一些吃力,我还好,看过了EOPL这本书之后,这次的语义分析难度倒不是很大,所以我大概花了四天,将测试用例逐条逐条都通过了。

在这里,我推荐你的写代码方式是测试驱动,通过作业给出的一个个测试用例来解决你代码中存在的一个又一个坑。这种方法非常高效。

非常有挑战度的是第四次作业,这次是汇编代码的生成,题目给了你一本汇编代码的查询手册,还给了n多的资料,汇编代码,要你一一查看,编译器其实就是这样啦,既然要写编译器,这意味着你必须要对另外一门汇编语言要特别熟悉,这样才能够做好代码翻译的工作。作业要求你将代码翻译成MIPS代码,好吧,对于我这种之前都没有接触过MIPS的人,难度确实是杠杠的。好在之前大学的时候手写过x86的汇编代码,对汇编代码的书写流程还算是比较熟悉啦,但是其实第四次的难度在于最开始,因为你压根就不知道应该如何开始,更加坑爹的是,github上压根找不到靠谱的代码,大部分人压根就没做这个assignment(确实有难度)。

当然,我光看这些东西也看不出个所以然来,所以我也参考了一下别人怎么弄的,一步一步理解,一步一步推敲,这次作业我差不多做了10天左右,你可以看到,这次作业的工作量等于前三次作业的总和,前五天基本天天在抓瞎,后来参考了一下之后对于大概怎样来书写有了一个比较清楚的认识,所以大家也不要害怕,其实还挺简单的,大概就这么几条规则吧,翻译一个函数的时候,首先要约定好堆栈的次序,约定这个寄存器里放什么,那个寄存器里放什么,只有每个函数都遵循这样的规则,你翻译出来的代码才不会出错。调用函数前,记得要将可能被调用的函数改变的寄存器里面的内容保存起来,你可以压栈,也可以保存在别的不用的寄存器里,调用返回之后要记得恢复回来。此外,如果想加快程序的运行速度的话,多用寄存器。否则,你翻译出来的代码会这里不对,那里又不对。

大概就这几条吧,当然翻译完成之后,必须要推荐一个利器,叫做QtSpim,方便汇编代码的调试,记住这个玩意太重要了,你不会使用的话,基本上这次作业你是完不成的,我也是通过对汇编代码的debug才解决了几个重大的bug,才最终完成了这次作业,当然,我并没有进行垃圾收集,所以扣除了5分。

我这里稍微讲解一些如何使用QtSpim吧!毕竟我也是折腾了7天左右还不会用这玩意,我讲了一下这个玩意之后,你的难度就会降低很多了。

怎样在ubuntu上安装QtSpim呢?首先你要安装Qtsdk

sudo apt-get install qt-sdk

然后,你要下载QtSpim提供的安装包,https://sourceforge.net/projects/spimsimulator/files/

下载deb格式的安装包,安装的事情,我就不说了。为了能够调试我们程序生成的代码,我们还需要做一些设置,首先要复制出/usr/class/cs143/lib/trap.handler文件,这个文件是作业提供给我们的,里面有一些basic class函数的定义,在运行我们的代码之前,我们必须首先加载这个文件。

copy file

接下来你要用你的软件加载这个文件。先点击设置:

settings

然后在这个页面加载原来的那个文件。

load file

现在差不多就可以加载你的汇编代码了:

all_done

好了,然后自己去实验吧,最关键的步骤我已经告诉你了,我差不多就是上面卡了几天,搞的我还以为这个玩意没法调试生成的代码,不过总算是完成了。总算是如释重负了。

总体来说,这是非常优秀的一个Project,因为最终的完成品功能其实已经很强大了,这可比一般的玩具语言要强得多。做完之后的收获其实也是仁者见仁智者见智啦,对于我来说,只有第四次assignment才真正有收获,前三个作业的内容其实写解释器的时候已经搞过几遍了,所以没什么吃惊的,而第四次的代码生成是我第一次从汇编的程度来看待我们使用的编程语言,特别是OOP的语言,我差不多彻底理解了C++的虚函数表的概念了,原来这个玩意是这样来实现的,光是如此,我就觉得这么多天的花费值得了。这个Project,打通了编程语言和底层的隔阂,使得我们可以从更加底层的角度来看待这个构建在抽象中的计算机世界。

现在在我看来,一切的语法都没有太大的意义了,其实所有的语言在内存里面差不多都是AST的形式,语法只是表象而已,将AST的节点加上一些所谓的书写方法,加上一些语法糖,可以很轻松地得到一门新的语言,所以,我们看到的都是假象而已。

世界本不是如此,一切都是假象,我们要感谢那些构建抽象的人们。

好了,我研一差不多也该结束了,回首这一年,无怨无悔,因为我做了很多我之前就想做的事情,比如写编译器,解释器,比如说读书,编码,这一年我读完了60多本计算机技术类经典,对于计算机有了一番新的认识,编程的能力比以前提升了不少,不为别的,因为我明白了递归的含义,递归是编程中最强大的利器之一,知道了将大问题拆解,分散成小的问题,通过小的函数组合起来形成强大的功能,感谢SICP以及EOPL以及 The little schemer,让我看到了另外一片天地。

好吧,要参考的同学可以查看这里:https://github.com/lishuhuakai/CS/tree/master/CS143_Compiler/Cool

That‘s All!

0 0
原创粉丝点击