好的,在我寻找编写编译器的必要内容的过程中,我遇到了一些障碍。似乎我发现的每一项技术或工具都在某些地方存在争议。
我现在使用Bison和Flex,但我觉得这种方法已经过时了。这是真的?这是一种很好的向前兼容的方式来继续编写一个完整的编程语言吗?
在不同概念和工具的海洋中(ANTLR,LL(k),GLR,LALR,LLVM,Flex,Bison)编写编译器的当前趋势和最佳实践是什么?龙书是否过时了?
答案 0 :(得分:30)
除非你想编写一个真正简单的编译器,否则你的注意力是错误的。
编写编译器只是编写解析器的一小部分。有一个解析器就像 当问题是攀登珠穆朗玛峰时,爬上喜马拉雅山的山麓。你到了山麓的顶部,向上看......只有2万英尺的距离,你只做了真正容易的部分。而且你会注意到,到达山麓顶部所需的技术远比你需要的技术更容易。
(仅供参考:目前最好的解析技术是GLR,很容易 在不破解语法的情况下接受含糊不清的语法。 GLR甚至可以轻松解析C ++, 这违反了C ++难以解析的民间定理。民间定理 来自试图使用YACC和ANTLR来解析它的人。)
要构建编译器,您需要许多机器:
我们甚至没有接近全球流量分析,全局优化或特殊处理 用于涉及SIMD指令或缓存优化的现代指令集。 ... 这个清单一直在继续。 Dragon书籍对基本主题进行了很好的介绍,但没有解决任何高级主题。你会想要Cooper的“工程编译器”和Muchnick的“高级编译器设计”作为参考,如果你在开始之前已经很好地浏览它们会很好。
构建现代编译器是一项非常出色的工程技术。
答案 1 :(得分:11)
虽然经过深入研究,但解析是编译中最不重要的部分。 (例外:你正在设计自己的具体语法,并且不断改进和改变语言。)
Yacc,Bison和朋友的设计是为了拥有64K内存的机器时代。它们非常适合在内存有限的机器上快速运行。但是,将语法强制为LALR(1)形式所需的人类工程量在今天是荒谬的。 Ira Baxter说GLR可能是最好,最灵活的解析技术,但PEG(Parsing Expression Grammars)也很好。在这两种情况下,人类工程学都比旧工具领先了几年。
解雇解析之后,我现在将开始另一项技术食品斗争:-) 编译主要包括将程序从一个表单重写到另一个表单,直到最终到达汇编代码或机器代码。对于这类问题,你真的不想使用C或C ++:
问:(当被问及Dave Hanson与Chris Fraser在lcc上发表他惊人的书时)“你和Chris已经花了十年的时间来构建可能是有史以来最精心设计的编译器之一。你从经验中学到了什么?“答:“好吧,C是编写编译器的糟糕语言。”
我建议您尝试一种流行的函数式语言,如Haskell或Standard ML。在这个领域工作的人普遍认为编译器是功能语言的“杀手级应用”。代数数据类型和模式匹配是为将抽象语法写入中间代码到机器代码而量身定制的。看看这些技术的强大功能的好地方是Andrew Appel的书 Compiling With Continuations 。 (Appel的编译器教科书也是一个很好的阅读和非常优雅的设计,但他并不总是解释为什么设计是这样的。)
答案 2 :(得分:7)
为了构建编译器,我强烈建议站在巨人的肩膀上。有很多好东西可以放在一起制作编译器。我一直在为C / C ++编写兼职编译器。它使用GLR进行解析,构建AST,使用SSA作为其中间形式,进行过程间优化,并为X86,ARM,MIPS,PowerPC,Sparc等生成代码。
秘密?我借用了几个来源的代码。
兼职工作我已经能够组建一个非常有用的工具系统。如果我试图从头开始,我现在几乎没有完成解析器。 ; - )
答案 3 :(得分:4)
我会假设你和我处于同一个位置:你想编写一个有趣的编译器,并至少学习它的每一个阶段。因此,您不希望仅为现有编译器编写插件。并且您希望避免使用太多现有的编译器模块,除非您可以准确理解他们正在做什么。在我的情况下,我使用bison
,这是一个轻微的例外,因为它至少做了一些我认为理所当然的事情(我在大学里学过语法等,但那是很长一段时间前)。另一方面,解析器生成器很常见,它是一个值得关注的编译器阶段:bison
可能会阻止我编写很多解析代码但是它给了我一个编写解析器动作代码的更改。
与某些建议相反,我会说你可以在不了解输入和目标语言的所有内容的情况下开始使用。除了一些例外情况,语言功能以后难以添加。我发现的一个例外是控制流:如果你将大多数后来的操作写在树形式上,那么很难满足break
,continue
和{{}之类的语句1}}(甚至是结构化形式)。所以我建议在做太多的事情之前从树翻译成CFG。
如果采用迭代方法,很容易完成大部分工作。
答案 4 :(得分:2)
我无法对各种方法进行比较,但ANTLR小组涵盖范围广range of rich target languages:
包括目前大多数常见的。 ANTLR还支持各种输出语言。我们计划解决类似CSS的语言
答案 5 :(得分:1)
Flex和Bison并没有什么问题,但如果您正在寻找更新的东西(面向对象),您可以考虑boost's Spirit library。
答案 6 :(得分:1)
有人认真询问龙书是否过时了?这是开创性的工作人员。我不能告诉你我从前两章中学到了多少(因为我已经忘记了它... ba-dum-bum)。
每项技术(除了goto语句之外)都有批评者和支持者。不要喋喋不休地“做出正确的工具选择”,并全神贯注地学习概念并以有意义的方式实施它们。我的意思是,即使你选择了世界上最完美的最好的工具,你也会认为你会像FORTRAN那样建立被爱,崇拜和尊重的东西......我的意思是我们喜欢它......对吧?
当然不是男人......这么多的学习来自犯错误。这就是你最了解的地方。
你可以做到!
答案 7 :(得分:1)
这是1)一个像Java或C ++这样的大型现有语言在一个极端,还是2)一种没有花哨的数据类型的小语言?
如果为1,你最好快速掌握Ira提到的所有技术。
如果是2,如果你只是编写一个递归下降的解析器,你可以立即执行它,并且a)在解析时将其转换为你最喜欢的语言(YFL),或者b)构建一个符号表和解析树,然后走那个生成YFL。如果您不想生成YFL,只需编写一个遍历解析树的解释器。
如果您的目标是学习所有棘手的技术,那么就这样做。如果没有,快速和肮脏是要走的路。如果是后者,请不要担心优化!!
顺便说一句,如果你想真正快速而又肮脏,而且你有C或C ++,并且你不会为编写宏而感到自豪,创建语言的一种简单方法就是编写一组宏。这样您就可以创建自己的语句,同时利用基础语言的数据类型,表达式语法,效率和运行时库。