编译自己的编译器(Bootstrapping)

时间:2018-04-05 19:15:24

标签: compiler-construction bootstrapping

我读到了关于bootstrapping但是还没有完成它。 我想解释一下我是如何看待它的,你要指出它是不是真的。 为了创建一个自编译它的编译器,它应该遵循以下步骤:

让我们有X和Y编程语言。

  1. 将编译器f从X langauge写入Y.对于Y中的每个代码A,编译器给出f(A)。
  2. 将编译器g从Y写入Y.因为编译器g是用Y语言编写的,然后编译器f可以编译它。因此,我们可以理解f(c)= g是从Y到Y的编译器。
  3. 您可以再次使用g编译C,然后g(C)= g - 编译器自行编译。
  4. 我觉得我的解释是缺乏重要的细节 如果有人能像我试图做的那样解释数学符号,我会很高兴。

2 个答案:

答案 0 :(得分:0)

在大多数情况下,您的步骤似乎是正确的,除非您似乎在混淆源语言和目标语言。我不确定这些只是错别字还是你真的很困惑。所以这是我对bootstrapping的正式描述的尝试,它接近你的,但在源,目标和实现语言之间有更明确的区别,还有更多的细节:

设X是源语言(即您新发明的语言),Y是目标语言(例如汇编或机器语言),Z是另一种语言,至少有一种实现已经存在。设T : X -> Y为翻译方案,将用X语言编写的有效程序翻译成用Y语言编写的等效程序。换句话说,对于用X编写的任何有效程序x,T(x)应生成一个用y编写的程序。 Y,其行为与x的定义行为等效。

现在我们要做的第一件事就是在编程语言Z中实现这个函数T.让我们调用这个实现C_0。由于Z的实现已经存在,我们现在可以开始编译X程序。这是你的第1步,除非你似乎在第二句中改变了X和Y.

在我们这样做之后,我们现在可以再次实现T,但这次是用语言X.所以我们编写了一个等同于C_1的程序C_0,但是用X而不是Z编写。我们仍然在从X到Y进行编译,但是我们在X中进行编译。我们现在可以使用C_0来应用T(C_1)并且我们得到一个(另一个)工作X编译器。除了我们仍将X翻译为Y之外,这与您的步骤类似。将X翻译成自身是没有意义的,因为那只是无所事事。将Y翻译成自身会更有意义,因为Y甚至不是我们的源语言。​​

我们现在也可以使用T(C_1)代替C_1来应用C_0,但此时这仅用于测试目的(确保编译器正常工作)。理想情况下,C_1(C_1)的结果应与C_0(C_1)的Y代码完全相同。一旦我们开始向X添加功能,我们可能只会在C_1中实现这些功能,所以此时我们要停止使用C_0,以便我们可以使用新功能。

答案 1 :(得分:0)

想象一下,您想要创建一种名为XYZPDQ的新语言。你知道C,所以你在C中编写了XYZPDQ的编译器。它有效,所以现在你可以用XYZPDQ语言编写代码并使用你在C中编写的编译器编译它,也许叫做XYZPDQc。

事实上,你非常喜欢你第二次编写编译器 - 但这次你用XYZPDQ语言编写它。您使用在C中编写的编译器(XYQPDQc程序)编译XYZPDQ编译器代码(用XYZPDQ本身编写)。结果是你可以运行的一个新程序,也许叫做XYZPDQc2。

现在您可以使用XYZPDQc2程序编译在XYZPDQ中编写的XYZPDQ编译器,因此编译器(实际上)编译自己。

此时:您已经使用了编译语言。