最近在翻看以前加星的 Google Reader 文章,把有用的整理出来打标签,然后就看到了这篇。原文作者的博客现在不知道被丢到哪边去了,搜也搜不到,转到这里,权当保存一下吧。
原文链接:Compilers: what are you thinking about?。当然,已经打不开了。
Compilers: what are you thinking about?
Author: Rotten Cotton
My recent post Compiler bibliography, a motley list of compiler papers that had been sitting in a box in my attic, generated a surprising amount of traffic: over a thousand unique visitors. But no comments. For those of you interested in compiler design, I ask, what are you trying to understand? What are you trying to do?
原文链接:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-6.html
既然上次已经提到说,我们其实是在从 Lisp、Scheme 还有类似的其他语言中借鉴各种要实现的功能(我没想过要把这个项目做成原创的⋯⋯或者至少也要等到以后再说吧),那么现在也是时候实现一些更加强大的功能了。
那就来做延迟求值以及匿名函数吧
Lambda ,又名匿名函数,可以像普通的数值或者字符串类型那样被当作函数参数来到处传递,也可以在需要的时候才调用(当然不调也可以)。同时,外层函数(也就是定义匿名函数的函数)作为它们的运行环境,在其中定义的局部变量可以被这些匿名函数所访问。这就形成了[一个闭包](http://en.wikipedia.org/wiki/Closure_(computer_science))。我们这次并不是要实现完整的闭包功能,只是开头的一小步而已,完整的实现要等到再后面了。
原文链接:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-5.html
上次我承诺会发布的更快一些,不过还是失败了⋯⋯作为补偿,这章的内容将会是原计划中的第 5,6,7 章内容的合并,因为这三章确实都很短。闲话少叙:
处理数字常量
到目前为止,我们只处理了一些实现所必须的数字常量,也就是当一个外部函数的返回值是数字的情况,而且没有做任何形式的类型检查。
原文链接:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-4.html
抱歉,又拖了很长时间。要忙的事情实在很多。正如上一篇文章末尾提到的那样,这次要讲的是自定义函数,以及一个简单的“运行时库”。
自定义函数
一门编程语言如果连函数和方法都没有的话,那也就不能算是一门语言了。而且,实践表明,一门面向对象语言中的所有特性都可以通过过程式的语言要素来实现:一个方法也只不过是以一个对象为额外参数的函数而已。因此,增加对函数的支持就是实现一门语言的核心所在。
原文链接:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up—step-3.html
我本来是想要早点发表的,可是我这周又不行了 – 虽然整理一篇旧文只需要半个小时。不管怎样,这是第三章,而且我会在末尾大概列一下之后的大纲。由于我会试着把一些小的步骤组合成更有内容的章节(下面就有个这样的例子),因此原来的 30 篇文章已经被我给减到了 20 篇左右(当然,这只是我已经完成了的,后面还有新的呢)。
原文地址:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-2.html
我会选择 Ruby 来作为我的实现语言并没有什么特别的理由。在现阶段,语言的选择并不重要;不过,我确实很喜欢 Ruby。
在这之后,我会采取一系列的步骤令所实现的语言向其实现语言靠拢。我的意思是,我想将编译器实现为可以自举的,即它应该能够编译自身。
而这也就意味着,要么我的编译器需要至少支持 Ruby 语言的一个子集,要么就需要一个中间的翻译步骤,来将编译器中的实现翻译成它自己可以编译的语言。
原文链接:http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-1.html
[译者抱怨:翻译好麻烦啊。]
我已经将这件事情搁置了很长时间了 – 这个系列中最早的文章甚至可以追溯到 2005 年的早期,而那时我还没有开始写这个博客呢。
这是一个国外的编译器达人写的一系列教程,内容为用 Ruby 语言,以自底向上的方式开发一个 Ruby 语言的编译器。这个教程非常适合于实战派的程序员。该教程的入口见这里,其代码见这里。
我会试着翻译一下这个教程。由于这个项目之后又有了很大的进展,而教程本身却又已经很久没有更新了,所以之后我可能也会自己总结一下那些最新的开发工作。
我正在看虎书,在这本书中所给出的那个 MiniJava 语言的语法并不是 LALR(1) 语法,因此在某些情况下,所生成的语法分析器会对正确的输入给出语法解析错误。不过 Bison 提供了一个简单而又强大的解决方案,可以轻易的解决掉这个问题。
注意,我用的软件版本为:Bison - 2.4.1,Flex - 2.5.35 。至于老的版本会怎样我就不深究了。工具不是重点。
%skeleton "lalr1.cc"
可以用
%language "c++"
来代替了,其中参数 “c++” 不区分大小写。
今天在用 Bison 手册中的 C++ 例子作为一个编译器前端实现的起点时发现,这个官方示例居然编译通不过,具体错误为在 Bison 生成的头文件中,没有 Driver 类的声明。按照 POSIX Yacc 标准,位于 %union
块之前的 Prologue 区中的代码,应该会被拷到头文件中的啊,于是 google 半天,在某个地方的 Bison ChangeLog 中找到了线索。
原来,POSIX Yacc 确实应该符合上述行为,可是 Bison 这家伙为了统一性,从 2.3a 版开始,就把所有 Prologue 中的代码,不管是 %union 前的还是之后的,统统只拷到实现文件中而不管头文件了。而为了对应不同的需求,又新增了一套 Prologue 语法,就是 %before-header
等四个新的 directive。好吧,这样也不错,以显式的统一格式的声明代替了可能会让人抓狂的隐规则。遂试之,结果告诉我说语法错误。接着往上看 ChangeLog 才发现,到了 2.3b 就又改了,把 %before-header
改成了 %code
之类的。这回终于没问题了。
我说,这也太不厚道了吧,这种兼容性改动,我在它的文档里面扒了半天都没看到半个字,而且还是出现在流行度这么高的软件中。于是深刻体会到「错文档不如无文档」的道理啊。由此看来,要做好软件还是需要有相当的责任感的啊。