核心逻辑是基于上下文无关文法的产生式规则,在语法分析过程中结合语义动作动态生成四元式,并利用回填技术处理控制流语句中的未定跳转地址。具体实现如下:
-
四元式的结构:每个四元式形如
(op, arg1, arg2, result),其中:op是操作符(如+,<,j<,j,:=等);arg1,arg2是两个源操作数;result可以是目标变量或跳转目标标号。
-
从产生式到四元式的映射示例:
-
对于
E → a < b,语义动作为:E.code = [ ('<', 'a', 'b', 't1'), # t1 = (a < b) ('jnz', 't1', '', L1) # if t1 != 0 goto L1 ] E.truelist = [当前四元式编号 + 1] # 下一条可能跳转的位置 E.falselist = [当前四元式编号 + 2] # 否则跳转到这里?实际中常使用布尔短路与三地址码结合的方式,更常见的是直接生成条件跳转指令。
-
更典型的处理方式是将比较表达式用于控制流,例如在
if E then S中:- 先生成
E的代码,得到真链(truelist)和假链(falselist); - 将
S的起始地址回填到E.truelist指向的待填跳转位置; - 构造出口并处理后续跳转。
- 先生成
-
-
回填机制(Backpatching):
- 在遇到
while或if时,某些跳转目标尚未确定,因此先留空,记录这些待填位置的列表(如quad_list)。 - 当目标地址已知后,调用
backpatch(list, target)函数,将列表中所有待填四元式的跳转字段设为target。
- 在遇到
-
典型控制结构的四元式生成流程:
-
If-Then 语句:
if E then S步骤:
- 生成
E的代码,得到E.true和E.false链表; backpatch(E.true, nextquad()):让真分支跳转到S的开始;- 生成
S的代码; - 最终连接出口。
- 生成
-
While 循环:
while E do S步骤:
- 记录循环开始位置
L_begin = nextquad(); - 生成
E的代码; backpatch(E.true, S_start)进入循环体;- 生成
S的代码; - 添加无条件跳转回
L_begin; backpatch(E.false, nextquad())处理退出路径。
- 记录循环开始位置
-
-
最终四元式序列示例(简化版):
(1) (<, a, b, t1) (2) (jz, t1, _, 4) // 若 a<b 不成立,则跳转到 4 (3) (j, _, _, 6) // 成立则跳转到 then 分支 (4) ... // else 或后续代码
这种机制使得编译器可以在不预先知道目标地址的情况下构造控制流结构,通过延迟绑定地址实现灵活的中间代码生成。



被折叠的 条评论
为什么被折叠?



