直观地说,Foo语言的编译器本身似乎不能用Foo来编写。更具体地说,Foo语言的第一个编译器不能用Foo编写,但任何后续的编译器都可以为Foo编写。

但这是真的吗?我隐约记得读过一种语言,它的第一个编译器是用“自身”编写的。这可能吗?如果可能,如何实现?


当前回答

也许你可以用BNF来描述BNF。

其他回答

这就是所谓的“自我引导”。你必须首先用其他语言(通常是Java或C)为你的语言构建一个编译器(或解释器)。一旦完成了这一步,你就可以用语言Foo编写一个新版本的编译器。您使用第一个引导编译器来编译编译器,然后使用这个编译器来编译其他所有内容(包括自身的未来版本)。

大多数语言确实是以这种方式创建的,部分原因是语言设计者喜欢使用他们正在创建的语言,也因为非平凡的编译器通常可以作为语言“完整”程度的有用基准。

Scala就是一个例子。它的第一个编译器是用Martin Odersky的实验语言Pizza创建的。从2.0版开始,编译器完全用Scala重新编写。从那时起,旧的Pizza编译器可以完全被丢弃,因为新的Scala编译器可以用于将来的迭代中编译自己。

是的,你可以用一种语言编写编译器。不,你不需要第一个编译器来引导该语言。

您需要引导的是该语言的实现。它可以是编译器,也可以是解释器。

历史上,语言通常被认为是解释语言或编译语言。解释器只为前者编写,编译器只为后者编写。所以通常,如果要为一种语言编写编译器,第一个编译器会用其他语言编写以引导它,然后,可选地,编译器会为主题语言重新编写。但是用另一种语言编写解释器也是一种选择。

这不仅仅是理论上的。我自己也在做这件事。我正在为自己开发的语言Salmon编写编译器。我首先用C创建了一个Salmon编译器,现在我正在用Salmon编写编译器,所以我可以让Salmon编译器工作,而不需要用任何其他语言为Salmon编写编译器。

这是一个dump(实际上很难搜索的话题):

闲聊 C

这也是PyPy和Rubinius的想法:

(我想这也适用于Forth,但我对Forth一无所知。)

也许你可以用BNF来描述BNF。

在之前的答案上增加好奇心。

这里引用了Linux from Scratch手册中的一段话,说明了从源代码开始构建GCC编译器的步骤。(Linux From Scratch是一种安装Linux的方式,它与安装发行版完全不同,因为你必须编译目标系统的每一个二进制文件。)

做引导 “bootstrap”目标不只是编译GCC,而是多次编译它。它使用在第一个编译的程序 进行第二次编译,然后再次进行第三次。然后比较第二和第三个 编译以确保它能够完美地复制自己。这也意味着它是正确编译的。

使用“bootstrap”目标的动机是,用于构建目标系统工具链的编译器可能与目标编译器的版本不完全相同。在目标系统中,以这种方式进行操作一定会获得一个可以编译自身的编译器。