语法分析和语法分析程序

语法分析和语法分析程序

自顶向下

特点:

  1. 无左递归
  2. 不能有回溯
  3. 指出错误位置

理论基础

消除左递归

情况一、 消除直接左递归

方法一

A->Aα|β等价改写为A->β{α}

方法二

A->Aα|β等价改写为A->βA'A'->αA'|ε

情况二、 消除间接左递归

A->Bα|βB->Aγ转化为A->Aγα|β,变为情况一

消除回溯

将情况相同的都归为同一类

LL(1) 文法:

对每个产生式A->γ1|γ2|...|γm

  1. FIRST(γi)FIRST(γj)的交集为空集(1<=i,j<=m;i!=j)
  2. γj=>...=>ε,则FIRST(γi)FOLLOW(A)的交集为空集(i=1,2,...,m;i!=j)

代码实现

递归下降分析法(对应消除左递归)

指对文法的每一非终结符号,都根据相应的产生式各候选式的结构,为其编写一个子程序(或函数),用来识别该非终结符号所表示的语法范畴。

[ 例1 ]

对于文法G[E]:

  1. E->T|E+T
  2. T->F|T*F
  3. F->(E)|i

[ 解 ] 消除左递归(方法二):

  1. E->TE'
  2. E'->+TE'|ε
  3. T->FT'
  4. T'->*FT'|ε
  5. F->(E)|i

代码实现(伪代码):

def E():
    if (match(T)):
        T()
        EE()
        print("语句正确!")
    else:
        error()
        
def EE():
    if(match(PLUS)):
        PLUS()
        T()
        EE()
      
# 剩余的就不再赘述
def T():
    none
    
def TT():
    none
    
def F():
    none
改进的递归下降分析法(对应消除左递归)

[ 同例1 ]

对于文法G[E]:

  1. E->T|E+T
  2. T->F|T*F
  3. F->(E)|i

[ 解 ] 消除左递归(方法一):

  1. E->T{+T}
  2. T->F{*F}
  3. F->(E)|i

代码实现(伪代码):

def E():
    if (match(T)):
        T()
        while (match(PLUS)):
            T()
        print("语句正确!")
    else:
        error()
        
      
# 剩余的就不再赘述
def T():
    none
    
def F():
    none
预测分析法(对应消除回溯)

关键是构造LL(1)分析表

(I) 前置知识

构建FIRST集和FOLLOW集:

构建FIRST集算法:

  1. X∈VT,则FIRST(X)={X}
  2. X∈VN,且有X->aα∈P (a∈VT)则令a∈FIRST(X);若有X->ε∈P则令ε∈FIRST(X)
  3. X->Y1Y2...Yk∈P
    1. Y1∈VN则令FIRST(Y1)-{ε}⊆FIRST(X)
    2. 对于所有j(1<=j<=k-1),Yj∈VN,且Yj=>...=>ε,则令FIRST(Yj)-{ε}⊆FIRST(X) (1<=j<=k)
    3. 特别的当ε∈FIRST(Yj) (1<=j<=k)时,令ε∈FIRST(X)

构建FOLLOW集算法:

  1. 对于文法开始符号S,令#∈FOLLOW(S)
  2. 对于每一A->αBβ∈P,令FIRST(β)-{ε}⊆FOLLOW(B)
  3. 对于每一A->αB∈P,或A->αBβ∈P,且ε∈FIRST(β),则令FOLLOW(A)⊆FOLLOW(B)
  4. 反复使用本规则,直到集合不再增大为止。

(II) 构建预测分析表:

