【发布时间】:2016-02-27 18:37:32
【问题描述】:
我看过很多关于 one pass 和 multi pass 编译器的帖子,但我似乎不明白这一点。
什么是一次性编译器?
什么是多通道编译器?
它们之间的主要区别是什么?
谁能用非常简单的语言提供它们之间的区别?
【问题讨论】:
我看过很多关于 one pass 和 multi pass 编译器的帖子,但我似乎不明白这一点。
什么是一次性编译器?
什么是多通道编译器?
它们之间的主要区别是什么?
谁能用非常简单的语言提供它们之间的区别?
【问题讨论】:
multi-pass 一词的起源来自计算机内存少得多的时代。编译器需要大量内存,而在内存小的机器中,这很难管理。
所以最初的想法是编译器多次运行。第一遍读取源代码,并完成语法检查等基本任务,可能构建符号表,然后将其结果写入磁盘文件以进行第二遍。每次连续的 N 轮将读取前一轮的结果,并更改程序表示以使其越来越接近机器代码,并写出其结果以供 N+1 轮读取。重复这个过程,直到最后一遍产生最终代码。许多编译器可以通过几次(“多”)通过;有著名的编译器在非常旧的机器上构建了几十个通道。
(同样的概念适用于所谓的“两遍汇编器”:第一遍读取汇编器源代码,语法检查,找出标签符号应该使用哪些位置值;第二遍使用知识生成目标代码在第一遍中分配的符号位置)。
内存现在变大了,将每个非常大的程序的源代码读入内存,让编译器在单个进程的内存中完成所有工作,然后编写目标代码,这是非常实用的。您仍然可以在 linkers 的概念中看到一些类似的残余;他们将多个对象模块(“第一遍”)粘合到一个二进制文件中。
如果您在内部查看编译器,它们会分阶段运行。典型的阶段可能是:
* Parse and syntax check
* Build symbol tables
* Perform semantic sanity check
* Determine control flow
* Determine data flow
* Generate some "intermediate" language (representing abstract instructions)
* Optimize the intermediate language
* Generate machine code from the optimized language
特定编译器对阶段所做的工作因编译器而异。这些步骤中的每一个都使程序表示更接近最终的机器代码。 N-pass 编译器会将这些步骤中的一个或多个捆绑到一个 pass 中。
回到现在,我们有很多记忆;不需要现代编译器将中间结果写入磁盘文件,因此所有这些阶段都发生在单个进程的内存中。您,编译器用户,看不到它们。因此,您可以将现代编译器称为“一次性”一词的原始含义。由于现在没有人关心,这个短语已经被废弃了。
无论如何,编译器在内部通常仍然是多阶段的。 (有些编译器在一个阶段完成所有这些步骤;通常,他们不能做很多优化)。
【讨论】:
多遍编译器是将编译分成多遍的编译器,其中每一遍都将继续前一遍的结果。这样的传递可能包括解析、类型检查、中间代码生成、各种优化传递和最后的代码生成。例如,解析器可能会创建一个解析树,然后类型检查器将检查类型错误,中间代码生成器可以将其转换为某种形式的中间代码。然后,优化通道将分别采用当前的中间代码并将其转换为更优化的形式。最后,代码生成过程将采用优化的中间代码并从中生成目标代码。
在单遍编译器中,所有步骤都发生在一次遍中。因此它会读取一些源代码,对其进行分析、类型检查、优化并为其生成代码,然后才继续执行下一段代码。
单程编译器消耗更少的内存(因为它们不会将整个 AST 和/或中间代码保存在内存中)并且通常运行得更快。
某些语言(如 C)被设计为可一次性编译,但其他语言则不然。例如,C 中的函数需要在第一次使用之前声明,因此编译器在读取函数调用之前已经看到了函数的类型签名。然后它可以使用该信息进行类型检查。在更现代的语言中,例如 Java 或 C#,可以在定义函数之前调用函数(并且不存在前向声明)。此类语言无法一次性编译,因为类型检查器在遇到函数调用时可能对函数的签名一无所知,因此在未首先处理整个文件的情况下无法对程序进行类型检查。
此外,多通道编译器可以利用更多种类的优化,因此即使对于可以单通道编译的语言,现代编译器通常也使用多通道。
【讨论】:
a multi pass separates compilation in multiple passes 而不是 phases ?这不是更有意义吗?
一次性编译器是只对每个编译单元的源代码进行一次传递的编译器。多遍编译器是一种对程序的源代码或抽象语法树进行多次处理的编译器。
单遍编译器比多遍编译器更快
单遍编译器的遍数范围有限,而多遍编译器的遍数范围很广。
多通道编译器有时称为宽编译器,而单通道编译器有时称为窄编译器。
【讨论】:
编译器中的传递只不过是遍历整个程序 从上到下一次
. 通常一个 pass 会包含几个阶段。一般来说一个 pass 就足以完成词法和语法分析。这意味着通过一次遍历整个程序,我们可以检查语句在语法上是否正确。然后语法分析的输出是一个抽象语法树,它只不过是树形式的源代码(压缩)。语义分析器必须通过 AST 来完成它的工作,并且有效地通过整个程序再一次。 也就是说,要完成语义分析,需要两次通过。(如果需要显式 AST)。
【讨论】:
一个“pass”读取源程序或前一个pass的输出,根据其阶段进行转换并将输出写入一个中间文件,然后可以通过下一个pass读取。
【讨论】:
单遍编译器是只扫描程序一次并生成等效的二进制程序的编译器。
另一方面,多通道编译器会多次处理源代码(多通道),每次之前生成的代码都作为输入。
从上面的定义来看,single pass 和 multi pass 编译器的区别已经很清楚了。除了这个 multi pass 让你的代码更无错误之外,在 single pass 编译器中错误检测的机会更低。一个 multi pass 编译器需要很多时间。这就是为什么单通道编译器比多通道编译器快的原因。
【讨论】: