直观地说,Foo语言的编译器本身似乎不能用Foo来编写。更具体地说,Foo语言的第一个编译器不能用Foo编写,但任何后续的编译器都可以为Foo编写。
但这是真的吗?我隐约记得读过一种语言,它的第一个编译器是用“自身”编写的。这可能吗?如果可能,如何实现?
直观地说,Foo语言的编译器本身似乎不能用Foo来编写。更具体地说,Foo语言的第一个编译器不能用Foo编写,但任何后续的编译器都可以为Foo编写。
但这是真的吗?我隐约记得读过一种语言,它的第一个编译器是用“自身”编写的。这可能吗?如果可能,如何实现?
当前回答
在之前的答案上增加好奇心。
这里引用了Linux from Scratch手册中的一段话,说明了从源代码开始构建GCC编译器的步骤。(Linux From Scratch是一种安装Linux的方式,它与安装发行版完全不同,因为你必须编译目标系统的每一个二进制文件。)
做引导 “bootstrap”目标不只是编译GCC,而是多次编译它。它使用在第一个编译的程序 进行第二次编译,然后再次进行第三次。然后比较第二和第三个 编译以确保它能够完美地复制自己。这也意味着它是正确编译的。
使用“bootstrap”目标的动机是,用于构建目标系统工具链的编译器可能与目标编译器的版本不完全相同。在目标系统中,以这种方式进行操作一定会获得一个可以编译自身的编译器。
其他回答
在之前的答案上增加好奇心。
这里引用了Linux from Scratch手册中的一段话,说明了从源代码开始构建GCC编译器的步骤。(Linux From Scratch是一种安装Linux的方式,它与安装发行版完全不同,因为你必须编译目标系统的每一个二进制文件。)
做引导 “bootstrap”目标不只是编译GCC,而是多次编译它。它使用在第一个编译的程序 进行第二次编译,然后再次进行第三次。然后比较第二和第三个 编译以确保它能够完美地复制自己。这也意味着它是正确编译的。
使用“bootstrap”目标的动机是,用于构建目标系统工具链的编译器可能与目标编译器的版本不完全相同。在目标系统中,以这种方式进行操作一定会获得一个可以编译自身的编译器。
你不能自己编写编译器,因为你没有任何东西来编译你的初始源代码。有两种方法可以解决这个问题。
最不受欢迎的是下面这些。你用汇编器(恶心)为语言的最小集合写一个最小的编译器,然后用那个编译器来实现语言的额外功能。逐步构建,直到拥有一个具有所有语言特性的编译器。这是一个痛苦的过程,通常只有在你别无选择的时候才会做。
首选的方法是使用交叉编译器。您可以在不同的机器上更改现有编译器的后端,以创建在目标机器上运行的输出。然后你就有了一个完美的完整编译器,并在目标机器上运行。这方面最流行的是C语言,因为现有的很多编译器都有可插拔的后端,可以进行交换。
一个鲜为人知的事实是,GNU c++编译器有一个只使用C子集的实现。原因是,通常很容易为新的目标机器找到一个C编译器,然后允许您从它构建完整的GNU c++编译器。现在,您已经在目标计算机上安装了c++编译器。
实际上,大多数编译器都是用它们所编译的语言编写的,原因如上所述。
第一个引导编译器通常是用C、c++或Assembly编写的。
GNAT是GNU Ada编译器,需要完全构建Ada编译器。当将其移植到一个没有现成的GNAT二进制文件的平台时,这可能是一个麻烦。
也许你可以用BNF来描述BNF。