第七章 语义分析和中间代码的产生
知识总结
一、中间语言
1、语法树
语法树,有向非循环图和后缀式表示源程序的自然层次结构
2、后缀式
中 缀式: a:=b*-c+b*-c
后缀式:
a b c - * b c - * + =
3、三地址代码表示
一般形式 x:=y op z
三地址语句的种类:
4、语法制导翻译生成三地址代码
需要用到的量:
(1)E.place表示存放E值的名字。
(2)E.code表示对E求值的三地址语句序列。
(3) newtemp是个函数,对它的调用将产生 一个新的临时变量。
5、三地址代码的具体实现
(1)四元式 op, arg1, arg2, result
(2)三元式 op, arg1, arg2
(3)间接三元式 间接码表+三元式表
二、说明语句
说明语句的翻译:对每个局部名字在符号表中建立相应的表项,填写有关的信息。如:类型、嵌套深度、相对地址、内情向量等。
相对地址:相对静态数据区基址或活动数据中局部数据区基址的一个偏移值。
过程中的说明语句 :
一个过程中的所有说明语句作为一个类集来处理。
一个全程变量Offset来记录下 一个数据在符号表中的相对地址。
三、赋值语句的翻译
赋值语句的翻译:
表达式的成分可以是整型量、实型量、数组 元素和记录。
1、符号表中的名字
名字可以理解为指向符号表中相应该名字表项的指针。
过程lookup(id.name)检查是否在符号表中存在相应此名字的表项。
lookup(id.name)= id.entry
nil
emit 它将生成的三地址代码送到输出文件上
例:
emit(E.place‘:=’E1.place‘+’E2.place) 或
emit(= , E1.place,E2.place, E.place)
2、数组元素地址分配(复杂赋值语句)
数组元素地址的计算公式
①一维数组的数组元素计算公式
A[i]的地址:
base+(i-low )* w
=bace-low*w + i*w
常量部分+变量部分:bace-low*w + i*w
②二维数组
A[i1,i2]的地址:
base+((i1 一low1)* n2+i2 一low2)*w)
= base-((low1 *n2)+low2)*w + ((i1*n2)+i2)* w
令c= ((low1 *n2)+low2)*w 则常量部分=a[low1,low2]-c
③多维数组A[i1,i2,...,ik] 的地址的计算:
常量部分c=((...((low1*n2+low2)*n3+low3)...)*nk+lowk) * w
变量部分v= ((...((i1*n2+i2)*n3+i3...)*nk+ik)*w
所以a[i1,i2,…in]的地址
=base-c+v
四、布尔表达式的翻译
布尔表达式: 用布尔运算符号(and,or,not)作用到布尔变量或关系表达式上而组成
布尔表达式的作用:
1. 用作计算逻辑值
2. 用作控制流语句如if-then,if-then-else和while-do等之中的条件表达式
翻译布尔表达式的方法
表示一个布尔表达式的值
方法一:用数值表示真和假,从而对布尔表达式的求值可以象对算术表达式的求值那样一步一步地来计算
方法二:另一种方法是根据布尔表达式的特点,采用了某种优化措施。
数值表示法:用1表示真,0表示假来实现布尔表达式的翻译。
布尔表达式的数值表示法的翻译模式
·emit用于将一个三地址语句输送到文件中
·Nextquat是一个计数器,指向下一个三地址语句在输出序列中的索引序号,也就是即将生成的三地址语句序号。
每执行一次emit后,nextquat自动加1
五、控制语句的翻译
控制流语句中的布尔表达式的翻译:
对于出现在条件语句 if E then s1 else s2中的布尔表达式E,其作用就是控制对S1和S2的选择
因此,作为条件的布尔表达式,把它设计成两个出口:E.true 和 E.false
考虑E的上下文,对于IF语句,E.true 指向S1, E.false指向S2;
对于while语句E.true 指向循环的开始, E.false指向while 的下一语句
基本思想: 假定E 形如a<b,则将生成如下的E的代码:
三地址表示:
E.true: if a<b goto E.true (真出口)
E.false: goto E.false (假出口)
四元式表示:
E.true:(j<, a , b , E.true) (真出口)
E.false: (j, , , E.false ) (假出口)
用四元式实现三地址码,真假出口可表示为:
真出口:
(jnz,a,_,P)表示 if a goto P
(jrop,x,y,P)表示 if x rop y goto P
假出口:
(j,_,_,P)表示 goto P
回填
生成跳转语句时,将其E.true和E.false链成一个链表,记录在E.truelist和E.falselist中
等到转移目标确定以后,再将转移出口填入E.truelist和E.falselist中
翻译模式中用到的三个函数:
①.makelist(i):创建一个仅包含i的新表,i 是四元式数组的一个索引(下标),或说 i是四元式代码序列的一个标号。
②.merge(p1,p2):连接由指针p1和p2指向的两个表并且返回一个指向连接后的表的指针。 Merg(p1,p2)= p1 p2=0;
p1 p2≠0;
③.backpatch(p,t):把i作为目标标号回填到p所指向的表中的每一个转移指令中去。此处的“表”都是为“反填”所拉的链.
使用回填翻译控制流语句
先记录要回填的转移指令地址,在适当的时候进行回填,以便赋值和布尔表达式的求值得到合适的连接,以完成程序的控制流程。
六、过程调用的处理
1. 过程调用主要解决两个问题:
(1)把程序控制转移到子程序(过程段),执行完毕再返回。这个问题很好解决。
(2)传递实在参数。我们前面谈到过几种不同的参数传递方式(传名、传值、传地址),它们的语义动作也就有所区别。
知识应用
总结
这是这学期所学的最后一个章节,赶得紧,也就能理解一些浅显的东西。临近考试,还需要把以前的章节重新回顾一下。