Bonky Zhu
If someone is able to show me that what I think or do is not right, I will happily change, for I seek the truth, by which no one was ever truly harmed. It is the person who continues in his self-deception and ignorance who is harmed.

编译原理 – 中间代码生成

中间代码生成程序的目的是:把经过语法分析和语义分析而获得的源程序翻译为中间代码表示。

那我们为什么要使用中间代码呢?首先就是便于编译系统建立和编译系统的移植,在移植的时候我们只需要修改后趟即可。然后就是,便于进行独立于机器的代码优化工作,而不是在汇编指令上进行优化。

中间代码的形式

逆波兰表示(后缀式)

运算对象写在前,运算符在后,也称为后缀式。

a+bc 后缀表示为 abc+ 
(a+b)*c 后缀表示为 ab+c*


适合翻译表达式,不适合翻译控制语句(IF,WHILE 什么的)。

三地址代码表示

一般形式:x:=y op z

四元式 op, arg1, arg2, result 
三元式 op, arg1, arg2


四元式需要利用较多的临时单元, 四元式之间的联系通过临时变量实现。但是在中间代码优化处理时,四元式比三元式方便的多 。

常用三地址码的四元式表示:

image-20191125102628875

类型表达式

  • 基本类型是类型表达式:integer,real,char,boolean,type_error (出错类型),void (无类型)
  • 可以为类型表达式命名,类型名也是类型表达式
  • 将类型构造符(type constructor)作用于类型表达式可以构成新的类
  • 型表达式,如:数组,指针笛卡尔积,函数,记录

例子:

image-20191125064159347

  • 和stype绑定的类型表达式:record ( (name x array(8, char)) x (score x integer) )
  • 和table绑定的类型表达式:array (50, stype) 
  • 和p绑定的类型表达式:pointer (stype)

声明语句的翻译

局部变量的存储分配

对于声明语句,语义分析的主要任务就是收集标识符的类型等属性信息,并为每一个名字分配一个相对地址。

  • 从类型表达式可知该类型所需的存储单元称为类型的宽度(width)。
  • 在编译时,可以使用类型的宽度为每一个名字分配一个相对地址。
  • 名字的类型和相对地址信息保存在相应的符号表记录中

image-20191125073942959

由上图,分析方法如下:首先我们先从 P 开始,P 根据产生式,可以生成两个子结点 {a} 和 D,{a} 代表对应的动作,然后让非终结符一直向下生成,直到碰上句柄然后向上归约,归约时,从左到右遍历,遇到 action 时候则执行 。

赋值语句翻译的任务

主要任务是生成对表达式求值的三地址码。

image-20191125081959778

数组引用的翻译

将数组引用翻译成三地址码时要解决的主要问题是确定数组元素的存放地址,也就是数组元素的寻址。

数组元素寻址

注意下面是 w 的意义

image-20191125082120482

例1,假设 type(a)=array(n, int),源程序片段 c = a[i]

三地址码:
$$
\begin{array}{l}{t_{1}=i * 4} \ {t_{2}=a\left[t_{1}\right]} \ {c=t_{2}}\end{array}
$$
例2,假设 type(a)= array(3, array(5, int)),源程序片段 c = a[i1][i2]

三地址码:
$$
\begin{array}{l}{t_{1}=i_{1} * 20} \ {t_{2}=i_{2} * 4} \ {t_{3}=t_{1}+t_{2}} \ {t_{4}=a\left[t_{3}\right]} \ {c=t_{4}}\end{array}
$$

控制流语句

在高级语言中,控制流语句指的是 if...thenif...then...elsewhile...

if ...then...else...

image-20191125083330476

Share

You may also like...

发表评论