摘要:
经过漫长的旅途,我们的编译期实现之旅终于到达了终点。感慨之余,就让我们最后一次共同回顾与展望这段遥远的旅程吧。 1. 回顾与展望 在编译器实现之旅的最初几章中,我们手写了一个针对CMM语言的词法分析器。实际上,我们使用的是一种被称为"手工编码的词法分析器"的实现方案。词法分析器实际上是具有通过程序进 阅读全文
摘要:
在上一章的旅程中,我们已经实现了函数调用的代码生成器分派函数,但在上一章的末尾,我们留下了三个问题: 我们需要为全局变量压栈 main函数需要在程序启动时被自动调用 我们需要实现一个链接器,以将所有的CALL伪指令转变为一条真正的CALL指令 所以,在这一章的旅程中,我们就将解决这三个遗留问题,为代 阅读全文
摘要:
在前面几个章节的旅程中,我们实现了一些各有特点的代码生成器分派函数,而在这一章的旅程中,我们将迎来整个代码生成器,乃至整个编译器实现之旅的重头戏:函数调用的实现。现在,就让我们开始吧。 1. 函数调用概观 函数调用是一个复杂的过程,从代码生成器层面看,其涉及到符号表以及多个与之相关的分派函数,此外, 阅读全文
摘要:
在上一章的旅程中,我们已经实现了if语句和while语句的代码生成器分派函数,而在这一章的旅程中,我们将要实现变量存取相关的代码生成器分派函数。要讨论变量存取,我们就需要对变量存取时的栈内存情况具有充分的了解。所以接下来,就让我们先来认识一下:在变量存取过程中所涉及到的栈内存情况吧。 1. 与变量存 阅读全文
摘要:
在上一章的旅程中,我们已经实现了表达式类代码生成器分派函数,而在这一章的旅程中,我们将要实现if语句和while语句的代码生成器分派函数。if语句和while语句是两种典型的带有跳转指令的语句。观察CMM指令集的实现不难发现,跳转指令,实际上就是通过强行修改IP的值,使得虚拟机下一次看到的CS[IP 阅读全文
摘要:
在上一章的旅程中,我们已经实现了一类最为简单的,只含有委托调用的分派函数,而在这一章的旅程中,我们将要实现表达式类节点的分派函数。表达式类节点,包括数字常量节点、算术运算类节点和比较运算类节点。在我们展开讨论之前,不知道你有没有从CMM指令集中注意到这样一件事:CMM指令集中的所有指令,如果只需要一 阅读全文
摘要:
从这一章的旅程开始,我们就要开始逐步的实现各个代码生成器分派函数了。首先,什么叫"较为顶层的代码生成器分派函数"?原来呀,这类分派函数都有一个共同特点:其自身不产生任何代码,而只是通过调用一些其他的分派函数,并合并这些函数所产生的代码,以实现自身功能。接下来,就让我们来看看这样的函数都有哪些,分别都 阅读全文
摘要:
从这一章开始,我们将进入代码生成器的世界。代码生成器是整个编译器中最复杂,但也最为精彩的部分。话不多说,就让我们开始吧。 1. 代码生成器概观 顾名思义,代码生成器就是用来生成代码的编译器组件。这里的"代码"一词,指的是我们已经实现了的CMM指令集中的指令。代码生成器通过解析抽象语法树,并利用符号表 阅读全文
摘要:
在这一章的旅程中,我们来实现虚拟机。CMM的虚拟机具有一套极为简单的指令集,和一个能够运行这套指令集的虚拟机。 需要注意的是:本章将不会对指令集以及虚拟机的设计和行为做过多的解释,而只是着重于展示。这是因为:在没有讲解代码生成器之前,这些解释是十分苍白的。 1. CMM虚拟机的指令集 CMM指令集一 阅读全文
摘要:
作为编译器后端的第一站,我们首先来实现语义分析器。 1. 语义分析器概观 正如上一章所说,语义分析器主要用于对抽象语法树进行语义层面的进一步检查,并生成符号表。我们也为符号表给出了一个"记录任何你想额外记录下的东西的表"这样的说了等于没说的定义。那么,CMM编译器的语义分析器到底需要做什么?其符号表 阅读全文
摘要:
在前面的旅程中,我们已经实现了整个的编译器前端。我们也知道,前端的目标是将源代码转变为抽象语法树,以供后端使用。从这一章开始,我们就要前往后端世界一探究竟了,现在,就让我们来看看编译器后端到底由哪些组件组成,其分别又是在做什么吧。 1. 编译器后端的结构组成 不同于编译器前端,编译器后端并不是一个严 阅读全文
摘要:
在上一章的旅程中,我们为实现语法分析器做了许多准备,我们讨论了如何表示语法,如何将记号流变为抽象语法树,如何消除左递归,如何得到First集合等问题。现在,就让我们来实现语法分析器吧。 1. CMM语言的语法及其做出选择的方案 这里,我们直接给出CMM语言的语法及其做出选择的方案,并已经消除了左递归 阅读全文
摘要:
在前面的旅程中,我们已经实现了词法分析器。词法分析器可将源代码转变为记号流,以供语法分析器使用。所以现在就让我们启程,朝着下一站——语法分析器出发吧。 1. 什么是语法 什么是语法呢?提到词法分析器,我们能够立即联想到一个个看得见摸得着的词;而提到语法分析器,又能联想到什么呢? 词法和语法的关系,就 阅读全文
摘要:
在上一章的旅程中,我们讨论了词法分析器的实现思路,我们也为词法分析器的实现做了许多准备工作。现在,就让我们来实现词法分析器吧。 1. 词法分析器的类定义 词法分析器的类定义如下: class __LexicalAnalyzer { // Friend friend class Core; publi 阅读全文
摘要:
在这一章的旅程中,我们将要为整个编译器的"前端中的前端":词法分析器的实现做好充足的准备。 1. 词法分析器概观 纵观编译器的输入:源代码,我们不难发现,源代码说白了也就是一个很长很长的字符串。而说到字符串,我们不难想到字符串的分割函数。这类分割函数以空格,或任意的什么字符或字符串作为分隔符,将一个 阅读全文
摘要:
在这一章的旅程中,我们将要深入编译器前端一探究竟。看看编译器前端到底由哪些组件组成,其分别又是在做什么。 1. 编译器前端的结构组成 似乎比我们想象的要简单,编译器前端仅由两个组件组成,词法分析器与语法分析器。请看下图: + + + + 源代码 -> | 词法分析器 | -> 记号流 -> | 语法 阅读全文
摘要:
编译器,近在咫尺却又远在天边。当我们写下任何非机器语言代码后,我们都需要借助编译器将这些代码变为通过计算机可运行的状态。但是,就是这样一个使用率极高的程序,我们对其却知之甚少。什么是编译器?编译器对我们的代码做了什么?又是怎么做的呢?如果你也怀有这些疑问,想要深入编译器内部一探究竟的话,那就随我一起 阅读全文