语义分析(一)

语义分析一般是和语法分析组合在一起执行的,语法分析完成前一步语法树分析的构建(调用某个产生式完成一步规约,形成当前的树节点),然后语义分析便接着调用相应产生式配备的语义动作或子程序,完成属性文法所要求的语义动作(比如类型转换或生成中间代码)。所以对于属性文法而言,属性的加工和使用过程便是语义处理的意义。

属性文法

一个属性文法是一个三元组,A=(G,V,F),一个上下文无关文法G;一个属性的有穷集V和关于属性的谓词函数的有穷集F。每个断言与文法的某产生式相联。如果对G中的某一输入串而言(句子),A中的所有断言对该输入串的语法树结点的属性全为真,则该串也是A语言中的句子,如下便是一个关于属性文法的例子

由于产生式中出现2个T,加以区别右边T用T1,T2来代替
E→T1+T2 {T1.t=int AND T2.t=int}//谓词,要求若是符合该产生式,则进行相加的两元素必须都是整型
E→T1orT2 {T1.t=bool AND T2.t=bool}
T→num {T.t∶=int} //属性加工,声明该变量为整型,该标识符数据类型属性被赋值为“整型”
T→true {T.t∶=bool}
T→false {T.t∶=bool}
称t为T的一属性。则这带有属性的方法称为属性文法

属性文法便是为所有标识符配备一些属性的文法,这些属性不仅可以描述设计语言的语法有效补充,又可以为语义分析提供足够的数据支持。在推导语法树的过程中,标识符的属性值也在不断加工并通过赋值规则不断层层传递。

对于产生式A->α都有一套与这相关联的语义规则,每队规则的形式b:=f(c1,c2,…)
(1)如果b是A的一个属性,c1,c2…为右部产生式文法符号的属性或则A的其它属性,则称b为A的综合属性。
(2)如果b是右部产生式文法符号X的属性A的一个属性,c1,c2…为A或产生式右边任务文法符号的属性,则称b为X的继承属性。 注意:

  1. 非终结符既可以有综合属性也可以有继承属性,文法开始符号没有继承属性。
  2. 终结符只有综合属性,它由词法分析器提供

综合属性

产生式 语义规则
L->E print(E.val)
E->E1 + T E.val = E1.val + T.val
E->T E.val = T.val
T->T1 * F T.val = T1.val * F.val
T->F T.val = F.val
F->(E) F.val = E.val
F-> digit F.val = digit.lexval
  • 终结符digit仅有综合属性,lexval值由词法分析程序提供
  • 左部E的属性值的计算来自它的右部的非终结符满足条件1,称val为E的综合属性

继承属性

产生式 语义规则
D->TL L.in=T.type
T->int T.type = integer
L->L1,id addtype(id.entry,L.in)
L1.in = L.in
L-> id addtype(id.entry,L.in)
  • T.type = integer,非终结符T,满足条件1,称type为T的综合属性
  • L.in=T.type,非终结符L,满足条件1,称in为L的继承属性
  • addtype(id.entry,L.in)为把终结符类型信息便当在符号表中

计算语义规则

计算语义规则在属性文法的基础上进行处理的。例有属性文法:

产生式 语义规则
D->TL L.in=T.type
T->int T.type = integer
L->L1,id addtype(id.entry,L.in)
L1.in = L.in
L-> id addtype(id.entry,L.in)

当输入字符串为“int id1, id2, id3” 时
(1)构造语法树

D
T
L
int
L1
id3
L2
id2
id1

(2)结合文法属于构造依赖图

L.in=T.type
L1.in = L.in
addtype(id3.entry,L.in)
L2.in = L1.in
addtype(id2.entry,L1.in)
addtype(id1.entry,L2.in)
T
L
L1
id3
L2
id2
id1

从“依赖图”中,我们可以得到主义规则的计算顺序。用这个顺序来计算语义规则就能得到输入符号串的翻译。
注意: 从“依赖图”中发现循环依赖关系,那此文法将不能计算。

属性文法的翻译

