判断LL(1)文法(first集、follow集、select集)

**

LL(1)文法判别

**

LL(1)文法是根据SELECT集进行判别,如果相同左部产生式的SELECT交集都为空,则是LL(1)文法,否则不是LL(1)文法。


FIRST集判断

如A->aB | CD

①以终结符开头,把这个终结符a放到A的FIRST里
②以非终结符开头且此非终结符 推不出 ε,把C的FIRST放到A的FIRST里
③如果 C->ε 把FIRST( C )-{ε}放入FIRST(A)中,把C之后D字符的FIRST集放入A的FIRST集里,如果 D->ε 把FIRST( C )-{ε}放入FIRST(A)中,把D之后的字符FIRST集放入A的FIRST集里,依次类推,如果D后面没有字符则把ε加人入A的FIRST集里。

比如:
文法:
S→ABc
A→a|ε
B→b|ε

因为 A->a ,A->ε,所以FIRST(A)={a,ε};
因为B->b ,B->ε,所以把FIRST(B)={b,ε};
因为S->ABc, A->ε,B->ε ,A后面有B,B后面有个终结符c
所以FIRST(S) = (FIRST(A) - {ε})∪(FIRST( B )-{ε})∪{c}

再如:
*文法:
S→AB
A→a|ε
B→b|ε

因为 A->a ,A->ε,所以FIRST(A)={a,ε};
因为B->b ,B->ε,所以把FIRST(B)={b,ε};
因为S->ABc, A->ε,B->ε ,A后面有B,B后面没有字符
所以FIRST(S) = (FIRST(A) - {ε})∪(FIRST(B)-{ε})∪{ε}


FOLLOW集判断

如S->(L) | aL | LC

①如果S为开始符号,把{#}加入FOLLOW(S)中
②如果L后面为终结符 ‘)’ ,把{ ) }加入到FOLLOW(L)中
③如果L后面是非终结符 C,把(Fisrt( C )-{ε})加入到FOLLOW(L)中
④如果L处于尾部,把 -> 左部S的FOLLOW(S)加入到FOLLOW(L)中

比如:
文法:
S→ABc
A→a|ε
B→b|ε

对于 S->ABc
符合①把{#}加入FOLLOW(S)中
符合②把{c}加入到FOLLOW(B)中,因为B->ε 即可推出S->Ac,所以把{c}加入FOLLOW(A)中
符合③把(FIRST(B)-{ε})加入到FOLLOW(A)中
不符合④

对于A->a,A->ε,B->b,B->ε
不符合①
不符合②
不符合③
不符合④

所以
FOLLOW(S)={#}
FOLLOW(A)={b,c}
FOLLOW(B)={c}

再如:
文法G [S]为:
S→AB
S→bC
A→ε
A→b
B→ε
B→aD
C→AD
C→b
D→aS
D→c

FIRST集为:
FIRST(S)={a,b,ε}
FIRST(A) = {b,ε}
FIRST(B)={a,ε}
FIRST( C)={a,b,c}
FIRST(D)={a,c}

FOLLOW(S)={#}∪FOLLOW(D)={#}
FOLLOW(A)=(FIRST(B)-{ε})∪FOLLOW(S)∪FIRST(D)={a,#,c}

提示:因为S->AB,B->ε, 推出 S->A符合④ ,把左部的FOLLOW(S)加入到FOLLOW(A)中

FOLLOW(B)=FOLLOW(S)={#}
FOLLOW©=FOLLOW(S)={#}
FOLLOW(D)=FOLLOW(B)∪FOLLOW©={#}

SELECT集判别

给定上下文无关文法的产生式A→α, A∈VN,α∈V*, ①若α不能推导出ε,则SELECT(A→α)=FIRST(α)   
②如果α能推导出ε则:SELECT(A→α)=(FIRST(α) –{ε})∪FOLLOW(A)
需要注意的是,SELECT集是针对产生式而言的。

SELECT(S->AB)=(FIRST(AB)-(ε))∪FOLLOW(S) = {b,a,#)
SELECT(S→bC)=FIRST(bC) = {b}
SELECT(A→ε)=(FIRST(ε) –{ε})∪FOLLOW(A)={a,b,#}
SELECT(A→b)=FIRST(b)={b}
SELECT(B→ε)=(FIRST(ε) –{ε})∪FOLLOW(B)={#}
SELECT(B→aD)=FIRST( aD ) = {a}
SELECT(C→AD)=FIRST( AD )={a,b,c}
SELECT(C→b)=FIRST( b )={b}
SELECT(D→aS)=FIRST( aS ) ={a}
SELECT(D→c)=FIRST ( c ) ={c}

根据SELECT集判别LL(1)文法

左部相同产生式做交集

SELECT(S→AB)∩SELECT(S→bC)={b,a,#}∩{b}={b}≠ф   
SELECT(A→ε)∩SELECT(A→b)={a,c,#}∩{b}=ф   
SELECT(B→ε)∩SELECT(B→aD)={#}∩{a}=ф   
SELECT(C→AD)∩SELECT(C→b)={b,a,c}∩{b}={b}≠ф   
SELECT(D→aS)∩SELECT(D→c)={a}∩{c}=ф

由LL(1)文法定义知该文法不是LL(1)文法,因为关于S和C的相同左部,其产生式的SELECT集的交集不为空。

LL(1)文法是根据SELECT集进行判别,如果相同左部产生式的SELECT交集都为空,则是LL(1)文法,否则不是LL(1)文法。

本程序的所用的存储结构都是string类型的,最主要的存储文法的数据结构为自定义结构,里面包括一个产生式的左部,右部以及select合,至于非终结符的first和follow合,则是定义了一个string类型的数组进行存储。 本程序的求first,followselect合的算法即为书上所介绍的方法,即求first的合时,只看本产生式,求follow合时,要进行递归查找一个非终结符的所有后跟字符,求select其实就是对first与follow合的运算,最终根据所有的select合,便可以判断文法是否为LL(1)文法。 对于不是LL(1)文法的产生式,本程序在判断后进行转换,先进行消除左递归,然后提取左公因子,在这两步的每一步结束之后,都要对产生式进行整合,去掉空存储,去掉无法到达的产生式,将select全部置空。 每进行一次非LL(1)到LL(1)的转换之后,都要对其文法性质进行判断,如果是LL(1),则跳出,不是则继续,但是当循环一定次数之后仍不是,程序判定其无法转换,也要跳出。 其中还有对第一个非终结字符的右部替换与否进行选择,原因是,有些通过替换就可以很方便的进行转换,这个要通过人为进行输入。 提取公因子中也有上一段所说的类似的判断机制,目的是为了防止文法的左公因子无法提取完的情况出现。 最终有三种结果,一种是是LL(1)文法,一种是不是LL(1),但是经过转换变成了LL(1),还有一种是经过转换也无法变成LL(1)。 输入文本格式样例: A A->ad A->Bc B->aA B->bB
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

内存不足°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值