语法分析 (4)

本文详细介绍了构造LR(1)和LALR(1)语法分析表的算法过程,包括如何求克林闭包、创建项目集、构建分析表,并通过实例演示了整个分析流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

语法分析4

       主要介绍构造LR(1)LALR(1)分析表的算法:

 

LR(1)语法分析表的主要核心是求出各个状态的克林闭包,具体看龙书算法4.9

简单表达如下:

有产生式:

A -> αBβ

B -> η

当输入字符为a时表示为:

[A -> α.Bβ, a]

目的是要求出它的闭包,这个运算的最关键的步骤在于求出可接受的下一个输入字符.算法简单的描述为:

[A -> α.Bβ, a]

[B -> .η, first(βa)]

first(βa)代表,产生式βafirst集合.

依次类推知道不再有新的状态加入到该集合中为止.

例如龙书上的例子:

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函数(蓝色部分)可以确定I3I4的核项目中含有自生符号c/d(自生表中蓝色字体,灰色背景部分), 同时搜索符的传播也可以确定下来(传播表中的蓝色部分).

依照这样的做法,求出自生表和传播表(同样颜色代表自生表和传播表是有那个闭包求得的)

(注意在求I3I4的闭包的时候不要受自生表的影响,自生表是这个算法的结果,所以求闭包不要考虑)

下面根据自生表和传播表来求出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                             $

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值