大家好,欢迎来到IT知识分享网。
第六章 中间代码生成
1、后缀式
2、图表示法
抽象语法树、DAG图
3、三地址代码
三元式、四元式、间接三元式
后缀式
6.1 声明语句的翻译
6.1.1 类型表达式
各类语句的翻译,包括声明语句、控制语句等。声明语句主要是收集类型等信息。
类型表达式也是一种结构,类型表达式包括以下几种情况:
- 基本类型是类型表达式
integer 、real 、char 、boolean 、type_error (出错类型) 、void (无类型)
- 可以为类型表达式命名,类型名也是类型表达式
- 将类型构造符(type constructor)作用于类型表达式可以构成新的类型表达式
数组构造符array ,若T是类型表达式,则array( I, T)是类型表达式( I是一个整数)。
类型 类型表达式 int[3] array(3,int) int[2][3] array(2, array(3,int) )
指针构造符pointer,若T是类型表达式,则pointer ( T ) 是类型表达式,它表示一个指针类型。
笛卡尔乘积构造符x,若T1和T2是类型表达式,则笛卡尔乘积T1xT2 是类型表达式。
函数构造符→ ,若T1、T2、…、Tn 和R是类型表达式,则T1xT2x…xTn→R是类型表达式
记录构造符record ,若有标识符N1、N2、…、Nn 与类型表达式T1 、T2、…、Tn ,则 record( (N1 x T1)x(N2xT2)x…x(NnxTn ))是一个类型表达式。
例如,下列C语言程序片段中
structstype { char[8] name; intscore; }; stype[50] table; stype* p;
和stype绑定的类型表达式 :
record ( (name x array(8, char)) x (score x integer) )
和table绑定的类型表达式 :
array (50, stype)
和p绑定的类型表达式 :
pointer (stype)
6.1.2 声明语句的翻译
对于声明语句,语义分析的主要任务就是收集标识符的类型等属性信息,并为每一个名字分配一个相对地址,从类型表达式可以知道该类型在运行时刻所需的存储单元数量 称为类型的宽度(width),在编译时刻,可以使用类型的宽度为每一个名字分配一个相对地址,名字的类型和相对地址信息保存在相应的符号表记录中。
声明语句的文法动作中enter( name, type, offset):在符号表中为 名字name创建记录,将name的类型设置 为type,相对地址设置为offset。
其中t, w用于暂时存储当前变量的类型和宽度信息。
B表示基本类型
C便是数组类型
T表示表达式类型
D表示声明序列
P表示程序
例1:realx; inti;的翻译
其中红色表示real x中的变量类型和宽度的传递过程;蓝色虚箭头便是int i的变量类型和宽度传递过程。
例2::数组类型表达式“int[2][3]”的语法制导翻译
注意其中宽度在传递过程中的变化,最终类型表达式的宽度为24。
6.2 简单赋值语句的翻译
赋值语句的基本文法:
①S→id=E; ②E→E1+E2 ③E→E1*E2 ④E→ -E1 ⑤E→(E1) ⑥E→id
赋值语句翻译的主要任务是生成对表达式求值的三地址码。
例如:
源程序片段 x = ( a + b ) * c ;
三地址码 :
t1= a+ b t2 = t1 * c x= t2
赋值语句对应的SDT为:
lookup(name):查询符号表 返回name对应的记录;gen(code):生成三地址指令code;newtemp( ):生成一个新的临时变量t, 返回t的地址 。
在增量方法中,gen( )不仅要构造出 一个新的三地址指令,还要将它添加 到至今为止已生成的指令序列之后
分析过程如上。
6.3 数组引用的翻译
将数组引用翻译成三地址码时要解决的主要问题是 确定数组元素的存放地址,也就是数组元素的寻址。
一维数组
假设每个数组元素的宽度是w,则数组元素a[i]的相对地址是:
base+i x w
其中,base是数组的基地址,i x w 是偏移地址。
二维数组
假设一行的宽度是w1,同一行中每个数组元素的宽度是w2,则 数组元素a[i1] [i2]的相对地址是:
base+i1 x w1+i2 x w2
举例:
假设type(a)= array(3, array(5, array(8, int) ) ), 一个整型变量占用4个字节, 则
a[i1]是一个二维数组,宽度为5*8*8*4=160;a[i1][i2]为一个一维数组,宽度为8*4=32;a[i1][i2][i3]为一个一维数组,宽度就是一个整型变量长度4。
例1:一维数组
假设type(a)=array(n, int);
源程序片段 c = a[i];
三地址码 :
t1= i* 4 t2= a[ t1] c= t2
addr(a[i]) = base + i*4
其中t1表示偏移地址,t2表示加上基地址后的实际地址。
数组引用的SDT
从下往上进行扫描,并逐渐规约出最终地址。
带有语义动作的SDT如上图所示。
6.4 控制流语句及其SDT
控制流语句的代码结构为:
其中包含的继承属性为:
S.next:是一个地址,该地址中存放了紧跟在S代码之后的指令 (S的后继指令)的标号
B.true:是一个地址,该地址中 存放了当B为真时控制流转向的 指令的标号
B.false:是一个地址,该地址 中存放了当B为假时控制流转向 的指令的标号
用指令的标号标识一条三地址指令
控制流语句的基本文法及SDT:
newlabel( ): 生成一个地址;
label(L): 将下一条 三地址指令的标号赋给L
if-then-else语句的SDT
首先生成B.true和B.false的地址并用临时变量存放,如果下一条地址指令给B.true,则将S代码的下一步执行地址给S1,即执行S1的代码,执行完之后,转向执行S的代码。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/149878.html