语法分析4
主要介绍构造LR(1)和LALR(1)分析表的算法:
LR(1)语法分析表的主要核心是求出各个状态的克林闭包,具体看龙书算法4.9
简单表达如下:
有产生式:
A -> αBβ
B -> η
当输入字符为a时表示为:
[A -> α.Bβ, a]
目的是要求出它的闭包,这个运算的最关键的步骤在于求出可接受的下一个输入字符.算法简单的描述为:
[A -> α.Bβ, a]
[B -> .η, first(βa)]
first(βa)代表,产生式βa的first集合.
依次类推知道不再有新的状态加入到该集合中为止.
例如龙书上的例子:
S’ -> S
S -> CC
C -> cC | d
初时状态为$代表文件结束
[S’ -> .S, $]
接下来的步骤是
[S’ -> .S, $]
[S -> .CC, first($)] = [S -> .CC, $]
[C -> .cC, first(C$)] = [C -> .cC, c/d]
[C -> .d, first(C$)] = [C -> .d, c/d]
以上是集合I0
I1 = I0 –S->
[S’ -> S., $]
I2 = I0 –C->
[S -> C.C, $]
[C -> .cC, first($)] = [C -> .cC, $]
[C -> .d, first($)] = [C -> .c, $]
就这样进行下去,最后再没有新的状态加入了,这样状态集合和转换函数都求出来了.
最后LR(1)项目集:
I0: S' -> .S, $
S -> .CC, $
C -> .cC, c/d
C -> .d, c/d
I1: S' -> S., $
I2: S -> C.C, $
C -> .cC, $
C -> .d, $
I3: C -> c.C, c/d
C -> .cC, c/d
C -> .d, c/d
I4: C -> d., c/d
I5: S -> CC., $
I6: C -> c.C, $
C -> .cC, $
C -> .d, $
I7: C -> d., $
I8: C -> cC., c/d
I9: C -> cC., $
Goto函数
goto(I0, S) = I1
goto(I0, C) = I2
goto(I0, c) = I3
goto(I0, d) = I4
goto(I2, C) = I5
goto(I2, c) = I6
goto(I2, d) = I7
goto(I3, C) = I8
goto(I3, c) = I3
goto(I3, d) = I4
goto(I6, C) = I9
goto(I6, c) = I6
goto(I6, d) = I7
由LR(1)项目集构造分析表的过程:
将原理的BNF拆分并编号
0)S’ -> S
1)S -> CC
2)C -> cC
3)C -> d
根据龙书算法4.10
根据算法a)首先看LR(1)项目集或者goto函数中蓝色的部分,填入sx其中x是状态号分析表如下:
根据算法b)看LR(1)项目集中的红色部分填入rx 其中x是产生式的号码,根据算法c)看LR(1)项目集中粉色部分表示接受.
根据算法3)看goto函数的绿色部分,填入goto表如下:
状态 |
action |
goto | |||
c |
d |
$ |
S |
C | |
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 |
|
|
下面是使用这个分析表分析字符串的例子
ccccdcd
0 ccccdcd$
0c3 cccdcd$
0c3c3 ccdcd$
0c3c3c3 cdcd$
0c3c3c3c3 dcd$
0c3c3c3c3d4 cd$
0c3c3c3c3C8 cd$
0c3c3c3C8 cd$
0c3c3C8 cd$
0c3C8 cd$
0C2 cd$
0C2c6 d$
0C2c6d7 $
0C2c6C9 $
0C2C5 $
0S1 $
0acc $
------------------------------
LALR(1)分析表的建立
第一种方法是建立LR(1)项目集,然后合并同心项目,这样做工作量太大.龙书中给出了简便的做法:
同样的产生式:
S’ -> S
S -> CC
C -> cC | d
1)建立LR(0)项目集,和goto函数
LR(0)项目集
I0: S' -> .S
S -> .CC
C -> .cC
C -> .d
I1: S' -> S.
I2: S -> C.C
C -> .cC
C -> .d
I3: C -> c.C
C -> .cC
C -> .d
I4: C -> d.
I5: S -> CC.
I6: C -> cC.
Goto函数
goto
goto(I0, S) = I1
goto(I0, C) = I2
goto(I0, c) = I3
goto(I0, d) = I4
goto(I2, C) = I5
goto(I2, c) = I3
goto(I2, d) = I4
goto(I3, C) = I6
goto(I3, c) = I3
goto(I3, d) = I4
2)由LR(0)项目集求出LR(0)项目集的核(核的概念在4.7.3.1中)
I0: S' -> .S
I1: S' -> S.
I2: S -> C.C
I3: C -> c.C
I4: C -> d.
I5: S -> CC.
I6: C -> cC.
3)接下来要通过LR(0)的核构造LALR(1)的核.
首先通过LR(0)的核和哑搜索符号,根据算法4.12来求出核中搜索符号的自生和传播.
自生和传播的概念龙书算法4.12前面一段.
关于#克林闭包
I0: S' -> .S, #
S -> .CC, #
C -> .cC, c/d/#
C -> .d, c/d/#
I1: S' -> S., #
I2: S -> C.C, #
C -> .cC, #
C -> .d, #
I3: C -> c.C, #
C -> .cC, #
C -> .d, #
I4: C -> d., #
I5: S -> CC., #
I6: C -> cC., #
----------------------------------
自生表
I0: S' -> .S, $
I3: C -> c.C, c/d
I4: C -> d., c/d
----------------------------------
传播表
from : to
I0 I1
I2
I3
I4
I2 I3
I4
I5
I3 I3
I4
I6
首先LR(0)项目集的核中初时状态中$是自生的
所以自生表有了第一个自生元素(黑色的部分)
然后对于LR(0)核中的I0求关于哑搜索符号#的克林闭包(克林闭包表中蓝色的部分)看第三和第四个项目(灰色背景)根据龙书中搜索符号自生和传播的发现算法,和goto函数(蓝色部分)可以确定I3和I4的核项目中含有自生符号c/d(自生表中蓝色字体,灰色背景部分), 同时搜索符的传播也可以确定下来(传播表中的蓝色部分).
依照这样的做法,求出自生表和传播表(同样颜色代表自生表和传播表是有那个闭包求得的)
(注意在求I3和I4的闭包的时候不要受自生表的影响,自生表是这个算法的结果,所以求闭包不要考虑)
下面根据自生表和传播表来求出LALR(1)的核, 根据龙书算法4.13
集合:项目 |
搜索符 | ||
初始化 |
第一次传播 |
第二次传播 | |
I0: S' -> .S |
$ |
$ |
$ |
I1: S' -> S. |
|
$ |
$ |
I2: S -> C.C |
|
$ |
$ |
I3: C -> c.C |
c/d |
c/d/$ |
c/d/$ |
I4: C -> d. |
c/d |
c/d/$ |
c/d/$ |
I5: S -> CC. |
|
|
$ |
I6: C -> cC. |
|
c/d |
c/d/$ |
初始化时只有自生搜索符,根据自生表填入初始化列.
然后开始传播,的一次传播时根据传播表,只有有初时状态的项才能传播,I0可以向I1,I2,I3,I4传播$,I3可以向I3,I4,I6传播c/d但是传播表中没有I4的传播路径所以I4不会向下传播.(黑色代表由I0传播的,蓝色代表由I3传播的)
第二次传播
看传播表, 在第一次传播以后I0没有产生新的搜索符,所以I0的传播已经完成了,在第一次传播以后I2有新的搜索符产生,所以I2要向I3,I4,I5传播$,但是I3,I4已经有$不需要传播了所以I2只向I5传播(表中红色部分).
在第一次传播以后,I3也加入了新的传播符号$, 对于$来说只有I6没有被传播,所以第二次传播,只有I6被传播了$(表中绿色部分).到这里不在有新符号在传播中产生了,传播结束了,根据表可以写出LALR(1)的核:
I0: S' -> .S, $
I1: S' -> S., $
I2: S -> C.C, $
I3: C -> c.C, c/d/$
I4: C -> d., c/d/$
I5: S -> CC., $
I6: C -> cC., c/d/$
4)对LALR(1)中的每个项目求对应搜索符的克林闭包,得到LALR(1)项目集
I0: S' -> .S, $
S -> .CC, $
C -> .cC, c/d
C -> .d, c/d
I1: S' -> S., $
I2: S -> C.C, $
C -> .cC, $
C -> .d, $
I3: C -> c.C, c/d/$
C -> .cC, c/d/$
C -> .d, c/d/$
I4: C -> d., c/d/$
I5: S -> CC., $
I6: C -> cC., c/d/$
5)有了LALR(1)项目集再根据goto函数和产生式就可以求出LALR(1)的分析表:
goto(I0, S) = I1
goto(I0, C) = I2
goto(I0, c) = I3
goto(I0, d) = I4
goto(I2, C) = I5
goto(I2, c) = I3
goto(I2, d) = I4
goto(I3, C) = I6
goto(I3, c) = I3
goto(I3, d) = I4
---------------------------------
0)S’ -> S
1)S -> CC
2)C -> cC
3)C -> d
根据求LR(1)的分析表的方法求出LALR(1)的分析表:
状态 |
action |
goto | |||
c |
d |
$ |
S |
C | |
0 |
s3 |
s4 |
|
1 |
2 |
1 |
|
|
acc |
|
|
2 |
s3 |
s4 |
|
|
5 |
3 |
s3 |
s4 |
|
|
6 |
4 |
r3 |
r3 |
r3 |
|
|
5 |
|
|
r1 |
|
|
6 |
r2 |
r2 |
r2 |
|
|
对字符串分析
ccccdcd
0 ccccdcd$
0c3 cccdcd$
0c3c3 ccdcd$
0c3c3c3 cdcd$
0c3c3c3c3 dcd$
0c3c3c3c3d4 cd$
0c3c3c3c3C6 cd$
0c3c3c3C6 cd$
0c3c3C6 cd$
0c3C6 cd$
0C2 cd$
0C2c3 d$
0C2c3d4 $
0C2c3C6 $
0C2C5 $
0S1 $
0acc $