本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
编译原理第五章——自下而上分析
目录
- 一、复习:语法分析的两种方式
- 二、自下而上分析概述
- 1.🐯核心思想:移进-规约
- 2.🐶规范规约
- 3.🦁规范规约的两个问题
- 三、算符优先分析
- 1.🐸概念辨析-算符文法、算符优先文法
- 2.🐙概念辨析-算符优先分析法、直观算符优先分析法
- 3.🐬概念辨析-算符文法、算符优先文法
- 4.🐳 利用优先关系表用直观算符优先分析法分析算数表达式(不考可以跳过)
- 5.🐂构造FIRSTVT§和LASTVT§两个集合(必考!!)
- 6.🐝利用FIRSTVT§和LASTVT§两个集合构造优先关系表(必考!!)
- 7.🐇素短语
- 8.🐏优先函数(感觉不会考,至少掌握下概念吧)
- 四、LR分析法
- 1.🐡LR分析法概述
- 2.🍁LR分析过程
- 3.🐚LR(0) (基础必须掌握!!)
- 4.🎵SLR (复习一手FOLLOW集~!!)
- 5.🐼规范规约:LR(k) (最容易考的!!)
- 6.🐱LALR
- 五、本章总结
前面部分的链接: 自下而上分析概述、 算符优先分析、 LR(0)和SLR详细分析(内含FOLLOW优化构造方法)
5.🐼规范规约:LR(k)
概念
- 构造问题:有些无二义文法会产生“移进/归约”冲突或“归约/归约”冲突。
- 产生原因:SLR分析法未包含足够多的“展望”信息。
- 解决办法:让每个状态含有更多的“展望”信息。
- 方法:重新定义项目,使得每个项目都附带有k个终结符,即每个项目的形式为:[A->a ⋅ · ⋅β, a 1 a 2 ⋯ a k a_1 a_2 \cdots a_k a1a2⋯ak]。
- 定义:如上形式的项目称为一个LR(k)项目。
- 说明:
- 向前搜索符串仅对归约项目[A->a·, a 1 a 2 ⋯ a k a_1 a_2 \cdots a_k a1a2⋯ak]有意义;
- 归约项目[A->a·, a 1 a 2 ⋯ a k a_1 a_2 \cdots a_k a1a2⋯ak]意味着:当它所属的状态呈现在栈顶且后续的k个输入符号为 a 1 a 2 ⋯ a k a_1 a_2 \cdots a_k a1a2⋯ak时,才可以把栈顶上的a归约为A;
- 我们只研究k≤1的情形,因为当k = 1的时候已经很很很复杂了,并且已经可以满足绝绝绝大部分需要了~
确定LR(1)项目
确定LR(1)项目的方法:
- ① 对S和S’,只向前搜索#;
- ② 其他产生式,对每一个 V t V_t Vt(含#)均向前搜索。
栗子!
(0) S’ -> S
(1) S -> aB
(2) B -> BB
(3) B -> b
由(0)和(1):
S’ -> [·S,#]
S’ -> [S·,#]
S -> [·BB,#]
S -> [B·B,#]
S -> [BB·,#]
由(2)和(3):
B -> [·aB,a]
B -> [·aB,b]
B -> [·aB,#]
B -> [a·B,a]
B -> [a·B,b]
B -> [a·B,#]
B -> [aB·,a]
B -> [aB·,b]
B -> [aB·,#]
B -> [·b,a]
B -> [·b,b]
B -> [·b,#]
B -> [b·,a]
B -> [b·,b]
B -> [b·,#]
是不是写起来很累,对啦,就没打算让你写,这就是让你康康就行的!
LR(1)分析表的构造步骤
跟LR(0)分析表的构造一样~
标准步骤:(同样了解即可)
- 确定LR(1)项目
- 根据与LR(1)项目构造NFA
- 利用函数CLOSURE和GO求DFA
- 根据DFA构造规范LR分析表
简化步骤:(也是考试的步骤)
- LR(1)项目集规范族的构造
- LR(1)分析表的构造
LR(1)分析的项目集闭包
假定I是文法G’的任一项目集,定义和构造1的闭包CLOSURE(I)如下:
- I的任何项目都属于CLOSURE(I)。
- 若项目[A -> α·Bβ,a]属于CLOSURE(I),B -> ξ \xi ξ是一个产生式,那么,对于FIRST(βa)中的每个终结符b,如果[B -> ξ \xi ξ,b]原来不在CLOSURE(I)中,则把它加进去。
- 重复执行步骤2,直至CLOSURE(I)不再增大为止。
项目集的转换函数GO
令I是一个项目集,X是一个文法符号,函数GO(I,X)定义为:
G
O
(
I
,
X
)
=
C
L
O
S
U
R
E
(
J
)
GO(I, X)=CLOSURE(J)
GO(I,X)=CLOSURE(J)
其中
J
=
任何形如
[
A
→
α
X
⋅
β
,
α
]
的项目
∣
[
A
→
α
٠
X
β
,
α
]
∈
I
J = {任何形如[A→αX·β,α]的项目| [ A→α٠Xβ, α]∈I}
J=任何形如[A→αX⋅β,α]的项目∣[A→α٠Xβ,α]∈I
直接上例子(重中之重!!)
构造如下拓广文法的规范LR分析表
S -> BB
B -> aB
B -> b
1.为文法编号
(O) S’ -> S
(1) S -> BB
(2) B -> aB
(3) B -> b
2.利用CLOSURE方法构造LR(1)项目集规范族:
-
- 先写$ I_0$ = { [S’ -> · S , #] }
- 发现 · 后面有非终结符号,写出S的有关项,则$ I_0$ = { [S’ -> · S , #] , [S -> · B B , #]},因为S和S’的项目的搜索符号只有#,自然不必多说。
- 发现 · 后面有非终结符号,写出B的有关项,则$ I_0$ = { [S’ -> · S , #] , [S -> · B B , #] , [B -> · a B , ?] , [B -> · b , ?] }
- 那么?处到底填什么呢,我们观察[S -> · B B , #]这个项目,当 · 向后移位到第一个B后面时,搜索的就是第二个B了,那么我们填入a/b,则$ I_0$ = { [S’ -> · S , #] , [S -> · B B , #] , [B -> · a B , a/b] , [B -> · b , a/b] }
- 至此$ I_0$总算是写完了。
- 根据$ I_0$可以得到:
- $ I_1$ = GO( $ I_0$ , S ) = { [S’ -> S · , #] }
- 根据$ I_0$可以得到:
- $ I_2$ = GO( $ I_0$ , B ) = { [S -> B · B , #] }
- 发现 · 后面有非终结符号,写出B的有关项,则$ I_2$ = { [S -> B · B , #] , [B -> · a B , ?] , [B -> · b , ?] }
- 那么?处到底填什么呢,我们观察[S -> B · B , #]这个项目,当 · 向后移位到第二个B后面时,搜索的就是#了,那么我们填入#,则$ I_2$ = { [S -> B · B , #] , [B -> · a B , #] , [B -> · b , #] }
- 根据$ I_0$可以得到:
- $ I_3$ = GO( $ I_0$ , a ) = { [B -> a · B , a/b] }
- 填入B的有关项,$ I_3$ = { [B -> a · B , a/b] , [B -> · a B , ?] , [B -> · b , ?] }
- 我们观察[B -> a · B , a/b]这个项目,当 · 向后移位到B后面时,搜索的是a/b了,所以$ I_3$ = { [B -> a · B , a/b] , [B -> · a B , a/b] , [B -> · b , a/b] }
- 根据$ I_0$可以得到:
- $ I_4$ = GO( $ I_0$ , b ) = { [B -> b · , a/b] }
- $ I_1$无法进行下一步了,跳~
- 根据$ I_2$可以得到:
- $ I_5$ = GO( $ I_2$ , B ) = { [S -> B B · , #] }
- 根据$ I_2$可以得到:
- $ I_6$ = GO( $ I_2$ , a ) = { [B -> a · B , #] }
- 填入B的有关项,$ I_6$ = { [B -> a · B , #] , [B -> · a B , ?] , [B -> · b , ?] }
- ? 填入#,$ I_6$ = { [B -> a · B , #] , [B -> · a B , #] , [B -> · b , #] }
- 根据$ I_2$可以得到:
- $ I_7$ = GO( $ I_2$ , b ) = { [B -> b · , #] }
- 根据$ I_3 可以得到: 可以得到: 可以得到: I_8$ = GO( $ I_3$ , B ) = { [B -> a B · , a/b] }
- 根据$ I_3$可以得到:GO( $ I_3$ , a ) = $ I_3$
- 根据$ I_3$可以得到:GO( $ I_3$ , b ) = $ I_4$
- I 4 I_4 I4无法进行下一步了,跳~
- I 5 I_5 I5无法进行下一步了,跳~
- 根据$ I_6 可以得到: 可以得到: 可以得到: I_9$ = GO( $ I_6$ , B ) = { [B -> a B · , #] }
- 根据$ I_6$可以得到:GO( $ I_6$ , a ) = $ I_6$
- 根据$ I_6$可以得到:GO( $ I_6$ , b ) = $ I_7$
- I 7 I_7 I7无法进行下一步了,跳~
- I 8 I_8 I8无法进行下一步了,跳~
- I 9 I_9 I9无法进行下一步了,跳~
- 终于结束辣~~
3.利用LR(1)项目集规范族构造LR(1)分析表:
掏出一张空表:
a | b | # | S | B | |
---|---|---|---|---|---|
0 | |||||
1 | |||||
2 | |||||
3 | |||||
4 | |||||
5 | |||||
6 | |||||
7 | |||||
8 | |||||
9 |
- 先找acc避免遗忘,[S’ -> S · , #] 在 I 1 I_1 I1:
a | b | # | S | B | |
---|---|---|---|---|---|
0 | |||||
1 | acc |
- 按顺序看
I
0
I_0
I0:
- 第一个项目[S’ -> · S , #],点后面是非终结符S,因为$ I_1$ = GO( $ I_0$ , S ),所以输入E前往状态 I 1 I_1 I1,所以GOTO表的第0行第S列写1;
- 第二个项目[S -> · B B , #],点后面是非终结符B,因为$ I_2$ = GO( $ I_0$ , S ),所以输入E前往状态 I 2 I_2 I2,所以GOTO表的第0行第B列写2;
- 第三个项目[B -> · a B , a/b],点后面是a,因为$ I_3$ = GO( $ I_0$ , a ),所以输入a以后前往 I 3 I_3 I3,则ACTION表第0行第a列写s3。
- 第四个项目[B -> · b , a/b],点后面是b,因为$ I_4$ = GO( $ I_0$ , b ),所以输入b后前往 I 4 I_4 I4,则ACTION表第0行第b列写s4。
a | b | # | S | B | |
---|---|---|---|---|---|
0 | s3 | s4 | 1 | 2 | |
1 | acc |
- 同理往后看
I
1
I_1
I1:
- 哈哈这一行只有一个项目~填过了,过!
- 同理往后看
I
2
I_2
I2:
- GOTO表B的位置填5
- ACTION表a的位置填s6
- ACTION表b的位置填s7
- 同理往后看
I
3
I_3
I3:
- GOTO表B的位置填8
- ACTION表c的位置填s3
- ACTION表d的位置填s4
- 同理往后看
I
4
I_4
I4:
- 对项目[B -> b · , a/b]可以规约,根据(3)B -> b ,我们在ACTION表的a/b填上r3。
- 同理往后看
I
5
I_5
I5:
- 对项目[S -> B B · , #]可以规约,根据(1) S -> BB ,我们在ACTION表的#填上r1。
- 同理往后看
I
6
I_6
I6:
- GOTO表B的位置填9
- ACTION表c的位置填s6
- ACTION表d的位置填s7
- 同理往后看
I
7
I_7
I7:
- 对项目[B -> b · , #]可以规约,根据(3)B -> b ,我们在ACTION表的#填上r3。
- 同理往后看 I 8 I_8 I8:
- 对项目[B -> a B · , a/b]可以规约,根据(2) B -> aB ,我们在ACTION表的a/b填上r2。
- 同理往后看 I 9 I_9 I9:
- 对项目[B -> a B · , #]可以规约,根据(2) B -> aB ,我们在ACTION表的#填上r2。
a | b | # | S | B | |
---|---|---|---|---|---|
0 | s3 | s4 | 1 | 2 | |
1 | acc | ||||
2 | s6 | s7 | 5 | ||
3 | s3 | s4 | 8 | ||
4 | r3 | r3 | |||
5 | r1 | ||||
6 | s6 | s7 | 9 | ||
7 | r3 | ||||
8 | r2 | r2 | |||
9 | r2 |
终于,结束辣哈哈哈!!!
6.🐱LALR
概念
- 问题:对于一般的语言,规范LR分析表要用几千个状态,无法实际应用。
- 分析:由例6可以看到,有些状态集除了搜索符不同外是两两相同的。
- 解决办法:合并同心集,构造LALR分析表。
我们称两个LR(1)项目集具有相同的心,如果除去搜索符之后,这两个集合是相同的。
将所有同心的LR(1)项目集合并后,得到一个心就是一个LR(O)项目集。
合并项目集时不用修改转换函数,即GO(1,X);但是,动作ACTION应进行修改,使得能够反映各被合并的集合的既定动作。
合并同心集不会产生新的移进-归约冲突,但有可能产生新的“归约-归约”冲突。
对于同一个文法,LALR分析表和SLR分析表永远具有相同数目的状态,但却能处理一些SLR所不能对付的事情。
构造方法
- 构造文法G的LR(1)项目集族 C = { I 0 , I 1 , ⋯ , I n } C=\{I_0,I_1,\cdots,I_n\} C={I0,I1,⋯,In}
- 把所有的同心集合并在一起,记 C ′ = { J 0 , J 1 , ⋯ , J m } C'=\{J_0,J_1,\cdots,J_m\} C′={J0,J1,⋯,Jm}为合并后的新族。那个含有项目 [ S ′ → ⋅ S , # ] [S'\to \cdot S,\#] [S′→⋅S,#]的 J k J_k Jk为分析表的初态
- 从
C
′
C'
C′构造
A
C
T
I
O
N
ACTION
ACTION表
- 若项目 [ A → α ⋅ a β , b ] [A\to \alpha \cdot a \beta ,b] [A→α⋅aβ,b]属于 J k J_k Jk且 G O ( J k , a ) = J i GO(J_k,a)=J_i GO(Jk,a)=Ji, a a a为终结符,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“ s j sj sj”
- 若项目 [ A → α ⋅ , a ] [A\to \alpha \cdot ,a] [A→α⋅,a]属于 J k J_k Jk,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“用产生式 A → α A\to \alpha A→α归约”,简记为" r j rj rj";其中,假定 A → α A\to \alpha A→α为文法 G ′ G' G′的第 j j j个产生式
- 若项目 [ S ′ → S ⋅ , # ] [S'\to S\cdot ,\#] [S′→S⋅,#]属于 J k J_k Jk,则置 A C T I O N [ k , # ] ACTION[k,\#] ACTION[k,#]为"接受",简记为“ a c c acc acc”
- 构造 G O T O GOTO GOTO表
- 分析表中凡不能用步骤3、4填入信息的空白格均填上“出错标志”
好好好我知道你们都不看,上栗子!
对于刚刚构造的LR(1)项目集规范族,进行同心集合并。
$ I_{36}$ = { [B -> a · B , a/b/#] , [B -> · a B , a/b/#] , [B -> · b , a/b/#] }
$ I_{47}$ = GO( $ I_0$ , a/b/# ) = { [B -> b · , a/b/#] }
$ I_{89}$ = GO( $ I_3$ , a/b/# ) = { [B -> a B · , a/b/#] }
重新写构造表(规则完全一致)。
五、本章总结
- 简单来说,这一章是重点中的重点,内容也相当多(看我这1000多行就知道了),相对也比较难理解,当然考的分也很多,就单纯的大题,算符优先分析约10分,LR分析约17分,比前面几章加起来的分都多,所以一定要好好学习~
- 写题时要注意:看小分写,一般3分对应3个;步骤写全,别偷懒。
我,我的任务完成辣!~~啊哈哈哈哈哈!!(穿山甲的狂笑~)