【编译原理】第六章 中间代码生成

第六章 中间代码生成

中间代码也叫中间语言(Intermediate code /language)是:源程序的一种内部表示,不依赖目标机的结构,复杂性介于源语言和机器语言之间。
中间代码常见的几种形式

1、后缀式

2、图表示法

抽象语法树、DAG图

3、三地址代码

三元式、四元式、间接三元式

后缀式

6.1 声明语句的翻译

6.1.1 类型表达式

各类语句的翻译,包括声明语句、控制语句等。声明语句主要是收集类型等信息。

类型表达式也是一种结构,类型表达式包括以下几种情况:

  1. 基本类型是类型表达式

integer 、real 、char 、boolean 、type_error (出错类型) 、void (无类型)

  1. 可以为类型表达式命名,类型名也是类型表达式

  2. 将类型构造符(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的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值