编译原理习题Ch2.8


📘 Exercise 2.8.1

❖ Problem(题目)

For-statements in C and Java have the form:

1
for ( expr1 ; expr2 ; expr3 ) stmt

其中:

  • expr1:循环开始前执行一次(初始化)
  • expr2:每次迭代前的判断条件,若为 0 则退出
  • expr3:每轮循环末尾执行(通常是自增)
  • stmt:循环体

等价于:

1
2
3
4
5
expr1;
while (expr2) {
stmt;
expr3;
}

任务:定义一个类 For 来表示 for 语句,类似于图 2.43 中的 If 类。


✅ Answer(答案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class For extends Stmt {
Expr E1; // 初始化表达式
Expr E2; // 判断条件
Expr E3; // 每次循环末执行
Stmt S; // 循环体

public For(Expr expr1, Expr expr2, Expr expr3, Stmt stmt){
E1 = expr1;
E2 = expr2;
E3 = expr3;
S = stmt;
}

public void gen(){
E1.gen(); // 执行初始化
Label start = new Label();
Label end = new Label();
emit(start + ":"); // 循环开始位置
emit("ifFalse " + E2.rvalue().toString() + " goto " + end); // 判断条件
S.gen(); // 执行循环体
E3.gen(); // 执行增量表达式
emit("goto " + start); // 返回循环开头
emit(end + ":"); // 循环结束
}
}

🧠 Explanation(解释)

这个类表示 for 循环的语义为:

  1. E1 是开始前执行的表达式(初始化变量)。
  2. start 是循环体的开始标签。
  3. E2 是判断是否继续循环,如果 false(例如为 0)就跳出循环。
  4. 执行语句 S,然后再执行 E3(如 i++),再跳回 start
  5. 如果条件失败,就跳转到 end,即循环结束。

📘 Exercise 2.8.2

❖ Problem(题目)

C 语言没有布尔类型。演示 C 编译器如何将 if 语句转换成三地址代码(three-address code)。


✅ Answer(答案)

默认 if 的翻译使用:

1
emit("ifFalse " + E.rvalue().toString() + " goto " + after);

但 C 没有布尔类型,判断条件为 0(假)或非 0(真),所以可以改成:

1
emit("ifEqual " + E.rvalue().toString() + " 0 goto " + after);

或者简化为:

1
emit("ifEqualZero " + E.rvalue().toString() + " goto " + after);

🧠 Explanation(解释)

  • 在 Java 或其他语言中,有布尔类型(如 true, false),可以直接判断 if (cond) {...}
  • 但在 C 中,条件 cond 是一个整数表达式,0 表示假,非 0 表示真。
  • 所以 C 的 if (E) 实际上是:“如果 E == 0,则跳过”
  • 因此,if 语句的生成必须显式地和 0 比较,使用 ifEqualifEqualZero 等三地址跳转语句。