属性文法的翻译分为遍历树的和一遍扫描的.

  • 遍历树:深度优先,从左到右遍历方法。如果有需要可以多次遍历。
  • 一遍扫描:在语法分析的同时计属性值,而不是语法分析构造之后进行属性计算,而且无需构造语法树。对于编译程序来讲非常重要。

S-属性文法和自下而上翻译

S-属性文法是只含有综合属性的,例有属性文法:

产生式 语义规则
L->E print(E.val)
E->E1 + T E.val = E1.val + T.val
E->T E.val = T.val
T->T1 * F T.val = T1.val * F.val
T->F T.val = F.val
F->(E) F.val = E.val
F-> digit F.val = digit.lexval

当输入字符串为“2+3*5” 时
(1)LR分析表构造《自底向上语法分析LR(1)》这里简单的用语法树代替

2
3
5
L
E
E1
T
T2
F1
T1
F
F2

(2)分析步骤

步骤 语义栈 符号栈 输入符串 动作
1 - # 2+3*5#
2 -- #2 +3*5#
3 -2 #F1 +3*5# F1-> 2
4 -2 #T2 +3*5# T2-> F1
5 -2 #E1 +3*5# E1->T2
6 -2- #E1+ 3*5
7 -2-- #E1+3 *5#
8 -2-3 #E1+F2 * 5# F2->3
9 -2-3 #E1+T1 * 5# T1->F2
10 -2-3- #E1+T1* 5#
11 -2-3-- #E1+T1*5 #
12 -2-3-5 #E1+T1*F # F->5
13 -2-15 #E1+T # T->T1*F
14 -17 #E # E->E1+T
15 acc

L-属性文法和自上而下翻译

对每个产生式A->X1X2…Xn,其每个语义规则中的每个属性或者综合属性或者Xj(1<=j<=n)的一个继承属性仅依赖于

  1. 产生式Xj在左边符号X1,X2…Xj-1
  2. A的继承属性

S-属性文法一定是L-属性文法,因为1,2的限定只针对继承属性。

带有属性的左递归消除方式

假设文法为
A->A1Y {A.a = g(A1,Y.y)}
A->X {A.a = f(X.x)}
其中g,f是任意函数
文法转换为
A->XR
R->YR|ε
再加上语义动作,引入R的继承属性i和属合属性s
A-> X {R.i = f(X.x)} R {A.a = R.s}
R->Y {R1.i = g(R.i,Y.y)} R1 {R.s = R1.s}
R->ε {R.s = R.i}

例:给定属性文法G[E]

产生式 语义规则
E-> E addop T print(addop.Lexeme)
E-> T
T -> num print(num.val)

注:其中addop表示+或者-
因为要使用自上而下,引进LL(1)算法,由于左递归的关系,改写文法为

产生式
E-> ER
R -> addop T {print(addop.Lexeme) }R1
R -> ε
T -> num {print(num.val)}

当输入字符串为“2+3-5” 时
(1)LL分析表构造<<自顶向下语法分析LL>>这里简单的用语法树代替

2
3
5
E
T
R
print '2'
+
T1
print '+'
R1
print '3'
-
T2
print '-'
R2
print '5'
ε

(2)分析步骤
  (略)

L-属性文法和自下而上翻译

自上而下的计算继续属性有2种方法:

  1. 去掉嵌入在产生式中间的动作

例如文法G[E]
E->TR
R->+T {print(’+’)} R1
R->-T {print(’-’)} R1
R->ε
T->num {print(num.val)}
引入M和N,将原嵌入在产生式中间的动作都放到产生式后面
E->TR
R->+T M R1
R->-T N R1
R->ε
T->num {print(num.val)}
M->ε {print(’+’)}
N->ε {print(’-’)}

  1. 用综合属性代替继承属性

例如文法G[D]
D->L:T
T->integer | char
L->L,id|id
重新构造文法,借以实现综合属性代替继承属性
D->id L
L -> ,id L|:T
T->integer | char

你可能感兴趣的:(#,编译原理)