好吧,在我寻找编写编译器的必要内容的过程中,我遇到了一些障碍.似乎我发现的每一项技术或工具都在某些地方存在一些反对意见.
我现在使用Bison和Flex,但我觉得这种方法已经过时了.这是真的?这是一种良好的向前兼容的方式来继续编写完整的编程语言吗?
在不同概念和工具的海洋中(ANTLR,LL(k),GLR,LALR,LLVM,Flex,Bison)编写编译器的当前趋势和最佳实践是什么?龙书是否已过时?
除非你想编写一个真正简单的编译器,否则你的注意力是错误的.
编写编译器只是编写解析器的一小部分.当问题在攀登珠穆朗玛峰时,拥有一个解析器就像爬上喜马拉雅山的山麓.你到了山麓的顶部,向上看......只有2万英尺的距离,你只做了真正容易的部分.而且你会注意到,到达山麓顶部所需的技术远比你需要的技术更容易.
(仅供参考:目前最好的解析技术是GLR,它可以轻松接受模糊语法而不会破解语法.GLR甚至可以轻松解析C++,这违反了C++难以解析的民间定理.民间定理来自人们试图使用YACC和ANTLR来解析它).
要构建编译器,您需要许多机器:
AST建设
符号表构造
控制流量分析
数据流分析
程序代码表示基本上作为数据流计算(SSA或三元组)
目标机器的模型
将程序代码映射到机器指令的方法
注册分配
优化:持续传播,循环展开,......
我们甚至还没有接近全局流分析,全局优化或涉及SIMD指令或缓存优化的现代指令集的特殊处理.......这个清单一直在继续.Dragon书籍对基本主题进行了很好的介绍,但没有解决任何高级主题.你会想要Cooper的"工程编译器"和Muchnick的"高级编译器设计"作为参考,如果你在开始之前已经很好地浏览它们会很好.
构建现代编译器是一项非常出色的工程技术.
解析虽然经过深入研究,但却是编译中最不重要的部分.(例外:您正在设计自己的具体语法,并且不断改进和更改语言.)
Yacc,Bison和朋友的设计是为了拥有64K内存的机器时代.它们非常适合在内存有限的机器上快速运行.但是,将语法强制为LALR(1)形式所需的人类工程量在今天是荒谬的.Ira Baxter说GLR可能是最好,最灵活的解析技术,但PEG(Parsing Expression Grammars)也很好.在这两种情况下,人类工程学都比旧工具领先了几年.
解散了解析后,我现在将开始另一项技术食品斗争:-)编译主要包括将一个程序一遍又一遍地重写到另一个表单,直到最终到达汇编代码或机器代码.对于这种问题,你真的不想使用C或C++:
问:(当被问及戴夫汉森与克里斯弗雷泽一起出版关于lcc的精彩书籍时)"你和克里斯花了十年时间建造了可能是有史以来最精心设计的编制器之一.你从这次经历中学到了什么?"
答:"好吧,C是编写编译器的糟糕语言."
我劝你尝试一种流行的函数式语言,比如Haskell或Standard ML.在这个领域工作的人普遍认为编译器是功能语言的"杀手级应用".代数数据类型和模式匹配是为将抽象语法写入中间代码到机器代码而量身定制的.看看这些技术的力量的好地方是Andrew Appel的书Compiling With Continuations.(Appel的编译器教科书也是一个很好的阅读和非常优雅的设计,但他并不总是解释为什么设计是这样的.)
为了建立一个编译器,我强烈建议站在巨人的肩膀上.有很多好东西可以放在一起制作编译器.我一直在为C/C++编写兼职编译器.它使用GLR进行解析,构建AST,使用SSA作为其中间形式,进行过程间优化,并为X86,ARM,MIPS,PowerPC,Sparc等生成代码.
秘密?我借用了几个来源的代码.
来自clang的预处理器和错误报告
Elkhound和Elsa编译器生成器和C/C++编译器
用于优化和代码生成的LLVM系统
兼职工作我已经能够组建一个非常有用的工具系统.如果我试图从头开始,我现在几乎没有完成解析器.;-)
http://ellcc.org