属性文法
- 属性文法,也称属性翻译文法
- Knuth在1968年提出
- 以上下文无关文法为基础
- 为每个文法符号(终结符或非终结符)配备若干相关的“值"(称为属性),代表与文法符号相关信息,如类型、值、代码序列、符号表内容等
- 对于文法的每个产生式都配备了一组属性的语义规则,对属性进行计算和传递
| 产生式 | 语义规则 |
|---|---|
| L→En | 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 |
- 每一个产生式可配备一条或多条语义规则,这些语义规则说明了每一个产生式所涉及的语法单位之间的语义关系,通过属性计算表达。
综合属性
- 自下而上传递信息
- 语法规则:根据右部候选式中的符号的属性计算左部被定义符号的综合属性
- 语法树:根据子结点的属性和父结点自身的属性计算父结点的综合属性
继承属性
- 自上而下传递信息
- 语法规则:根据右部候选式中的符号的属性和左部被定义符号的属性计算右部候选式中的符号的继承属性
| 产生式 | 语义规则 |
|---|---|
| D→TL | L.in := T.type |
| T → int | T.type := integer |
| T → real | T.type := real |
| T→T1*F | T.val := T1.val*F.val |
| L → L1,id | L1.in := L.in addtype(id.entry, L.in) |
| L → id | addtype(id.entry, L.in) |
对于 L → L1,id,其对应的第一条语义规则 L1.in := L.in 说明 (产生式右侧的) L1的继承属性由(产生式左侧的) L 的继承属性得到;其对应的第二条语义规则 addtype(id.entry, L.in) 调用了addtype函数,实现在符号表中找到 id 在符号表的入口,并将入口的类型信息设置为 L.in 的值。 可以认为(左部的)L有一个虚拟的综合属性 L.s 用于接收该函数的返回值。
- 语法树:根据父结点和兄弟结点的属性计算当前结点的继承属性
第一层中的 L的继承属性 L.in 的值来自兄弟节点 T的type属性
第二层中的 L的继承属性 L.in 的值来自第一层的 L.in的值 (根据产生式L → L1,id对应的语义规则L1.in := L.in)
属性依赖
- 若对应于每个产生式A→a都有一套与之相关联的语义规则,每条规则的形式为(f是一个函数):
b := f(c1, c2…, ck) - 我们称 属性b 依赖于属性c1, c2…, ck
- 其中b是A的一个综合属性并且c1, c2…, ck是产生式右边文法符号的属性
如产生式 E → E1 + T 对应的语义规则 E.val := E1.val + T.val - 或者b是产生式右边某个文法符号的一个继承属性并且c1, c2…, ck是A(产生式左边)或产生式右边任何文法符号的属性
如产生式 L → L1,id对应的语义规则 L1.in := L.in
或产生式 D → TL 对应的语义规则 L.in := T.type
- 其中b是A的一个综合属性并且c1, c2…, ck是产生式右边文法符号的属性
- 终结符(没有子节点)只有综合属性,由词法分析器提供
- F→digit
- digit.lexval
- 非终结符既可有综合属性也可有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值
语义规则
-
对出现在产生式右边的继承属性和出现在产生式左边的综合属性都必须提供一个计算规则。属性计算规则中只能使用相应产生式中的文法符号的属性。
如产生式 L → L1,id对应的语义规则 L1.in := L.in 提供了对出现在产生式右面的 L1的继承属性 L1.in的计算规则
如产生式 E → T对应的语义规则 E.val:=T.val 提供了对出现在产生式左面的 E 的综合属性 E.val 的计算规则 -
对出现在产生式左边的继承属性和出现在产生式右边的综合属性不由所给的产生式的属性计算规则进行计算,由其它产生式的属性规则计算或者由属性计算器的参数提供
如产生式 L → id 对应的语义规则addtype(id.entry, L.in)中 用到了产生式左边的L的继承属性 L.in ,这个语义规则只能使用 L.in 但不能定义如何计算, L.in 的计算应当由其他规则定义
如产生式 D → TL 对应的语义规则 L.in := T.type中 用到了产生式右边的T的综合属性 T.type,这条语义规则同样只能使用T.type而不能定义如何计算。 -
语义规则所描述的工作可以是任何能用函数调用表示的过程,包括属性计算、静态语义检查、符号表操作、代码生成等。
带注释的语法树
语法树描述了语法构成单位之间的层次关系,是一种层次结构。
对语法树进行拓广,为每一个节点标上属性,可以得到带(属性)注释的语法树:
- 在语法树中,一个结点的综合属性的值由其子结点和它本身的属性值确定
- 使用自底向上的方法在每一个结点处使用语义规则计算综合属性的值
- 仅使用综合属性的属性文法称S-属性文法
例如
| 产生式 | 语义规则 |
|---|---|
| L→En | 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 |
- 在语法树中,一个结点的继承属性由其父结点、其兄弟结点和其本身的某些属性确定
- 用继承属性来表示程序设计语言结构中的上下文依赖关系很方便
小结
请点击小标题打开视频观看