编译原理--编译器的自举与移植

来源:互联网 发布:如何增加淘宝店铺流量 编辑:程序博客网 时间:2024/05/17 04:06

看的编译原理,发现挺好玩的东西:自举和移植。

有个著名的问题:Mommy, where do compilers come from?要解决这个问题,首先来看看T-Diagram。可以将编译器用一个T形图来表示:
 ---------
| S     T |
 ---   ---  
   | I |
    ---
其中,S表示Souce LanguageT表示Target LanguageI表示Implementation Language

根据这个图,可以得到两种组合:
1、 由I实现的将S翻译成A的编译器和将A翻译成T的编译器联合起来工作,可以实现S到T的编译。这不是很有意思的组合。
 ------------------
| S     A | A     T |
 ---   ------   ---   
   | I |    | I |
    ---      ---

2、由I实现的将S翻译成T的编译器(compiler C1),由H实现的将I翻译成K的编译器的组合(compiler C2)。这个组合比较有意思:可以用C2去编译C1(将其实现语言从I翻译成K),这样就得到由K实现的将S翻译成T的编译器(compiler C3):
 ---------                ---------
| S     T |              | S     T |
 ---   ----------  --->   ---   ---
   | I | I     K |          | K |
    -------   ---            ---
          | H |
           ---

这便是我们所感兴趣的:编译器的编译器。

而一个程序要在某台机器上运行时,其实现语言必须与相应的机器语言匹配。例如在x86平台上,能执行的程序只能是x86机器语言:
------------------
/    Program     /
 /              /
  -------------
  |     X86    |
  -------------
  |     X86    |
  -------------
让我们将T形图和上图联系起来看,以C为例(假定已有x86C编译器):
--------        --------       ---------
/ Hello /        / Hello /       / Hello /
 -----------------------        -------
 | C   | C    x86| x86  |  --->  | x86  |
 ---------    ----------        -------
          |x86|                 | x86  |
          ----                  -------

上图表示用C写的Hello程序可以在C“机器上运行,然而这不是我们想要的——x86机器上运行。于是使用实现语言为x86的编译器(其可执行代码)编译形成x86语言,这样就可以运行了。

根据上面的第2条(编译器的编译器)以及程序的执行,我们可以得出,要想得到在M机器上运行的S语言编译器,可以使用S语言来编写(用M语言也可以,然而太麻烦)。但还是需要用M语言写一个具有很小功能的S编译器,然后用其去编译加入了更多功能的编译器,然后用编译出来的更多功能的编译器去编译,这样就得到了最终需要的编译器,这便是自举。
 ---------                ---------
| S     M |              | S     M |
 ---   ----------  --->   ---   ---
   | S | S     M |          | M |
    -------   ---            ---
          | M |(微型S编译器)
           ---

用S编写S的编译器还有一个好处,那就是方便移植,并且能产生交叉编译器。假定要编译K机器语言的S编译器,只需要将目标语言替换成K,然后用已有的S语言编译器来编译:
 ---------           ---------
| S     K |         | S     K |
 ---   ---------- -> ---   ---
   | S | S     M |     | M |(运行在M机器上的编译器,即交叉编译器)
    -------   ---       ---
          | M |
           ---
有了交叉编译器,就可以编译在K上运行的S编译器了:
 ---------           ---------
| S     K |         | S     K |
 ---   ---------- -> ---   ---
   | S | S     K |     | K |
    -------   ---       ---
          | M |
           ---