语法制导翻译及中间代码生成
1. 中缀式改后缀式(也叫逆波兰式)
可以用栈转换,也可以画棵树,然后写它的后序遍历。
2. 将赋值语句翻译为四元式序列
就,按计算顺序一个个写。
例:赋值语句X=A*(B+C)+D翻译成四元式序列
Ans:
(1) (+ , B , C , T1)
(2) (* , A , T1 , T2)
(3) (+ , T2 , D , T3)
(4) (= , T3 , _ , X)
3. 将布尔表达式翻译为四元式序列
布尔算符的优先级(从高到低):^ ∧ ∨
简化算法:
A∧B —— A?B:0
A∨B —— A?1:B
^A —— A?0:1
布尔式的四元式序列形式
(jnz, A, _ , p): 若A为真转第p个四元式
(jez, A, _ , p): 若A为假转第p个四元式
(j< ,A1,A2,p): 若的A1 < A2关系为真转第p个四元式(大于同理)
(j,_ , _ , p): 无条件转第p个四元式
拉链回填技术:由于每次规约时才能执行语义动作,所以布尔表达式所包含的跳转地址只能先空着,标记一下跳转到真出口还是假出口,等跳转地址确定后再一起填入。推荐视频:拉链回填技术 中南大学
例:将布尔表达式A∧(B∨(C∨D∧┐F))翻译成四元式序列,给出语法制导的翻译过程。
Ans:
1 (jnz , A , _ , 0) → 3
2 (j , _ , _ , 0 ) 假出口
3 (jnz , B , _ , 0 ) 真出口
4 (j , _ , _ , 0) →5
5 (jnz , C , _ , 0 ) 真出口 →3
6 (j , _ , _ ,0) →7
7 (jnz , D , _ , 0) →9
8 (j , _ , _ , 0 ) 假出口 →2
9 (jnz , F , _ , 0 ) 假出口 →8
10 (j , _ , _ , 0 ) 真出口 →5
循环同理:
将语句:
while A<C∧B>0 do
if A=1 then C : =C+1
else while A<=D do A : = A+2
翻译成四元式序列,给出语法制导的翻译过程。
1 ( j< , A , C , 0) →3
2 ( j , _ , _ , 0) →16
3 ( j> , B , 0 , 0 ) →5
4 ( j , _ , _ , 0 ) →2→16
5 ( j= , A , 1 , 0 ) →7
6 ( j , _ , _ , 0 ) →10
7 ( + , C , 1 , T1 )
8 ( := , T1 , _ , C )
9 ( j , _ , _ , 0 ) →1
10 ( j≤ , A , D , 0 ) →12
11 ( j , _ , _ , 0 ) →9→1
12 ( + , A , 2 , T2)
13 ( := , T2 , _ , A )
14 ( j , _ , _ , 10 )
15 ( j , _ , _ , 1)
目标代码生成
1. 将四元式翻译为类8086汇编:
四元式(+,A,B,T)对应的指令为:
MOV AX,A;
ADD AX,B;
MOV T,AX;
其余二元操作四元式的翻译与此类拟;
四元式(=,B,—,A)对应的指令为:
MOV AX,B;
MOV A,AX;
四元式(jnZ,A,—,P)对应的指令为:
MOV AX,A;
CMP AX,0; JNZ P’;
四元式(J,—,—,P)对应的指令为:
JMP P’;
四元式(Jrop,A,B,P)对应的指令为:
MOV AX,A;
CMP AX,B;
Jrop P’;
2. 结点重构优化代码顺序
把图画出来后先处理右结点再处理左结点。
3. 寄存器分配与基本块代码的生成
目标:尽可能减少访存,压缩指令条数,也就是一个寄存器最好能多次使用。
按照基本块划分代码:每连续执行的一段代码为一个基本块。
先判定每个变量未来会不会被引用:如果一个变量会在未来(不局限于基本块)被使用,那么说它是活跃的;如果一个变量在基本块中后面的语句使用,那么说它是被引用的。
如果一个结果被后面覆盖,比如a=b+c,下一条语句是a=c+d,那么规定第一条语句即不活跃,也不被引用。
用以下形式记录:
序号 | 四元式 | 结果 | 左变量(引用,活跃) | 右变量(引用,活跃) |
1 | (-,A, B, T ) | ... | ... | ... |
寄存器分配算法:
有表达式a=b+c,现在要给a分配一个寄存器。首先看b在哪个寄存器中,假设我们在r1中找到了b。如果b未来不会被引用,或者B和A用同一个标识符,也就是同一个变量,那么直接返回r1;
如果没有在寄存器中找到b,那么分配一个空寄存器;
如果没有空寄存器,那么挑一个存储内容在最远的将来才会被使用的寄存器。
现在挑好寄存器了,可以生成一条指令。生成完记得查看b和c会不会被引用,不会的话清空记录表,也就是记录哪个寄存器装了哪个变量,哪个变量被哪个寄存器装着这两张表。
例:(谢谢老师的答案)