表元素M[A,a] (A ∈ VN,a ∈ VT ∪ {#})按下述规则确定。

对于文法中的每一个产生式A->γ1|γ2|...|γm

  1. a∈FIRST(γi),则置M[A,a]="A->γi"
  2. ε∈FIRST(γi),且a∈FOLLOW(A),则置M[A,a]="A->γi"
  3. 其余都置出错。

(III) 分析器的工作流程:

一、初始化

分析栈余留符号串
#Sa1a2...an#

二、在某一时刻,有以下格局:

分析栈余留符号串
#X1X2...Xm-1Xmaiai+1...an#
  1. Xm∈VT∪{#},且Xm=ai,则将Xm出栈,并将输入串前进一位,否则报错;
  2. Xm∈VN,则以符号对(Xm,ai)查分析表,设表元素A[Xm,ai]为产生式Xm->Y1Y2...Yk,则将Xm出栈,将Y1Y2...Yk反序入栈,从而得到下面的格局。若A[Xm,ai]为报错,则报错;
  3. Xm=ai=#,则分析成功。
分析栈余留符号串
#X1X2...Xm-1YkYk-1...Y1aiai+1...an#

[ 同例1 ]

对于文法G[E]:

  1. E->T|E+T
  2. T->F|T*F
  3. F->(E)|i

分析符号串i+i*i

[ 解 ] 消除左递归(方法二):

  1. E->TE'
  2. E'->+TE'|ε
  3. T->FT'
  4. T'->*FT'|ε
  5. F->(E)|i

FIRST集和FOLLOW集:

FIRST(E)={(,i}

FIRST(E')={+,ε}

FIRST(T)={(,i}

FIRST(T')={*,ε}

FIRST(F)={(,i}

FOLLOW(E)={),#}

FOLLOW(E')={),#}

FOLLOW(T)={+,),#}

FOLLOW(T')={+,),#}

FOLLOW(F)={+,*,),#}

构造LL(1)分析表:(注:终结符号用#表示)

i+*()#
EE->TE'E->TE'
E'E'->+TE'E'->εE'->ε
TT->FT'T->FT'
T'T'->εT'->*FT'T'->εT'->ε
FF->iF->(E)

空白部分,报错。

编写程序:

# 略

进行预测分析(过程如下表):

步骤分析栈余留符号串所用产生式
1#Ei+i*i#E->TE'
2#E'Ti+i*i#T->FT'
3#E'T'Fi+i*i#F->i
4#E'T'ii+i*i#
5#E'T'+i*i#T'->ε
6#E'+i*i#E'->+TE'
7#E'T++i*i#
8#E'Ti*i#T->FT'
9#E'T'Fi*i#F->i
10#E'T'ii*i#
11#E'T'*i#T'->*FT'
12#E'T'F**i#``
13#E'T'Fi#F->i
14#E'T'ii#
15#E'T'#T'->ε
16#E'#E'->ε
17##分析成功

自底向上(移进-归约)

关键是求句柄

优先分析法

简单优先分析法

暂略

局限性:对文法要求太强

算符优先分析法(有二义性)

暂略

LR分析法

类似于LL(1),LR分析法也是需要一个输入符号串,一个下推分析栈,一个总控程序和分析表。

显然,关键就在于分析表的构建。(分析表本质上是为了寻找句柄)

以下仅展示分析表的构建方法和总控程序。

LR(0)分析法

(I) 前置知识:

规范句型的活前缀:规范句型(没有语法错误的句型)不含句柄之右的前缀

·:为刻画在分析过程中,文法的一个产生式的右边有多少被识别,可以在右部加一个圆点“·”来表示位置。如:A->β·A->·α等。

LR(0)项目:

假设G[S],为方便描述,引入第0个产生式S'->S

  1. 归约项目:下一步要进行规约。如A->α·
  2. 接受项目:表明整个分析已经成功完成。如S'->S·
  3. 移进项目:下一步将当前输入符号移入栈中。如A->α·aβ
  4. 待约项目:下一步将从余留符号串进行归约。如A->α·Bβ

(II)构造DFA:

  1. S->·S'列入初态I0中,对其进行闭包运算I0=CLOSURE({S->·S'})
  2. 若I0中有A->α·Xβ,则其后面的状态Ii必含有全部形如A->αX·β的项目(后继项目)。设后继项目的集合为J,则Ii=CLOSURE(J)。此时我们 可以定义Ii = GO(I,X)=CLOSURE(J),其中Ii为后继状态,I为当前状态,X为文法符号,J就是后继项目集合。

注:求CLOSURE(I)的方法

  1. I中每一个项目都属于CLOUSER(I);
  2. 若形如A->α·Xβ的项目属于CLOUSER(I),且X为非终结符号,则文法中任何X-产生式的一切圆点在最左边的项目X->·γ也都属于CLOSURE(I);
  3. 重复上述过程,直到不再有新的项目加入为止。

此时G[S]的DFA为M=(C,V,GO,I0,C) (C={I0,I1,...In})

项目集相容:在一个项目集中不会出现

  1. 移进项目和归约项目共存。
  2. 多个归约项目共存。

(III)构造分析表:

构造分析表的方法如下:

  1. 对于Ii中形如A->α·Xβ的项目,若GO(Ii,X)=Ij,且X为终结符号a时,置[i,a]=sj。若X为非终结符时,置[i,X]=j
  2. 若归约项目A->α·属于Ii,设A->α为文法的第j个产生式,则对文法的任何终结符号或句子的右介符#(将他们统一记为a),置[i,a]=rj
  3. S'->S·属于Ii,则置[i,#]=acc
  4. 其余置出错。

注:

si:移入,并转换到Ii状态。

ri:按第i个产生式进行归约。

acc:分析成功。

[ 例2 ]

对于文法G[S]:

  1. S->A
  2. S->B
  3. A->aAb
  4. A->c
  5. B->aBb
  6. B->d

构造LR(0)分析表。

[ 解 ] 改写成拓展文法G[S']

  1. S'->S

  2. S->A

  3. S->B

  4. A->aAb

  5. A->c

  6. B->aBb

  7. B->d

求DFS的每个节点,并绘制DFS:

S
A
B
a
c
d
a
c
d
A
B
b
b
I0:
S'->.S
S->.A
S->.B
A->.aAb
A->.c
B->.aBb
B->.d
I1:S'->S.
I2:S->A.
I3:S->B.
I4:
A->a.Ab
A->.aAb
A->.c
B->a.Bb
B->.aBb
B->.d
I5:A->c.
I6:B->d.
I7:A->aA.b
I8:A->aAb.
I9:B->aB.b
I10:B->aBb.

显然,每一项目集是相容的。

做出LR(0)分析表

abcd#SAB
0s4s5s6123
1acc
2r1r1r1r1r1
3r2r2r2r2r2
4s4s5s679
5r4r4r4r4r4
6r6r6r6r6r6
7s8
8r3r3r3r3r3
9s10
10r5r5r5r5r5

总控程序将在本大节末介绍。

SLR(1)分析法

(I) 构造DFA:同LR(0)

(II) 构造分析表:

构造分析表的方法如下:(对比与LR(0)的不同)

  1. 对于Ii中形如A->α·Xβ的项目,若GO(Ii,X)=Ij,且X为终结符号a时,置[i,a]=sj。若X为非终结符时,置[i,X]=j
  2. 若归约项目A->α·属于Ii,设A->α为文法的第j个产生式,则对于任何属于FOLLOW(A)的输入符号a,置[i,a]=rj
  3. S'->S·属于Ii,则置[i,#]=acc
  4. 其余置出错。

[ 改例2.1 ]

对于文法G[S]:

  1. S->A
  2. S->B
  3. A->aAb
  4. A->a
  5. B->aBb
  6. B->d

构造SLR(1)分析表。

[ 解 ] 改写成拓展文法G[S']

  1. S'->S

  2. S->A

  3. S->B

  4. A->aAb

  5. A->a

  6. B->aBb

  7. B->d

求DFS的每个节点,并绘制DFS:

S
A
B
a
d
a
d
A
B
b
b
I0:
S'->.S
S->.A
S->.B
A->.aAb
A->.a
B->.aBb
B->.d
I1:S'->S.
I2:S->A.
I3:S->B.
I4:
A->a.Ab
A->a.
A->.aAb
A->.a
B->a.Bb
B->.aBb
B->.d
I5:B->d.
I6:A->aA.b
I7:A->aAb.
I8:B->aB.b
I9:B->aBb.

做出SLR(1)分析表

abd#SAB
0s4s6123
1acc
2r1
3r2
4s4r4s6r468
5r6r6
6s7
7r3r3
8s9
9r5r5

对比SR(0):

abcd#SAB
0s4s5s6123
1acc
2r1r1r1r1r1
3r2r2r2r2r2
4s4,r4r4s5,r4s6,r4r468
5r6r6
6s7
7r3r3r3r3r3
8s9
9r5r5r5r5r5
LR(1)分析法

(I) 前置知识:

向前搜索符a:指针向前扫视的一个符号。

(II) 构造DFA:

略。

求CLOSURE(I)的方法:

  1. I中每一个项目都属于CLOUSER(I);
  2. 设项目[A->α·Bβ,a]∈CLOSURE(I),并假设它对活前缀γ=δα有效,则对文法中所有形如B->η的产生式和每一个b∈FIRST(βα),形如[B->·η,b]的全部项目也要对γ有效,故若[B->·η,b]原不在CLOSURE(I)中,则应将其放入。
  3. 重复上述过程,直到不再有新的项目加入为止。

(III) 构造分析表:

构造分析表的方法如下:

  1. 对于Ii中形如[A->α·Xβ,b]的项目,若GO(Ii,X)=Ij,且X为终结符号a时,置[i,a]=sj。若X为非终结符时,置[i,X]=j
  2. 若归约项目[A->α·,a]属于Ii,设A->α为文法的第j个产生式,置[i,a]=rj
  3. [S'->S·,#]属于Ii,则置[i,#]=acc
  4. 其余置出错。

[ 改例2.2 ]

对于文法G[S]:

  1. S->A
  2. S->Bb
  3. A->aAb
  4. A->a
  5. B->aBa
  6. B->a

构造LR(1)分析表。

[ 解 ] 改写成拓展文法G[S']

  1. S'->S

  2. S->A

  3. S->Bb

  4. A->aAb

  5. A->a

  6. B->aBa

  7. B->a

求DFS的每个节点,并绘制DFS:

S
A
B
b
a
a
a
A
b
B
a
A
b
B
a
I0:
S'->.S,#
S->.A,#
S->.Bb,#
A->.aAb,#
A->.a,#
B->.aBa,b
B->.a,b
I1:S'->S.,#
I2:S->A.,#
I3:S->B.b,#
I4:S->Bb.,#
I5:
A->a.Ab,#
A->a.,#
A->.aAb,b
A->.a,b
B->a.Ba,b
B->a.,b
B->.aBa,a
B->.a,a
I6:
A->a.Ab,b
A->a.,b
A->.aAb,b
A->.a,b
B->a.Ba,a
B->a.,a
B->.aBa,a
B->.a,a
I7:A->aA.b,#
I8:A->aAb.,#
I9:B->aB.a,b
I10:B->aBa.,b
I11:A->aA.b,b
I12:A->aAb.,b
I13:B->aB.a,a
I14:B->aBa.,a

对比SLR(1):

S
A
B
b
a
a
A
B
b
b
I0:
S'->.S
S->.A
S->.Bb
A->.aAb
A->.a
B->.aBa
B->.a
I1:S'->S.
I2:S->A.
I3:S->B.b
I4:S->Bb.
I5:
A->a.Ab
A->a.
A->.aAb
A->.a
B->a.Ba
B->a.
B->.aBa
B->.a
I6:A->aA.b
I7:A->aAb.
I8:B->aB.a
I9:B->aBa.

做出LR(1)分析表:

ab#SAB
0s5123
1acc
2r1
3s4
4r2
5s6r6r479
6s6,r6r41113
7s8
8r3
9s10
10r5
11s12
12r3
13s14
14r5

对比SLR(1):

ab#SAB
0s5123
1acc
2r1
3s4
4r2
5s5,r6r4,r6r468
6s7
7r3r3
8s9
9r5r5
LALR(1)分析法

(I) 前置知识:

同心集:每个LR(1)项目由两部分组成。1.核:LR(0)项目。2.向前搜索符号集。除了搜索符号集不同外,核都相同的两个LR(1)项目集就是同心集。

(II)先构造LR(1),然后在不会产生冲突的情况下合并同心集。其余同LR(1)。

[ 同例1 ]

对于文法G[E]:

  1. E->T|E+T
  2. T->F|T*F
  3. F->(E)|i

构建LALR(1)分析表。

[ 解 ] 略。


注:本文只是记录课上所学,供大家共同学习。
作者:那么神奇

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值