我见过很多关于、一通和多通编译器的文章,但我似乎不明白。
发布于 2016-02-27 19:06:35
“多通”一词的起源来自于计算机内存少得多的时候。编译器需要大量的内存,而在小型内存机器中,这是很难管理的。
所以最初的想法是一个编译器在多个过程中运行。第一遍读取源代码,并执行基本任务,如语法检查、可能构建符号表,然后将其结果写入磁盘文件以供第二次使用。每次连续传递N将读取前一次传递的结果,并更改程序表示以将其进一步移动到机器代码,并写出其结果以供pass N+1读取。此过程会重复,直到最后一次传递生成最终代码。许多编译器可以通过几个(“多个”)通过;有许多著名的编译器,几十个在真正老旧的机器上构建的通行证。
(这一概念也适用于所谓的“两遍汇编程序”:第一遍读取汇编程序源代码,语法检查,确定标签符号应该使用的位置值;第二遍使用第一遍中分配的符号位置的知识生成目标代码)。
内存现在更大了,它非常实用,可以将源代码读取到内存中,让编译器在单个进程的内存中完成所有的工作,并编写目标代码。您仍然可以在链接器的概念中看到类似的残余;它们将多个对象模块(“第一次传递”)粘合到一个二进制文件中。
如果您在内部查看编译器,它们将分阶段运行。典型的阶段可能是:
* 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中.
回到现在,我们有大量的内存;现代编译器不需要将中间结果写入磁盘文件,因此所有这些阶段都发生在单个进程的内存中。你,编译器用户,没有看到他们。因此,你可以把现代编译器称为“一次通过”这个词的原意。既然现在没有人关心,这句话就被完全废弃了。
无论如何,编译器在内部仍然是多阶段的.(有些编译器在单个阶段中执行所有这些步骤;通常,它们不能进行大量的优化)。
发布于 2016-02-27 20:04:44
多通编译器是将编译分离为多个传递的编译器,每次传递都将与上一次传递的结果一起继续。这些传递可以包括解析、类型检查、中间代码生成、各种优化传递以及最后的代码生成。例如,解析器可能创建一个解析树,然后类型检查器将检查类型错误,中间代码生成器可以转换成某种形式的中间代码。然后,每个优化传递都将获取当前的中间代码,并将其转换为一个更优化的形式。最后,代码生成传递将采用优化的中间代码并从中生成目标代码。
在一个单程编译器中,所有的步骤都发生在一次传递中。所以它读取了一些源代码,分析了它,对它进行了类型选择,优化了它,并为它生成了代码,然后才会转到下一段代码。
单程编译器消耗更少的内存(因为它们不保存内存中的整个AST和/或中间代码),并且通常运行得更快。
有些语言,比如C语言,被设计成可以在一次传递中编译,而另一些语言则不是。例如,C中的函数需要在第一次使用之前声明,因此编译器在读取函数调用之前已经看到了函数的类型签名。然后,它可以使用该信息进行类型检查。例如,在更现代的语言(如Java或C# )中,函数可以在定义之前被调用(并且不存在前向声明)。这样的语言不能一次编译,因为类型检查程序在遇到函数调用时可能对函数的签名一无所知,因此不可能在不首先处理整个文件的情况下对程序进行排版。
此外,多通道编译器可以使用更多的优化,因此即使对于可以在一次传递中编译的语言,现代编译器也通常使用多次传递。
发布于 2017-05-12 08:24:03
https://stackoverflow.com/questions/35673818
复制相似问题