1 属性文法
1.1 属性文法
在上下文无关文法的基础上,为每个文法符号(终结符或非终结符)配备若干相关的 “值”(称为属性)
属性代表与文法相关信息,如类型、值、代码序列、符号表内容等
语义规则:对于文法的每个产生式都配备了一组属性的计算规则
1.2 属性
在一个属性文法中,对应于每个产生式 A→α 都有一套与之相关的语义规则,每条规则的形式为: b:=f(c1,c2,⋯,ck) ,这里, f 是一个函数,而且或者:
b 是 A 的一个综合属性 并且 c1,c2,⋯,ck 是产生式右边文法符号的属性
b 是产生式右边某个文法符号的一个继承属性 并且 c1,c2,⋯,ck 是 A 或产生式右边任何文法符号的属性
1.3 说明
终结符只有综合属性,由词法分析器提供
F→digit
digit.lexval
非终结符既可有综合属性也可用继承属性,文法开始符号的所有继承属性作为属性计算前的初始值
F→digit
F.val、digit.lexval
对于出现产生式右边的继承属性和出现产生式左边的综合属性都必须提供一个计算规则。属性计算规则只能使用相应产生式中的文法符号属性
F→digit
F.val:=digit.lexval
出现在产生式左边的继承属性和出现在产生式右边的综合属性不得由所给的产生式的属性计算规则计算,由其它产生式的属性规则计算或者由属性计算器的参数提供
语义规则所描述的工作可以包括属性计算、静态语义检查、符号表操作、代码生成等等
1.4 例子
非终结符考虑 A、B 和 C,其中:
产生式 A→BC 可能的规则有: C.d:=B.c+1A.b:=A.a+B.c ,而属性 A.a 和 B.c 在其他地方计算
1.5 总结
综合属性:只能由 等式右边 的 子结点 和 本身 计算
继承属性:只能由 等式左边 的 父节点 、兄弟结点 和 本身 计算
2. 基于属性文法的处理方法
输入串 ⟶ 语法树 ⟶ 按照语义规则计算属性
由源程序的语法结构所驱动的处理办法就是语法制导翻译法
语义规则的计算
对输入符号串的翻译也就是根据语义规则进行计算的结果
2.1 依赖图
在一颗语法树中的结点的继承属性和综合属性之间的相互依赖关系可以由依赖图(有向图)来描述
为每一个包含过程调用的语义规则引入一个虚综合属性 b,这样把每一个语义规则都写成 b:=f(c1,c2,⋯,ck) 的形式
依赖图中为每一个属性设置一个结点,如果属性 b 依赖于属性 c,则从属性 c 的结点有一条有向边连到属性 b 的结点
如:
例子:句子 real、id1、id2、id3 的带注释的语法树的依赖图
L.in:=T.type
T→int
T.type:=integer
T→real
T.type:=real
L→L1,id
L1.in:=L.inaddtype(id.netry,L.in)
L指向L1L和id指向addtype
addtype(id.netry,L.in)
L和id指向addtype
良定义的属性文法
如果一属性文法不存在属性之间的循环依赖关系,那么称该文法为良定义的
属性的计算次序
输入串 ⟶ 语法树 ⟶ 依赖图 ⟶ 语义规则计算次序
上面的例子的属性计算次序是:
a4:=real;a5:=a4;addtype(id3.entry,a5);a7:=a5;addtype(id3.entry,a7);a9:=a7;addtype(id3.entry,a9);
2.2 树遍历
通过树遍历的方法计算属性的值
假设语法树已建立,且树中已带有开始符号的继承属性和终结符的综合属性
while 还有未被计算的属性 do
visitNode(S) /* S 是开始符号 */
procedure visitNode(N:Node);
begin
if N 是一个非终结符 then
/* 假设它的产生式为 N→X1⋯Xm */
for i := i to m do
if Xi∈VN then /* 即 Xi 是非终结符 */
begin
计算 Xi 的所有能够计算的继承属性;
visitNode( Xi )
end;
计算 N 的所有能够计算的综合属性
end
2.3 一边扫描
语法制导翻译法
直观上就是为文法中每个产生式配上一组语义规则,并且在语法分析的同时执行这些语义规则
按语义规则被计算的时机分为:
抽象语法树
在语法树中去掉那些对翻译不必要的信息,从而获取更有效的源程序中间表达。这种经变换后的语法树称之为抽象语法树
简历表达式的抽象语法树
mknode(op,left,right) 建立一个运算符号结点,标号是 op,两个域指针 left 和 right 分别指向左子树和右子树
mkleaf(id,entry) 建立一个标识符结点,标号为 id,一个域 entry 指向标识符在符号表中的入口
mkleaf(num,val) 建立一个数结点,标号为 num,一个域 val 用于存放数的值
建立抽象语法树的语义规则
E→E1+T
E.nptr:=mknode(′+′,E1.nptr,T.nptr)
E→E1−T
E.nptr:=mknode(′−′,E1.nptr,T.nptr)
E.nptr:=T.nptr
T→(E)
T.nptr:=E.nptr
T.nptr:=mkleaf(id,id.entry)
T→num
T.nptr:=mkleaf(num,num.val)
构造 a−4+c 的抽象语法树
3. S- 属性文法的自下而上计算
定义
综合属性 可以在分析输入符号串的同时由自下而上的分析器来计算
分析器可以保存与栈中文法符号有关的综合属性值,每当进行归约时,新的属性值就由栈中正在归约的产生式右边符号的属性值来计算
S- 属性文法的计算
假设语义规则 A.a:=f(X.x,Y.y,Z.z) 是对应于产生式 A→XYZ
例子
print(E.val)
print(val[top])
E→E1+T
E.val:=E1.val+T.val
val[ntop]:=val[top−2]+val[top]
E.val:=T.val
T→T1∗F
T.val:=T1.val∗F.val
val[ntop]:=val[top−2]∗val[top]
T.val:=F.val
F→(E)
F.val:=E.val
val[ntop]:=val[top−1]
F→digit
F.val:=digit.lexval
F→digit
F→digit
T→T∗F
F→digit
E→E+T
4. L- 属性文法的自顶向下翻译
自顶向下翻译
通过深度优先的方法对语法树进行遍历,计算属性文法的所有属性值
L- 属性文法
对于每个产生式 A→X1X2⋯Xn ,其中每个语义规则中的每个属性要么是 综合属性,要么是 Xj(1≤j≤n) 的一个继承属性且这个继承属性仅依赖于:
产生式中 Xj 左边符号 X1,X2,⋯,Xj−1 的属性
4.1 翻译模式
语义规则:给出了属性计算的定义,没有属性计算的次序等实现细节
翻译模式:给出了使用语义规则进行计算的次序,这样就可把某些实现细节表示出来
在翻译模式中,和文法符号相关的属性和语义规则(语义动作),用花括号 { } 括起来,插入到产生式右部的合适位置上
4.2 建立翻译模式
当只需要综合属性时:为每一个语义规则建立一个包含赋值的动作,并把这个动作放在相应的产生式右边的末尾
产生式: T→T1∗F
语义规则: T.val:=T1.val∗F.val
建立产生式和语义动作: T→T1∗F{T.val:=T1.val∗F.val}
如果既有综合属性又有继承属性,在建立翻译者模式时就必须保证:
产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来
产生式左边非终结符的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的末尾
错误:S→A1A2{A1.in:=1;A2.in:=2}A→a{print(A.in)}
例子:
B.ps:=10S.ht:=B.ht
S→{B.ps:=10}B{S.ht:=B.ht}
B→B1B2
B1.ps:=B.psB2.ps:=B.psB.ht:=max(B1.ht,B2.ht)
S→{B1.ps:=B.ps}B1{B2.ps:=B.ps}B2{B.ht:=max(B1.ht,B2.ht)}
B→B1subB2
B1.ps:=B.psB2.ps:=shrink(B.ps)B.ht:=disp(B1.ht,B2.ht)
S→{B1.ps:=B.ps}B1sub{B2.ps:=shrink(B.ps)}B2{B.ht:=disp(B1.ht,B2.ht)}
B→text
B.ht:=text.h∗B.ps
B→text{B.ht:=text.h∗B.ps}
转换方法
加入新的产生式 M→ϵ
把嵌入在产生式中的每个语义动作用不同的标记非终结符 M 代替,并把这个动作放在产生式 M→ϵ 的末尾
E→R→∣∣T→TR+T{print(′+′)}R−T{print(′−′)}Rϵnum{print(num.val)} 转换后 E→R→T→M→N→TR+TMR∣−TNR∣ϵnum{print(num.val)}ϵ{print(′+′)}ϵ{print(′−′)}
4.3 自顶向下翻译
动作是在处于相同位置上的符号被展开(匹配成功)时执行的
为了构造不带回溯的自顶向下语法分析,必须消除文法中的左递归
当消除一个翻译模式的基本文法的左递归时同时考虑属性 —— 适合带综合属性的翻译模式
一般方法
假设有翻译模式: A→A1Y{A.a:=g(A1.a,Y.y)}A→X{A.a:=f(X.x)}
它的每个文法符号都有一个综合属性,用小写字母表示,g 和 f 是任意函数
消除左递归: A→XRR→YR∣ϵ
翻译模式变为: A→R→R→X{R.i:=f(X.x)}R{A.a:=R.s}Y{R1.i:=g(R.i,Y.y)}R1{R.s:=R1.s}ϵ{R.s:=R.i}
其中 R.i :R 前面子表达式的值;R.s :分析完 R 时子表达式的值
构造抽象语法树的属性文法定义转化成翻译模式
E→E1+T
E.nptr:=mknode(′+′,E1.nptr,T.nptr)
E→E1−T
E.nptr:=mknode(′−′,E1.nptr,T.nptr)
E.nptr:=T.nptr
T→(E)
T.nptr:=E.nptr
T.nptr:=mkleaf(id,id.entry)
T→num
T.nptr:=mkleaf(num,num.val)
先对上述产生式进行消除左递归后:
E→T{R.i:=T.nptr}R{E.nptr:=R.s}
R→+TR1
R→−T{R1.i:=mknode(′+′,R.i,T.nptr)}R1{R.s:=R1.s}
R→−TR1
R→−T{R1.i:=mknode(′−′,R.i,T.nptr)}R1{R.s:=R1.s}
R→ϵ
R→{R.s:=R.i}
T→(E)
T→(E){T.nptr:=E.nptr}
T→id{T.nptr:=mkleaf(id,id.entry)}
T→num
T→num{T.nptr:=mkleaf(num,num.val)}
4.4 递归下降翻译器的设计