编译原理第五、九章习题存档

Posted on 2023-02-15 15:13  Capterlliar  阅读(413)  评论(0编辑  收藏  举报

语法制导翻译及中间代码生成

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(CD∧┐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<CB>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 ) 216

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 ) 91

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会不会被引用,不会的话清空记录表,也就是记录哪个寄存器装了哪个变量,哪个变量被哪个寄存器装着这两张表。

例:(谢谢老师的答案)