当前位置:首页 > 高考

高考结束, 选择计算机专业学生必看的编译器原理。打造C/C++编译器没那么容易

在我们得到答案之前,您需要先了解一些事情。编译器是一种执行非常严格定义的任务的软件。此外,自从 60 多年前首次构想编译器以来,就一直非常需要它们。这种漫长的演变有好有坏。好的部分是,今天它非常简单,任何程序员都可以拿起一本书并最终完成它。糟糕的是,现代高级语言的出现只能归功于编译器技术的巨大进步。

现在是实际的答案。先说点理论。编译器只不过是一个翻译器。它采用输入语言并输出具有相同语义的其他(目标)语言。它由三部分组成:

1.将输入语言解析并分解为中间表示 (IR) 的前端。

2.可能对给定程序进行必要转换的中间端,也可能不进行必要的转换。

3.将 IR 映射到目标语言的后端

为此,有多种编译器。我们将采用任何编程语言并输出另一种人类可读的编程语言的编译器称为源到源编译器;像 Python 到 C 之类的东西。更常见的是,编译器生成机器语言,然后汇编程序将转换为二进制代码。

不要将汇编器与通用编译器混淆。虽然也是编译器,但它是一种非常不同的编译器,独立于我们今天所说的编译器。这同样适用于完全可选的预处理器,并且只存在于 C/C++ 语言家族(甚至 Fortran 只支持 C 预处理器指令)。

正如您可能已经猜到的那样,前端是您开始的地方。理论上,它采用输入语言,去除所有语义冗余(即括号)并生成 IR 树。要实现这一点,您可以从词法分析器开始。词法分析器将字符序列映射到标记。令牌是语言结构的抽象表示,通常只是一个代码编号。例如假设 IF 为 21,变量为 15;然后将句子 if(a > b) 词法化为:21 40 15 62 15 41。41、62 和 40 分别是字符 (, > 和 ) 的 ascii 字符编号。

接下来,解析器会将这些标记序列映射为输入语言的有效句子。这是语法验证发生的地方。有很多方法可以构建解析器。通常解析器和词法分析器是一致构建的。对于像 C 这样语法简单的语言,您可以使用像 GNU Flex 和 Bishon 这样的生成器。对于像 C++ 这样的模糊语言,您需要使用自定义递归下降解析器。 C++ 递归下降解析器也可以处理 C,但反过来不行。几年前,GCC 就为 C 和 C++ 提供了一个这样的解析器。

解析器将输出 IR,并保证它描述了一个语法有效的程序。 IR 是语义实体的语言不可知树。每个主要编译器都有一个非常明确的 IR。 IR 已删除所有冗余,如括号和比较符号。它的目的是使遍历和转换代码尽可能简单和快速。我需要很多行来详细描述一个 IR,所以我建议阅读一本关于编译器工程主题的书。

如果您想构建所谓的优化编译器,则中端会接受 IR并对其应用某些优化。它以相同的 IR 树语言输出程序的新版本,希望比最初更快。非优化编译器不需要有中间件。

后端采用 [优化的] IR 将其映射到目标语言。目标语言定义了 IR 需要的抽象程度。例如,如果您正在构建一个 Cx-to-Cy 编译器——比如 Cilk C,其中常用 C 增加了新语法,并且输出是某种标准的 C(如 gnu C 或 C99)——IR 不必是与 C 的实际语义相去甚远。但是,如果您想一直使用机器语言,则 IR 需要接近机器需要的方式。最好阅读有关其 IR 的 GCC 文档。

机器语言后端的重要部分是指令选择和寄存器分配。第一个抽象的 IR 语言结构必须映射到目标架构提供的实际指令(因此您需要为每个目标架构提供不同的后端)。接下来,您需要将变量映射到某些寄存器。后端输出的内容与汇编语言非常接近,可以进行汇编

本文来自网络,不代表教育资讯立场,转载请注明出处。