我听说过引导语言的想法,即为该语言本身编写编译器/解释器。我想知道如何实现这一点,环顾四周,看到有人说这只能通过以下任一方法来完成

  • 用不同的语言编写初始编译器。
  • 在汇编中手动编码初始编译器,这似乎是第一个编译器的特例

对我来说,这些似乎都不是 引导 从某种意义上说,它们都需要外部支持。有没有办法用自己的语言实际编写编译器?

有帮助吗?

解决方案

有没有办法用自己的语言实际编写编译器?

有一些现有的语言来编写新的编译器。如果您正在编写一个新的 C++ 编译器,您只需用 C++ 编写它,然后首先使用现有的编译器进行编译。另一方面,如果您要为一种新语言创建编译器(我们称之为 Yazzleof),您需要首先用另一种语言编写新编译器。一般来说,这将是另一种编程语言,但并非必须如此。它可以是汇编代码,或者如果需要的话,可以是机器代码。

如果你 要为 Yazzleof 引导编译器,您通常不会最初为完整语言编写编译器。相反,您可以为 Yazzle-lite 编写一个编译器,Yazzleof 的最小可能子集(嗯,一个 相当小 至少子集)。然后在 Yazzle-lite 中,您将为完整语言编写一个编译器。(显然,这可以迭代发生,而不是一次跳转。)因为 Yazzle-lite 是 Yazzleof 的真子集,所以您现在拥有一个可以自行编译的编译器。

有一个 真的 关于从尽可能低的级别引导编译器(在现代机器上基本上是一个十六进制编辑器)的好文章,标题为 从无到有引导一个简单的编译器. 。可以在以下位置找到: https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html.

其他提示

您读过的解释是正确的。有一个关于这个的讨论 编译器:原理、技术和工具 (《龙书》):

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

超级有趣的一个 对此的讨论 是 Unix 的共同创造者 肯·汤普森图灵奖 演讲。

他首先说:

我要描述的是当编译器用自己的语言编写时出现的许多“先有鸡还是先有蛋”问题之一。在本教程中,我将使用 C 编译器中的一个特定示例。

并继续展示他如何编写一个 Unix C 编译器版本,该编译器始终允许他无需密码即可登录,因为 C 编译器会识别登录程序并添加特殊代码。

第二种模式针对 C 编译器。替换代码是第一阶段自我复制程序,它将两个特洛伊木马插入编译器中。这需要一个学习阶段,如第二阶段的示例所示。首先,我们使用普通的 C 编译器编译修改后的源代码以生成有错误的二进制文件。我们将此二进制文件安装为官方 C.我们现在可以从编译器的源代码中删除错误,并且新的二进制文件在编译时将重新插入错误。当然,登录命令将仍然存在错误,在任何地方的源代码中都找不到踪迹。

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

这是定义 引导:

一个简单系统激活一个具有相同目的的更复杂系统的过程。

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

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

唐纳德·E。高德纳 实际建成 网络 通过在其中编写编译器,然后将其手动编译为汇编代码或机器代码。

据我了解,第一 口齿不清 解释器是通过手动编译构造函数和令牌读取器来引导的。然后从源代码中读入解释器的其余部分。

你可以通过阅读麦卡锡的原始论文来亲自检查, 符号表达式的递归函数及其机器计算,第一部分.

另一种选择是为您的语言创建一个字节码机(或者使用现有的字节码机,如果它的功能不是很不寻常)并编写字节码编译器,无论是在字节码中,还是在您想要的语言中使用另一种中间体 - 例如解析器工具包将 AST 输出为 XML,然后使用 XSLT(或另一种模式匹配语言和基于树的表示)将 XML 编译为字节码。它不会消除对另一种语言的依赖,但可能意味着更多的引导工作最终会出现在最终系统中。

这是计算机科学版的先有鸡还是先有蛋的悖论。我想不出一种不用汇编语言或其他语言编写初始编译器的方法。如果可以做到的话,我应该 Lisp 也可以做到。

事实上,我认为 Lisp 几乎符合资格。查看 它的维基百科条目. 。根据这篇文章,Lisp eval 函数可以在 IBM 704 机器代码,完整的编译器(用 Lisp 本身编写)于 1962 年诞生 麻省理工学院.

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

否则它会如何工作?我认为从概念上讲根本不可能采取其他措施。

一些引导编译器或系统将源形式和对象形式保留在其存储库中:

  • 奥卡姆尔 是一种同时具有字节码解释器的语言(即Ocaml 字节码的编译器)和本机编译器(x86-64 或 ARM 等)汇编器)。它的 svn 存储库包含源代码(文件 */*.{ml,mli})和字节码(文件 boot/ocamlc) 编译器的形式。因此,当您构建它时,首先使用其字节码(以前版本的编译器)来编译自身。随后,新编译的字节码能够编译本机编译器。所以 Ocaml svn 存储库包含两者 *.ml[i] 源文件和 boot/ocamlc 字节码文件。

  • 编译器下载(使用 wget, ,因此您需要有效的互联网连接)其二进制文件的早期版本才能自行编译。

  • 熔化 是一种类似 Lisp 的定制和扩展语言 海湾合作委员会. 。它由引导翻译器翻译为 C++ 代码。翻译器生成的C++代码是分布式的,因此svn存储库包含两者 *.melt 源文件和 melt/generated/*.cc 翻译器的“目标”文件。

  • J·皮特拉特 特许会计师协会 人工智能系统完全是自我生成的。它可以作为数千个的集合提供 [A-Z]*.c 生成的文件(也带有生成的 dx.h 头文件),包含数千个 _[0-9]* 数据文件。

  • 几个Scheme编译器也被引导。计划48、鸡计划、...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top