← 前一天目录后一天 →

每日科普 · 2026-10-22 周四

考研 408 × 求职面试

知识点 · 编译原理 · 进阶

单遍编译与多遍编译(Pass)的组织方式

编译中的一遍(pass)通常指对源程序或某种中间表示从头到尾完整处理一次。 1. 单遍编译:词法、语法、语义检查与代码生成尽量在一次扫描中完成,边读边查符号表、边生成目标代码;遇到前向引用常用回填,结构紧凑、内存省,但优化受限,语言和语法制约多。 2. 多遍编译:把分析、优化、代码生成拆成若干遍,每遍完成一类任务并输出中间表示,供下一遍读取;便于模块化、错误定位和全局优化,但需要保存IR,可能多次遍历,时间与空间开销更大。 3. 组织要点:遍的划分不是越细越好,常把兼容阶段合并;核心权衡是内存占用、编译速度、优化能力和实现复杂度。

每日一题 · 编译原理

单遍编译与多遍编译(Pass)的组织方式

关于单遍编译与多遍编译,下列说法正确的是( )。 A. 单遍编译一定比多遍编译生成的代码质量高 B. 多遍编译通常需要保存中间表示,便于分阶段优化 C. 阶段数等于源程序被扫描的次数,越多越好 D. 单遍编译无法使用符号表

解析

选B。多遍编译把任务分到多个pass,各遍通过中间表示衔接,因而便于做全局分析、优化和模块化;但会增加存储与遍历开销。A错,单遍通常优化空间较小;C错,阶段划分与扫描次数不必然相等,也非越多越好;D错,单遍也可边扫描边维护符号表并回填前向引用。

面试小贴士 · 编译原理

单遍编译与多遍编译(Pass)的组织方式

面试常问单遍/多遍区别及编译器为何多遍。回答抓住:是否保存IR、能否前向引用/回填、优化能力、时间空间与实现复杂度。易错点是把pass数等同扫描次数,或认为多遍一定更优。

代码实现 · C

代码示例

#include <stdio.h>
#include <string.h>

typedef struct { int is_decl; const char *name; int val; } Item;
typedef struct { const char *name; int val; } Sym;

int main(void) {
    Item prog[] = { {0, "y", 0}, {1, "x", 10}, {0, "x", 0}, {1, "y", 20} };
    int n = (int)(sizeof(prog) / sizeof(prog[0]));
    Sym syms[4];
    int m = 0;

    // Pass 1:先收集所有声明,建立符号表
    for (int i = 0; i < n; i++) {
        if (prog[i].is_decl) {
            syms[m].name = prog[i].name;
            syms[m].val = prog[i].val;
            m++;
        }
    }

    // Pass 2:再解析使用,因此可处理前向引用
    for (int i = 0; i < n; i++) {
        if (prog[i].is_decl) continue;
        int ok = 0;
        for (int j = 0; j < m; j++) {
            if (strcmp(prog[i].name, syms[j].name) == 0) {
                printf("use %s = %d\n", prog[i].name, syms[j].val);
                ok = 1;
                break;
            }
        }
        if (!ok) printf("use %s: undefined\n", prog[i].name);
    }
    return 0;
}
← 前一天目录后一天 →