引导仍然需要外部的支持

我听说过引导一种语言的想法,也就是说为这个语言编写一个编译器/解释器。 我想知道如何做到这一点,并看看周围,看到有人说,这只能由两者之一

  • 用不同的语言编写初始编译器。
  • 在Assembly中手工编写一个初始编译器,这看起来像是第一个特例

对我而言,这两者似乎都不是从某种意义上来说是引导语言,因为它们都需要外界的支持。 有没有一种方法可以用自己的语言编写一个编译器?

有没有一种方法可以用自己的语言编写一个编译器?

必须有一些现有的语言来编写你的新编译器。如果你正在编写一个新的C ++编译器,那么你只需要用C ++编写它,并且先用现有的编译器编译它。 另一方面,如果你正在为一种新语言创build一个编译器,那么我们把它叫做Yazzleof,你需要先用另一种语言编写新的编译器。 一般来说,这将是另一种编程语言,但不一定是。 它可以是组装,或者如果有必要,可以是机器代码。

如果您打算为Yazzleof引导一个编译器,那么通常不会为最初的完整语言编写一个编译器。 相反,你会为Yazzle-lite写一个编译器,它是Yazzleof的最小可能子集(至less是一个很小的子集)。 然后在Yazzle-lite中,您将编写一个完整语言的编译器。 (显然这可以迭代地发生,而不是一次跳跃。)因为Yazzle-lite是Yazzleof的一个真正的子集,所以你现在有了一个可以自己编译的编译器。

关于从最低级别(现代机器基本上是一个hex编辑器)引导编译器的一个很好的写法,题为从一无所有引导一个简单的编译器 。 它可以在https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.htmlfind。;

你读过的解释是正确的。 在编译器:原理,技术和工具 (龙书)中讨论了这个问题:

  • 用语言Y编写语言X的编译器C1
  • 使用编译器C1在语言X中为语言X编写编译器C2
  • 现在C2是一个完全自我托pipe的环境。

Unix的共同创始人肯·汤普森 ( Ken Thompson )的图灵奖 ( Turing Award)讲座是一个超级有趣的讨论 。

他开始与:

我将要描述的是编译器用自己的语言编写时出现的许多“鸡与蛋”问题之一。 在这个简单的例子中,我将使用C编译器的一个具体例子。

并继续说明他是如何编写一个版本的Unix C编译器,总是允许他不用密码login,因为C编译器会识别login程序并添加特殊代码。

第二种模式是针对C编译器的。 replace代码是一个阶段I自我复制程序,将两个木马插入到编译器中。 这需要像第二阶段的例子那样进行学习阶段。 首先,我们用普通的C编译器编译修改的源代码,以产生一个bug的二进制文件。 我们安装这个二进制文件作为官方C.我们现在可以从编译器的源代码删除错误,新的二进制文件将重新插入错误,每当它编译。 当然,login命令在任何地方都不会有踪迹。

我听说的方式是用另一种语言编写一个非常有限的编译器,然后用它编译一个更复杂的版本,用新语言编写。 然后可以使用第二个版本来编译自己,以及下一个版本。 每次编译时使用最后一个版本。

这是自举的定义:

一个简单的系统激活一个更复杂的系统,以达到相同目的的过程。

编辑: 关于编译器bootstrapping维基百科的文章涵盖了比我更好的概念。

查看播客软件工程电台第61集 (2007-07-06),讨论GCC编译器的内部,以及GCC的引导过程。

Donald E. Knuth实际上通过编译器编写了WEB ,然后将其编译成汇编或机器代码。

据我了解,第一个Lisp解释器是通过手工编译构造函数和令牌读取器来引导的。 其余的翻译从源头上读入。

你可以通过阅读原始的McCarthy论文, 符号expression式的recursion函数和机器计算,第一部分来检查自己

另一种方法是为你的语言创build一个字节码机器(或者如果它的function不是非常的话,就使用现有的机器),然后用字节码或者用你想要的语言编写一个编译器,parsing器工具包,它将AST输出为XML,然后使用XSLT(或其他模式匹配语言和基于树的表示forms)将XML编译为字节码。 它不会消除对另一种语言的依赖,但可能意味着更多的引导工作在最终系统中结束。

这是鸡与鸡矛盾的计算机科学版本。 我想不出用汇编语言或其他语言编写初始编译器的方法。 如果可以这样做,我应该Lisp可以做到的。

实际上,我认为Lisp几乎是合格的。 看看它的维基百科条目 。 根据这篇文章,Lisp eval函数可以在机器代码的IBM 704上实现,并在1962年在麻省理工学院出版了一个完整的编译器(用Lisp编写)。

引导一种我能想到的语言( C , PyPy )的每个例子都是在有一个工作编译器之后完成的。 你必须从某个地方开始,重新实现一种语言,首先需要用另一种语言编写一个编译器。

还有什么其他的工作? 我认为甚至在概念上是不可能的。

一些引导的编译器或系统将源表单和对象表单保存在其存储库中:

  • ocaml是一种既有字节码解释器(即编译器到Ocaml字节码)又有本地编译器(到x86-64或ARM等…汇编器)的语言。 它的svn仓库包含编译器的源代码(文件*/*.{ml,mli} )和字节码(文件boot/ocamlc )。 所以当你build立它时,首先使用它的字节码(编译器的以前版本)来编译它自己。 后来新编译的字节码能够编译本地编译器。 所以Ocaml svn仓库包含*.ml[i]源文件和boot/ocamlc字节码文件。

  • 生锈的编译器下载(使用wget ,所以你需要一个可用的互联网连接)的二进制文件的以前的版本来编译自己。

  • MELT是一种Lisp类语言,用于定制和扩展GCC 。 它被自举的翻译器翻译成C ++代码。 译码器生成的C ++代码是分布式的,所以svn仓库包含翻译器的*.melt源文件和melt/generated/*.cc *.melt “对象”文件。

  • J.Pitrat的CAIA人工智能系统完全是自发的。 它可以作为数千个[AZ]*.c生成的文件(还有一个生成的dx.h头文件)的数千个_[0-9]*数据文件集合的集合。

  • 几个Scheme编译器也被引导。 Scheme48,鸡计划,…

我对这样的事情并不是很有经验,但是我认为最初的编译器必须用另一种语言编写。 我相当确定,引导编译器的“bootstrapping”只是简单地用一种语言编写一个编译器来编译,而不是用编译的语言编写第一个语言的编译器。