我遇到了这个:Writing a compiler using Turbo Pascal
我很好奇是否有任何教程或参考资料解释如何创建一个简单的C编译器。我的意思是,如果它让我达到理解算术运算的水平就足够了。在Ken Thompson阅读本文后,我变得非常好奇。写一些理解自己的东西的想法似乎令人兴奋。
为什么我提出这个问题而不是问谷歌?我试过谷歌和帕斯卡一个是第一个链接。其余的似乎没有相关性,并且增加了......我不是CS专业(所以我仍然需要了解所有这些工具,如yacc),我想通过这样做来学习这一点,并希望有更多经验的人总是比谷歌更擅长这些事情。我想阅读一些与上面列出的文章相同的文章,但至少突出了构建简单C编译器的自举阶段。
另外,我不知道最好的学习方法。我是否开始用C或其他语言构建C编译器?我是否编写C编译器或其他语言?一旦我有方向去探索,我觉得这样的问题会得到更好的回答。有什么建议吗?
有什么建议吗?
答案 0 :(得分:24)
编译器由三部分组成:
有很多很好的解析器生成器以语言语法开头。也许ANTLR会是你开始的好地方。如果你想坚持C根,试试lex / yacc或bison。
C语法有,但我认为C语言很复杂。你最好先从语言的一部分开始,然后继续努力。
获得AST后,您可以使用它来生成您将运行的机器代码。
这是可行的,但并非无足轻重。
我还会查看亚马逊有关编写编译器的书籍。龙书是经典之作,但也有更多现代书。
更新:Stack溢出有类似问题,如this one。查看这些资源。
答案 1 :(得分:24)
答案 2 :(得分:15)
对于它的价值,Tiny C Compiler是一个相对较小的源代码包中功能齐全的C编译器。你可能会从研究这个来源中受益,因为它可能比试图理解GCC的所有源代码库要容易得多。
答案 3 :(得分:12)
这是我的观点(和猜想)如果不理解本科(中学后)计算机科学课程中通常涵盖的数据结构,编写编译器将很困难。这并不意味着你不能,但你需要知道必要的数据结构,如链表和树。
我建议将自己局限于语言的基本子集,例如常用运算符,仅整数支持以及基本函数和指针,而不是编写完整或符合标准的C语言编译器(至少在开始时)。一个典型的例子就是Ron Cain的Small-C,在Dr. Dobbs Journal写的一系列文章中受到欢迎,我相信20世纪80年代。他们在James Hendrix的绝版书CD上发表A Small-C Compiler。
我建议遵循Crenshaw的教程,但是将它写成类似C语言的编译器,以及你希望定位的任何CPU目标(Crenshaw的目标是Motorola 68000 CPU)。为此,您需要了解要在其上运行已编译程序的目标的基本程序集。这可能包括68000或MIPS的仿真器,它们可以说是更好的汇编指令集,而不是Intel x86(16/32位)的古老的CISC指令集。
有许多潜在的书籍可以作为学习编译器/翻译理论(和实践)的起点。阅读comp.compilers FAQ,并在各种在线图书销售商处进行评论。大多数入门书籍都是作为大二到大学本科计算机科学课程的教科书编写的,因此如果没有CS背景,它们可能会很慢。 Thomas Parsons撰写的一本较旧的书可能比“The Dragon Book”更具介绍性,但更容易阅读。 Introduction to Compiler Construction 。它比较旧,所以您应该能够以合理的价格从您选择的在线图书销售商处找到一份旧版本。
所以我想说,尝试从Jack Crenshaw的Let's Build a Compiler教程开始,按照他的示例作为指南编写自己的教程,并构建简单编译器的基础知识。一旦你有了这个工作,你就可以更好地决定你从哪里开始。
<强>加了:强>
关于自举过程。由于现有的C编译器可以免费使用,因此您无需担心自举。使用单独的现有工具(GCC,Visual C ++ Express,Mingw / djgpp,tcc)编写编译器,您可以担心在稍后阶段自行编译项目。我对这一部分问题感到惊讶,直到我意识到你通过阅读肯托马斯的ACM图灵奖演讲Reflections on Trusting Trust来编写自己的编译器的想法,该演讲确实进入了编译器引导过程。这是一个适度的高级主题,也简直是一个麻烦。我甚至发现在较旧的Unix系统(64位Alpha上的数字OSF / 1)下引导GCC C编译器,其中包括C编译器,这是一个缓慢且耗时且容易出错的过程。
另一类问题是像Yacc这样的编译器工具实际上做了什么。 Yacc(来自GNU的另一个编译器编译器或Bison)是一种旨在使编写(或转换器)解析器更容易编写的工具。基于您输入到yacc的目标语言的形式语法,它会生成解析器,它是编译器总体设计的一部分。接下来是Lex(或GNU的flex)用于生成词法分析器或扫描器,它通常与yacc生成的解析器结合使用,以形成编译器前端的骨架。这些工具使得编写者的前端可以说比编写词法分析器和解析器更容易。 Crenshaw的教程不使用这些工具,您也不需要,许多编译器编写者并不总是使用它们。当然,Crenshaw承认教程的解析器非常基础。
Crenshaw的教程还跳过生成AST(抽象语法树),这简化了但也限制了教程编译器。它缺乏大多数(如果不是全部)优化,并且与特定编程语言和编译器的“后端”发出的特定汇编语言密切相关。通常,AST是一个中间部分,可以执行某些优化,并用于在设计中解耦编译器前端和后端。对于没有计算机科学背景的初学者,我建议不要担心你的第一个编译器(或至少是它的第一个版本)没有AST。我认为保持它小而简单将帮助你完成编写第一个版本的编译器,然后你可以从那里决定你想如何继续。
答案 4 :(得分:6)
您可能对图书/课程 The Elements of Computing Systems:Building a Modern Computer from First Principles 感兴趣。
请注意,这不是关于从newegg购买的东西构建“pc”。它首先描述了布尔逻辑基础,并构建了一个虚拟计算机,从最低级别的抽象到逐步更高级别的抽象。课程材料都在线,这本书本身在亚马逊上相当便宜。
在课程中,除了“构建硬件”之外,您还将以逐步的方式实现汇编程序,虚拟机,编译器和基本操作系统。我认为这将为您提供足够的背景知识,以深入研究主题领域,并在其他答案中列出一些更常见的资源。
答案 5 :(得分:5)
编译器是一个复杂的主题,涵盖了
的各个方面这绝不是详尽无遗的,因为它是从山顶的抽象鸟瞰图,它归结为使语法符号正确并确保格式错误的输入不会将其丢弃,实际上是一个良好的输入处理无论多么畸形,可怕,滥用的输入案件被抛到脑后,都不应该跪倒在地。并且,在决定和知道输出将是什么时,它是否在机器代码中,这意味着您可能必须密切了解处理器指令...包括变量的内存寻址等等......
以下是一些供您入门的链接:
答案 6 :(得分:5)
在The Unix Programming Environment中,Kernighan和Pike进行了5次迭代,使计算器从简单的基于C的词法分析和立即执行到yacc / lex解析和抽象机器的代码生成。因为他们写的如此奇妙,我不能建议更顺畅的介绍。它肯定比C小,但这可能是你的优势。
答案 7 :(得分:5)
我如何[开始编写]一个简单的C编译器?
编译C 并不简单。最好的简单C编译器是Chris Fraser和David Hanson的lcc。他们花了10年的时间从事设计工作,尽可能简化设计,同时仍能生成相当不错的代码。如果您可以访问大学图书馆,那么您应该可以获得他们的图书。
我是否开始用C或其他语言构建C编译器?
其他一些语言。有一次我问汉森他和弗雷泽在lcc项目上花了10年时间学到了什么。汉森说的主要是
C是编写编译器的糟糕语言。
你最好使用Haskell或ML的一些方言。两种语言都提供代数数据类型的功能,这是编译器编写者面临的问题的完美匹配。如果你仍然想要追求C,你可以从George Necula的CIL开始,这是用ML编写的C编译器的一大块。
我想阅读一些与上面列出的文章相同的文章,但至少突出了自举阶段...
你不会找到像Ken这样的另一篇文章。但Andrew Appel撰写了一篇名为Axiomatic Bootstrapping: A Guide for Compiler Hackers的好文章,我找不到免费版本,但很多人都可以访问ACM数字图书馆。
有什么建议吗?
如果你想编写编译器,
使用Haskell或ML作为您的实现语言。
对于您的第一个编译器,选择一个非常简单的语言,如Oberon或类似P0,来自Niklaus Wirth的书 Algorithms + Data Structures = Programs 。 Wirth因设计易于编译的语言而闻名。
您可以为 second 编译器编写C编译器。
答案 8 :(得分:3)
编译器是一个非常大的项目,虽然我认为尝试它不会有什么坏处。
我知道至少有一个用Pascal编写的C编译器,所以它不是你能做的最疯狂的事情。我个人会选择一种更现代的语言,其中实现我的C编译器项目,既简单易用(很容易用于Python,Ruby,C,C ++或Java的d / l包),也因为它你的简历会更好看。
但是,为了将编译器作为初学者项目,您需要喝完所有的 Agile kool-aid。
即使它没有做任何事情,也总会有一些东西在运行。只需很小的步骤即可向编译器添加内容。 (“频繁发布”。)选择一个非常微小的语言子集并首先实现。 (一开始只支持i = 0;
并从那里扩展内容。)
答案 9 :(得分:3)
也值得学习函数式编程。函数式语言非常适合编写 in 和 for 的编译器。我的学校的介绍编译器类包含函数式语言的介绍,并且所有作业都在OCaml中。
有趣的是你今天应该问这个,因为就在几天前我写了一个lambda演算翻译。 Lambda演算是所有函数式语言的祖父。它只有200行(在C ++中,包括错误报告,一些漂亮的打印,一些unicode),并且具有两阶段结构,具有可用于生成代码的中间格式。
不仅从小规模开始并构建最实用的编译器方法,它还鼓励良好的,模块化的组织实践。
答案 10 :(得分:3)
如果你想要一个令人兴奋的经验教你如何编写自己编译的编译器,你需要阅读 1964 中的这篇论文。
Val Schorre的META II a syntax-oriented compiler writing language。
在10页中,它告诉您如何编写编译器,如何编写元编译器,提供虚拟元编译器指令集以及使用元编译器构建的示例编译器。
我从60年代后期开始学习如何编写本文的编译器,并使用这些思想为几台小型机和微处理器构建类似C语言的语言。
如果纸张本身太多(它不是!)那么an online tutorial会引导你完成整个过程。
如果因为您不是ACM会员而从原始链接获取论文很尴尬,您会发现该教程无论如何都包含所有细节。 (恕我直言,价格方面,报纸本身也值得一试)。
10页!
答案 11 :(得分:2)
我不建议以C作为要实现的语言,也不建议使用任何编译器生成器或解析器生成器工具。 C是一种非常棘手的语言,而且构建自己的语言可能更好。它可以像C一样(例如,如果要指示函数体,请使用卷曲的支持,使用相同的类型名称,这样您就不必记住所谓的所有内容)。
制作编译器和解析器的工具很棒,但是有一个真正的简写符号问题。如果你不知道如何用longhand创建编译器,那么速记就会显得神秘,不必要限制等等。所以先编写自己的简单编译器,然后从那里继续。我还建议你不要开始生成实际的机器代码,除非你吃和呼吸汇编程序。使用VM创建自己的字节码解释器。
至于你应该使用什么语言来创建你的第一个编译器:只要语言相当完整,这并不重要。您将阅读输入文本,从中构建数据结构并写出二进制数据。因此,如果一种语言以任何方式使这些事情变得更容易,那么这就是支持它的一点。选择一门你熟悉的语言,这样你就可以专注于创建编译器,而不是学习语言。我通常使用OO语言,这使得语法树更容易编写,如果你熟悉它,函数式语言可能也会有效。
我在博客上写了很多关于编程语言的文章,所以你可以在这里找到一些有用的帖子:http://orangejuiceliberationfront.com/category/language-design/
特别是,http://orangejuiceliberationfront.com/how-to-write-a-compiler/是解析常见结构并从中生成有用内容的详细信息,以及http://orangejuiceliberationfront.com/generating-machine-code-at-runtime/,其中讨论了实际吐出英特尔指令的事情。
哦,关于编译器的引导:你可能无法从一开始就做到这一点。创建编译器涉及大量工作。因此,编写引导编译器不仅需要编写编译器(在其他语言中),一旦拥有它,您就必须使用自己编写第二版编译器。这是工作的两倍,加上现有和自举新编译器所需的调试,直到它完成所有工作。也就是说,一旦你有一个正常工作的编译器,它是测试其完整性的好方法。好吧,也许不是两倍的工作,而是更多的工作。我先取得轻松的成功,然后继续前进。
无论如何,玩得开心!