前言
参考课上PPT内容。 该学习笔记目前仅打算个人使用。
后续会进一步整理,包括添加笔记内容,标明参考资料。
更新中。。。
目录
一、自底向上分析
基本算法思想
若采用自左向右地扫描和分析输入串,那么自底向上的基本算法是:
从输入符号串开始,通过反复查找当前句型的句柄(最左简单短语),并利用有关规则进行规约。若能规约为文法的识别符号,则表示分析成功,输入符号串是文法的合法句子;否则有语法错误。
分析过程是重复以下步骤 :
- 找出当前句型的句柄 x (或句柄的变形);
- 找出以 x 为右部的规则 X → x ;
- 把 x 规约为X,产生语法树的一枝。
关键: 找出当前句型的句柄 x (或其变形), 这不是很容易的。
二、移进——归约分析
- 自底向上分析的一般过程
- Shift-reduce parsing
要点:
- 设置符号栈,用来纪录分析的历史和现状 ,并根据所面临的状态,确定下一步动作是移进还是规约。
分析过程:
- 把输入符号串按顺序一个一个地移进符号栈(一次移一个);
- 检查栈中符号,当在栈顶的若干符号形成当前句型的句柄时,就根据规则进行规约——将句柄从符号栈中弹出,并将相应的非终结符号压入栈内(即规则的左部符号),然后再检查栈内符号串是否形成新的句柄,若有就再进行规约,否则移进符号;
- 分析一直进行到读到输入串的右界符为止。最后,若栈中仅含有左界符号和识别符号,则表示分析成功,否则失败。
优点
- 这一方法简单明了,不断地进行移进规约。
难点
- 关键是确定当前句型的句柄。
例:检查输入串 abbcde 是否是文法 G[S] 的合法句子。
G[S]:
S → aAcBe
A → b
A → Ab
B → d
若采用自底向上分析,即能否一步步规约当前句型的句柄,最终规约到识别符号S。先设立一个符号栈,我们仍然统一用符号 “ # ”作为待分析符号串的左右分界符。
作为初始状态,先将符号串的左分界符推进符号栈作为栈底符号。
分析过程如下表:
| 步骤 | 符号栈 | 输入符号串 | 动作 |
|---|---|---|---|
| 1 | # | abbcde# | 准备。初始化 |
| 2 | #a | bbcde# | 移进 |
| 3 | #ab | bcde# | 移进 |
| 4 | #aA | bcde# | 归约(A → b) |
| 5 | #aAb | cde# | 移进 |
| 6 | #aA | cde# | 归约(A → Ab) |
| 7 | #aAc | de# | 移进 |
| 8 | #aAcd | e# | 移进 |
| 9 | #aAcB | e# | 归约(B → d) |
| 10 | #aAcBe | # | 移进 |
| 11 | #S | # | 归约(S → aAcBe) |
| 12 | #S | # | 成功 |
注:
-
例子的分析过程是一步步地规约当前句型的句柄。
该句子的唯一语法树为:
-
栈内符号串 + 未处理输入符号串 = 当前句型
-
句柄都在栈顶
-
实际上,以上分析过程并未真正解决句柄的识别问题。
问题
上述分析过程中识别句柄的过程,主要看栈顶符号串是否形成规则的右部。
这种做法形式上是正确的,但在实际上不一定正确。
举例的分析过程可以说是一种巧合。
因为不能认为:对句型 xuy 而言,若有U → u,即U ⇒ u 就断定u是简单短语, u 就是句柄,而是要同时满足Z xUy
| 步骤 | 符号栈 | 输入符号串 | 当前句型 |
|---|---|---|---|
| 5 | #aAb | cde# | aAbcde |
A → b ∴ A ⇒ b
A → Ab ∴ A ⇒ Ab
若用 A → b 归约, 得 aAAcde ×
若用 A → Ab 归约,得 aAcde √
三、算符优先分析法
算符优先分析(Operator-Precedence Parsing)
-
这是一种经典的自底向上分析法,简单直观,并被广泛使用。
开始主要是对表达式的分析,现在已不限于此,可以用于一大类上下文无关文法。
-
称为算符优先分析是因为这种方法是仿效算术式的四则运算而建立起来的。
做算术式的四则运算时,为了保证计算结果和过程的唯一性,规定了一个统一的四则运算法则,确定运算符之间的优先关系。
运算法则:
- 乘除的优先级大于加减;
- 同优先级的运算符左大于右;
- 括号内的优先级大于括号外。
于是:4 + 8 - 6 / 2 × 3 运算过程和结果唯一。
思考:4 + 8 - 6 / 2 × 3 第一步进行的运算是哪种运算?
答案:是 + 而非 /,因为读入顺序是自左向右顺序读入的。
特点
仿效四则运算过程,预先规定相邻终结符之间的优先关系,然后利用这种优先关系来确定句型的“句柄”,并进行归约。