我看过很多关于一次通过和多次传递编译器的帖子,但我似乎没有明白这一点。
什么是一次通过编译器?
什么是多遍编译器?
它们之间的主要区别是什么?
任何人都可以用非常简单的语言提供它们之间的区别吗?
答案 0 :(得分:11)
术语 multi-pass 的起源来自计算机内存少得多的时候。编译器需要大量内存,而在小型内存机器中,这很难管理。
所以最初的想法是编译器在多次传递中运行。第一遍读取源代码,并完成基本任务,如语法检查,可能构建符号表,然后将其结果写入磁盘文件以进行第二次传递。每个连续的通过N将读取前一个通道的结果,并改变程序表示以使其进一步向机器代码移动,并写出其通过N + 1的结果以进行读取。重复此过程,直到最后一遍产生最终代码。许多编译器可以通过一些("多")传递;有很多知名的编译器,在很旧的机器上建立了几十个通道。
(这个概念适用于所谓的"两个传递汇编程序&#34 ;:第一次传递读取汇编程序源代码,语法检查,找出应该用于标签符号的位置值;第二次传递产生目标代码使用第一遍中指定的符号位置的知识。
内存现在变大了,将每个非常大的程序的源代码读入内存非常实用,让编译器在单个进程的内存中完成所有工作,并编写目标代码。你仍然可以在连接器的概念中看到一些类比的残余;它们将多个对象模块("第一遍")粘合到一个二进制文件中。
如果您在内部查看编译器,它们会分阶段运行。典型的阶段可能是:
* 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编译器会将这些步骤中的一个或多个捆绑到一个传递中。
回到现在,我们有很多记忆;不需要现代编译器将中间结果写入磁盘文件,因此所有这些阶段都发生在单个进程的内存中。您,编译器用户,看不到它们。所以你可以称之为现代编译器"一次通过"在这个词的原始意义上。由于现在没有人关心,这句话简直就是废弃了。
在任何情况下,编译器通常仍然是内部多阶段。 (有些编译器在单个阶段执行所有这些步骤;通常,他们不能进行大量的优化)。
答案 1 :(得分:7)
多次传递编译器是一种将编译分成多个传递的编译器,其中每次传递将继续前一次传递的结果。这样的传递可以包括解析,类型检查,中间代码生成,各种优化传递以及最终代码生成。因此,例如,解析器可能会创建一个解析树,然后类型检查器将检查类型错误,中间代码生成器可以转换为某种形式的中间代码。然后,优化过程将各自获取当前中间代码并将其转换为更优化的形式。最后,代码生成过程将采用优化的中间代码并从中生成目标代码。
在单通道编译器中,所有步骤都在一次通过中发生。因此,它会读取一些源代码,对其进行分析,对其进行检查,对其进行优化并为其生成代码,然后再转到下一段代码。
单通道编译器消耗更少的内存(因为它们不会将整个AST和/或中间代码保存在内存中)并且通常运行得更快。
某些语言(如C语言)可以在一次通过中进行编译,但其他语言则不是。例如,C中的函数需要在第一次使用之前声明,因此编译器在读取函数调用之前已经看到了函数的类型签名。然后,它可以使用该信息进行类型检查。在更现代的语言中,例如Java或C#,可以在定义之前调用函数(并且不存在前向声明)。这样的语言无法在一次传递中编译,因为类型检查器在遇到函数调用时可能对函数的签名一无所知,因此无法在没有首先处理整个文件的情况下对程序进行类型检查。
此外,多传递编译器可以使用更多种类的优化,因此即使对于可以在一次传递中编译的语言,现代编译器通常也会使用多次传递。
答案 2 :(得分:0)
编译器中的传递只是通过整个程序 一次从上到下
。通常一个传递将由几个阶段组成。一般来说,一个传递足以使词法和语法分析完成。这意味着通过遍历整个程序一次,我们可以检查语句是否在语法上是正确的。然后语法分析的输出是一个抽象语法树,它只是一个树形式的源代码(浓缩)。语义分析器必须通过AST来完成它的工作,并通过有效的方式进行整个计划再一次。 即完成语义分析需要两次传递(如果需要显式AST)。
答案 3 :(得分:0)
A"传递"读取源程序或前一个传递的输出,根据其阶段进行转换,并将输出写入中间文件,然后可以通过下一遍读取。
答案 4 :(得分:0)
单遍编译器是仅扫描程序一次并生成等效二进制程序的编译器。
另一方面,多遍编译器对源代码进行多次处理(多次遍历),并且每次以前生成的代码都作为输入使用。
根据上面的定义,单遍编译器与多遍编译器之间的区别很明显,除了这种多遍处理还使您的代码更加无错误,在单遍编译器中错误检测的机会更低。这就是为什么单遍编译器比多遍编译器更快的原因。