【编译原理复习笔记】语法分析(二)

自底向上的语法分析

从分析树的底部(叶节点)向顶部(根结点)方向构造分析树

自顶向下的语法分析采用最左推导,与之对应自底向上采用最左规约(反响构造最右推导)

移入规约分析

(1)从输入中移动终结符到栈中

(2)若此时栈中终结符无法与产生式列表中的右部任何一项对应,则继续移入终结符

(3)若此时栈中某一部分可以进行规约,则转换成对应可规约产生式的左部,然后再次进行(1)

(4)当输入中最后不含有终结符,且栈中最后只剩下开始符号的时候,证明规约结束

栈内符号串+剩余输入="规范句型"

每规约一次,规范句型才会变化一次(而不是移入栈内就会规约

存在的问题

在规约的过程中,可能栈中的符号串满足多个产生式的右部,此时会出现类似二义性的问题

LR 分析法

LR 文法是最大的,可以构造出相应移入-规约语法分析器的文法

L:对输入进行左到右的扫描

R:反向构造最右推导序列

LR(k)中的 k 代表需要向前查看 k 个输入符号

基本原理就是正确识别句柄:

e.g.
S → b B B S\to bBB S→bBB

对于该例子,我们可以认为其分为下面几种状态:
S → ⋅ b B B S\to ·bBB S→⋅bBB移进状态
S → b ⋅ B B S\to b·BB S→b⋅BB待约状态
S → b B ⋅ B S\to bB·B S→bB⋅B待约状态
S → b B B ⋅ S\to bBB· S→bBB⋅规约状态

LR 分析表

对于产生式
S → B B S \to BB S→BB
B → a B B \to aB B→aB
B → b B \to b B→b

s 代表移入栈,后面的符号代表了移入栈的状态,rn代表用第 n 个产生式进行规约

(这里不需要深究分析表如何构成的,后面会解释)

假如输入为:bab$

(1)此时状态栈顶为 0,指针指向 b,对应状态表将其放入栈中,栈中现在为 b ,然后跳转到 4 号状态( 2 )此时状态栈顶为 4 ,指针指向 a ,对应状态表使用第三个产生式对栈顶符号( b )进行规约,状态栈中 4 和符号栈中 b 被拿掉,栈中现在为 b,然后跳转到 4 号状态 (2)此时状态栈顶为 4,指针指向 a,对应状态表使用第三个产生式对栈顶符号(b)进行规约,状态栈中 4 和符号栈中 b 被拿掉,栈中现在为 b,然后跳转到4号状态(2)此时状态栈顶为4,指针指向a,对应状态表使用第三个产生式对栈顶符号(b)进行规约,状态栈中4和符号栈中b被拿掉,栈中现在为B

(3)此时状态栈顶为 0,遇到刚规约的 B,此时查看 GOTO 表可知进入 2 号状态

...

按照这个顺序不断进行,直到符号栈最后只剩下 S 为止,此时结束

LR(0)分析

在产生式右部中某位置标有圆点的产生式称为相应文法的一个 LR(0)项目,每个项目表示了一个句柄的识别状态

增广文法

在原本产生式的基础上定义一个新的开始符号,以及新的开始符号指向原开始符号的产生式,可以避免原本产生式中出现多个开始符号,保证分析器只有一个接受状态

等价状态

如果每个产生式的每个状态都认为是状态表中的一种状态,此时的状态个数会十分庞大,所以我们引入等价状态来削减状态数量,多个状态构成的等价状态才是状态机中的一个状态

e.g.
S ' → S S' \to S S'→S
S → B B S \to BB S→BB
B → a B B \to aB B→aB
B → b B \to b B→b

这是上述例子的增广文法,此时对这四条产生式分析等价状态

我们就可以得到一共 7 种等价状态,而如果每个产生式都单独考虑的话就需要 10 个状态

项目集闭包

在 LR0 分析这一节中,我们定义了什么是项目,项目集就是项目的集合,而项目集的闭包则包括了所有可以从初始项目通过 0 次或多次产生式推导而到达的项目

CLOSURE 函数

CLOSURE 函数用于计算一个给定项目集的闭包,给定一个项目集 I和一个文法 G,CLOSURE(I)会返回一个新的项目集,包含 I 中的所有项目以及 I 可以推导出的所有项目

GOTO 函数

返回项目集 I 对应于文法符号 X 的后继项目集闭包,其实就是起到了跳转的作用。如在例子中,如此时处于项目集 I0,那么 GOTO(I0,a)表示的就是项目集 I3

构造 ACTION 表

(1)对于某个项目集 Ii,遍历其所有项目

如果某个项目为有移进项目的形式: A → α ⋅ β A \to \alpha·\beta A→α⋅β

且 beta 的第一个符号为终结符 a,则 action 表第 i 行第 a 列填入 sk,k 为将 a 放入栈中后跳转的状态

(2)如果某个项目为有移进项目的形式: A → α ⋅ A \to \alpha· A→α⋅,则 action 表第 i 行所有列填入 rj,j 为对应产生式的序号

(3)如果某个位置没有任何移进或规约,则该行打上 err

(4)如果某个状态完成了所有规约只剩开始符号,该行打上 acc

构造 GOTO 表

(1)识别产生式中所有的非终结符

(2)计算当前状态集的闭包,确定通过当前栈顶的非终结符可以到达的下一个状态,重复的项目需要去重

(3)在 GOTO 表的对应位置,填入可以到达的下一个状态

LR(0)文法的形式化定义

M = ( C , V N ∪ V T , G O T O , I 0 , F ) M=(C,V_N\cup V_T,GOTO,I_0,F) M=(C,VN∪VT,GOTO,I0,F)
KaTeX parse error: Expected 'EOF', got '}' at position 73: ...T,I=GOTO(J,X)\\}̲
I 0 = C L O S U R E ( S ' → ⋅ S ) I_0=CLOSURE(\\{S' \to ·S\\}) I0=CLOSURE(S'→⋅S)
F = C L O S U R E ( S ' → S ⋅ ) F = \\{ CLOSURE(\\{S' \to S·\\})\\} F=CLOSURE(S'→S⋅)

移进规约冲突

在同一个状态中,可能出现一个项目需要移进,另一个项目需要规约的情况,问题源于 LR(0)算法往前看了 0 个符号

SLR

FOLLOW 集可以帮助我们判定何时规约:当规约后的非终结符的 FOLLOW 集不包含状态集中将要移进的非终结符时,此时不应该规约

SLR 分析法的基本思想
SLR 与 LR0

在 SLR 分析表中,原本 LR0一整行都为规约动作中,某一可能因为冲突而转为移进,其余地方没有差别

SLR 分析表中的冲突

有时候 FOLLOW 集不能够完全解决冲突的问题,我们还需要更多的限制来完成冲突的区分

LR(1)分析

SLR 只是简单的考察了规约与 FOLLOW 集的关系,下一个输入符号 a ∈ F O L L O W ( A ) a \in FOLLOW(A) a∈FOLLOW(A)只是规约 a 的一个必要条件,而非充分条件

对于产生式 A → a A \to a A→a的归约,在不同位置,A 会要求不同的后继符号

在特定位置,A 的后继符号集是 FOLLOW(A)的子集

LR(1)项目的规范

将一般产生式 [ A → α ⋅ β , a ] [A \to \alpha·\beta,a] [A→α⋅β,a]的项称为 LR(1)项,a 是一个终结符,它表示在当前状态下,A 后面必须紧跟终结符,称为展望符

当 beta 不等于 epsilon 时,a 不起作用;当 beta 等于 epsilon 时,只有在下一个输入符号为 a 时才可以按照产生式进行规约

等价 LR(1)项目

∣ A → α ⋅ b β , a ∣ |A \to \alpha·b\beta,a| ∣A→α⋅bβ,a∣

若 B → γ ∈ P B \to \gamma \in P B→γ∈P

则等价于 ∣ B → γ , b ∣ |B \to \gamma,b| ∣B→γ,b∣
b ∈ F I R S T ( β a ) b \in FIRST(\beta a) b∈FIRST(βa)

当 beta 为空字符的时候,b=a,称为继承的后继符,否则叫自身的后继符。

LR(1)自动机

如果除了展望符以外,两个 LR1 项目集是相同的,则称这两个 LR1 项目集是同心的,如 I4 和 I11

LALR 分析法

同心项目集合并为同一个项目集,根据合并后的项目集族构造语法分析表,若语法分析表没有错误则为 LALR 分析法

规约规约冲突

在同心项目集中,两个相同的都需要规约的产生式对应的展望符号不相同,此时会出现矛盾无法确定合并后按照哪个展望符进行规约

LALR 分析法的特点

形式上与 LR(1)相同

大小上与 LR(0)/SLR 相当

分析能力:LR0<SLR<LALR<LR1

相关推荐
芊寻(嵌入式)1 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
准橙考典1 小时前
怎么能更好的通过驾考呢?
人工智能·笔记·自动驾驶·汽车·学习方法
密码小丑3 小时前
11月4日(内网横向移动(一))
笔记
鸭鸭梨吖4 小时前
产品经理笔记
笔记·产品经理
齐 飞4 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
丫头,冲鸭!!!5 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
听忆.5 小时前
手机屏幕上进行OCR识别方案
笔记
Selina K6 小时前
shell脚本知识点记录
笔记·shell
6 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
霍格沃兹测试开发学社测试人社区7 小时前
软件测试学习笔记丨Flask操作数据库-数据库和表的管理
软件测试·笔记·测试开发·学习·flask