1761 字
9 分钟
编译原理: 语法制导的语义分析

使用一种由语法分析程序的分析过程来主导语义分析以及翻译的过程。称为语法制导的语义计算

语义计算模型主要分为属性文法翻译模式两种。

1. 基于属性文法的语义计算#

1.1 属性文法#

TIP

L={anbncnn0}L = \{a^nb^nc^n|n \ge 0\}不是任何一个上下文无关文法的语言。

对某一文法G[S]G[S]附加一些限定条件[为文法符号关联由特定意义的属性,为产生式关联语义动作或条件谓词],得到一个属性文法G[S]G'[S]G[S]G[S]G[S]G'[S]的基础文法。

定义1.1.11.1.1 语义动作是这样的表达式:

1.b:=f(c1,c2,,ck)[复写规则],b,ci都是绑定产生式的中的符号的属性。2.f(c1,c2,,ck),ci都是绑定产生式的中的符号的属性。\begin{align} &1. b:=f(c_1,c_2,\cdots,c_k)[复写规则], &b,c_i都是绑定产生式的中的符号的属性。\\ &2.f(c_1,c_2,\cdots,c_k), &c_i都是绑定产生式的中的符号的属性。 \end{align}

当语法分析使用某个产生式时,在满足条件谓词的请开给你下,就要执行对应的语义动作。

定义1.1.21.1.2 如果复写规则b:=f(c1,c2,,ck)b:=f(c_1,c_2,\cdots,c_k)中的bb是对应产生式AαA \to \alpha中的AA的属性,则bbAA综合属性。(对父节点赋值,自底向上)

定义1.1.31.1.3 如果复写规则b:=f(c1,c2,,ck)b:=f(c_1,c_2,\cdots,c_k)中的bb是对应产生式AαXβA \to \alpha X\beta中的XX的属性,则bbXX继承属性。(对子节点赋值,自顶向下)

如果是只有综合属性或者只有继承属性的语法树,通过自底向上遍历或者自顶向下遍历就可以计算出所有属性。

但是如果综合属性和继承属性都存在,则可以使用建图(依赖)的方式计算:

建立一张图:1.语法树节点X有关的产生式(一般有2)中节点X的属性,建一个新节点X.attribute2.语法树节点X有关的产生式对应的语义动作(b:=f(c1,c2,,ck)),连上从cib的边。\begin{align} 建立&一张图:\\ &1.语法树节点X有关的产生式(一般有2个)中节点X的属性,建一个新节点X.attribute\\ &2.语法树节点X有关的产生式对应的语义动作(b:=f(c_1,c_2,\cdots,c_k)),连上从c_i到b的边。 \end{align}

如果是一张有向无环图,则可以通过拓扑排序的办法计算得到属性值。

TIP

但是实际过程里如果使用建图的方式,那么语法分析和语义分析是两个不同的过程,需要分两遍进行。

为了发挥语法制导的语义分析的单遍的优势,往往采用一些带限制的属性文法,在语法分析的时候一并完成语义动作,完成语义分析。

1.2 S-属性文法#

定义1.2.11.2.1 SS-属性文法是只包含综合属性的属性文法。

综合属性自底向上传递,因此SS-​属性文法的计算只需要自底向上语法分析时执行语义动作即可。

如果某个SS-属性文法的基础文法G[S]G[S]可以使用某种LR分析方法进行语法分析,就可以在LR分析过程中加入一个语义栈,存放符号栈对应位置的符号的属性值。

IndexIndex状态栈符号栈语义栈输入串ActionActionGOTOGOTO

1.3 L-属性文法#

定义1.3.11.3.1 如果一个属性文法满足的所有语义动作b:=f(c1,c2,,ck)b:=f(c_1,c_2,\cdots,c_k)[关联于产生式AαA\to \alpha]满足:

