第六章:属性文法和语法制导翻译
一、属性文法
属性文法:是在上下文无关文法的基础上为每个文法符号(终结符或非终结符)配备若干个相关的“值”(称为属性)
属性:代表与文法符号相关的信息,和变量一样,可以进行计算和传递
属性的分类:综合属性和继承属性
1)综合属性
l 用于“自下而上”传递信息
l 在语法树中,一个结点的综合属性的值,由其子结点的属性值确定
l S—属性文法:仅仅使用综合属性的属性文法
2)继承属性
l 用于“自上而下”传递信息。
l 在语法树中,一个结点的继承属性由此结点的父结点和/或兄弟结点 的某些属性确定
语义规则:属性计算的过程即是语义处理的过程,对于文法的每一个产生式配备一组属性的计算规则,则称为语义规则。
A®b1b2…bn
b:=f(c1,c2,…,ck)
(1)b是A的一个综合属性
(2)b是bi的一个继承属性
注意:
1)终结符只有综合属性,它由词法分析器提供
2)非终结符既可以有综合属性也可以有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值。
3)产生式右边符号的继承属性和产生式左边符号的综合属性都必须提供一个计算规则
4) 产生式左边符号的继承属性和产生式右边符号的综合属性不由所给的产生式的属性计算规则进行计算,它们由其它产生式的属性规则计算
语义规则所描述的工作:
属性计算
静态语义检查
符号表操作
代码生成
二、基于属性文法的处理过程
输入串®语法树®依赖图®语义规则计算次序®计算结果
这种由源程序的语法结构所驱动的处理办法就是语法制导翻译法
依赖图:在一颗语法树中的结点的继承属性和综合属性之间的相互依赖关系可以用称作依赖图的一个有向图来描述。
在为一棵语法树构造依赖图以前,我们为每一个包含过程调用的语义规则引入一个虚综合属性b,这样把每一个语义规则都写成
b:=f(c1,c2, …ck)
依赖图中为每一个属性设置一个结点,如果属性b依赖属性c,则从属性c的结点有一条有向边连到属性b的结点。
依赖图的构造算法:
for分析树中每一个结点n
for结点的文法符号的每一个属性a
为a在依赖图中建立一个结点;
for分析树中每一个结点n
for结点n所用产生式对应的每一个语义规则
b:=f(c1,c2,…ck)
fori :=1 to k
从ci结点到b结点构造一条有向边
属性的计算次序问题:
一个有向非循环图的拓扑序是图中结点的任何顺序m1,m2, …mk,使得边必须是从序列中前面的结点指向后面的结点。也就是说,如果mi®mj是mi到mj的一条边,那么在序列中mi必须出现在mj之前。
树遍历的属性计算方法:
最常用的遍历方法是深度优先,从左到右的遍历方法
如果需要,可使用多次遍历
一遍扫描的处理方法:
是在语法分析的同时计算属性值,而不是语法分析构造语法树之后进行属性的计算,而且无需构造实际的语法树。
两个因素密切相关:
1)所采用的语法分析方法
2)属性的计算次序
抽象语法树:
抽象语法树中,操作符和关键字都不作为叶结点出现,而是把它们作为内部结点,即这些叶结点的父结点。
三、S-属性文法的自下而上计算
S—属性文法,它只含有综合属性。
1、S属性的自下而上计算
第七章:语义分析和中间代码的产生
1、语义分析
语义分析的任务:
1) 审查每一个语法结构的静态语义,即验证语法正确的结构是否有意义
2) 在语义正确的基础上生成一种中间代码或目标代码。
语义分析的范围
1)确定类型
2)类型检查
3)识别含义
4)控制流检查
5)一致性检查
6)相关名字检查
2、几种常用的中间语言形式
1)逆波兰表示法
波兰表示是一种既不须考虑优先关系、又不用括号的一种表示表达式的方法(前缀式)
例子:a+b → ab+
a*(b+c) → abc+*
2) 图表示法
抽象语法树。
无循环有向图(DAG)
3) 三元式
三元式由三个部分组成:
算符:OP
第一运算分量:ARG1
第二运算分量:ARG2
各种语句都可表示成一组三元式
例1: OP ARG1 ARG2
语法制导产生三元式:
4) 间接三元式
在三元式的基础上附加一张指示器表─间接码表,按运算的先后顺序列出有关三元式在三元式表中的位置。这种表示方法称为间接三元式
5) 四元式
一个四元式是一个带有四个域的记录结构:op,arg1,arg2及result。它实际上就是一条三地址的指令。
有时将四元式表示成更直观的形式-三地址代码
三地址代码形式:
x:=a op b (赋值形式)
与赋值语句的区别:其右边最多只能有一个运算符
3、某些语句的四元式及翻译
1)说明语句的翻译
为局部名字建立符号表条目
为它分配存储单元
符号表中包含名字的类型和分配给它的存储单元的相对地址等信息
简单说明句
用一个基本字来定义一串名字,其语法描述一般为:
D→integer namelist∣realnamelist
namelist→namelist,i∣i
直接用这种文法来制导翻译有点麻烦,就是只能在把所有名字规约成namelist之后才能把性质登记到符号表中。这就意味着在扫描名字时,应把名字用一个队列(或栈)保存起来,然后再处理。
我们可以对文法稍做改动,就可以免去建立队列或栈的过程。修改文法如下:
D→D,i∣integer i∣real i
数组说明:
2)赋值语句的翻译
简单算术表达式的赋值语句
类型转换
3) 控制流语句的翻译
可以仿照算术表达式的翻译来进行。
例如 A∨B∧C=D可翻译成如下四元式序列:
(=,C,D,T1)
(∧,B,T1,T2)
(∨,A,T2,T3)
但是对于控制语句中的条件表达式,我们还必须结合控制语句作进一步的分析。
(1)条件语句中布尔表达式的翻译:
(2)标号和无条件转移的翻译:
(3)循环与分情况语句的翻译:
循环语句:
1产生四元式:emit(:=,E1.place,--,ENTRY(i));
2保留ENTRY(i):F1.place:=ENTRY(i);
3因为goto over 的转移地址暂时填不上,必须
建链:F1.chain:=nextquad;
4产生无条件转移指令:emit(j,--,--,0);
5保留again的地址:F1.quad:=nextquad;
分情况语句:
4) 过程调用的翻译