bA的综合属性或者是某个产生式右部非终结符X的继承属性,但要满足:b只能依赖于X左边符号的属性和A的继承属性\begin{align} b是A的综合属性或者是&某个产生式右部非终结符X的继承属性,但要满足:\\ &b只能依赖于X左边符号的属性和A的继承属性 \end{align}

那么该属性文法才是一个L-属性文法

TIP

SS-属性文法是LL-属性文法的一个特例。

L-属性文法中非终结符的属性只依赖于父节点的继承属性和左边兄弟节点的属性,因此一次自顶向下的遍历可以求出每个符号的属性值。

由于自顶向下语法分析正是这样的过程,所以也可以在LL(k)LL(k)语法分析的同时完成语义分析。

2. 基于翻译模式的语义计算#

翻译模式在形式上类似于属性文法,用{}\{\}​括起来的语义动作出现在产生右部的任何位置,显示地表达属性计算的次序。

属性文法一样,也希望翻译模式在一些加了限制条件的文法上可以单遍遍历就能完成语法分析+语义分析。

2.1 S-翻译模式#

定义2.1.12.1.1 S-翻译模式是一种仅仅涉及综合属性的翻译模式。通常语义动作置于相应的产生式右端的末尾。

SS-翻译模式和SS-属性文法一样,都可以通过自底向上语法分析制导。S-属性文法偏重原理,而S-翻译模式则偏重实现,S-翻译模式里把语义动作都翻译为栈上操作:

若产生式AX1X2XkA\to X_1 X_2\cdots X_k对应的语义动作为:

b:=f(c1,c2,,ck),bA的属性v[topk+1]:=f(v[topk+1],v[topk+2],,v[top])b:=f(c_1,c_2,\cdots,c_k), \quad b是A的属性 \Rightarrow v[top-k+1] := f(v[top-k+1],v[top-k+2],\cdots,v[top])

如果cic_i恰好是XiX_i的属性。

2.2 L-翻译模式#

定义2.2.12.2.1 L-翻译模式既可以包含综合属性,也可以包含继承属性,不过要满足:

若产生式AαXβA \to \alpha X \beta有语义动作X.attr:=f(...)A.attr:=f(...)X.attr := f(...) A.attr := f(...)

  1. XX的继承属性计算只能依赖XX左边符号的属性和产生式左部非终结符AA继承属性并且该计算必须要在非终结符XX之前。
  2. AA​的综合属性计算要在所有依赖属性之后,一般放在产生式的末尾。

形如:Aα {X.attr=f(...)} X β{A.attr=f(...)}A \to \alpha \ \{X.attr = f(...)\} \ X \ \beta \{A.attr = f(...)\}

TIP

S-翻译模式也是L-翻译模式的一个特例。

自顶向下分析方法有预测分析法递归下降法,L-翻译模式就可以是在递归下降分析方法中插入语义分析。

由于L-翻译模式已经指定了语义动作和非终结符XX规约的次序,因此parseA()parseA()函数就很好写。

规定1. 每个parseA()parseA()函数A的继承属性为形参,以AA的综合属性为返回值。

规定2. parseA()parseA()中遇到终结符xx,将xx的属性保存下来,再进行语法判断(查看当前符号是否和该终结符匹配,不匹配则报语法错误)

规定3. parseA()parseA()中遇到非终结符XX,调用parseX()parseX()进行规约,并且把XX的继承属性传递给该函数,用变量保存它的综合属性。

规定4. parseA()parseA()中若遇到语义动作,则执行语义动作

改造后的递归下降分析方法被称为递归下降语义计算程序或者递归下降翻译程序

TIP

当原文法并非是一个LL(1)LL(1)文法时,可以通过消除左递归将文法转变为LL(1)LL(1)文法。不过此时的语义动作也要相应变化:

先往下传递,再传回。

编译原理: 语法制导的语义分析
http://blog.fragments.work/posts/principleofcompiling/ch7/
作者
Lixin WANG
发布于
2024-06-15
许可协议
CC BY-NC-SA 4.0