终结符:ε、a、b、c、d、+、-、*、/、,等非大写字母
非终结符:A、B、C、D、S、… 大写字母。
核心理念:first(A) A能推出的第一个是什么。
结果的取值范围:终结符,即非大写字母。答案要写成一个集合。
G[A]:
A---->aB|ε
A---->c
解析:因为A能推出的第一个字符是a、ε、c,且都是非大写字母(都是终结符),所以可以直接得到
first(A)={a,ε,c}
竖线 | 表示或
G[A]:
A-----> Bc | ε
B ------>b | ε
解析:A能推出的第一个字符是B,B是大写字母,即是非终结符,我们要利用产生式(规则)对B进行替换,
得到 A---->bc | ε | εc, 由于 εc 可以化简成 c,所以得到 A---->bc | ε | c。 可以看出,A能推出的第一个字符是b、 ε 、c,且都是非大写字母,所以,first(A)={b,ε,c}
因为B能推出的第一个字符是 b、ε,所以first(B) = {b,ε}
掌握:替换
G[S] :
S ----> ABc
A------>a | ε
B -------> b | ε
答案 | |
---|---|
first(S) | {a,b,c} |
frst(A) | {a,ε} |
first(B) | {b,ε} |
解析first(S):
S-----> ABc,将A和B都进行替换,得到 S------>abc | aεc | εbc | εεc ,即 S------>abc | ac | bc | c
替换过程:就是A取a时,B可以取b或 ε; A取ε时,B可以取b或ε。就是小学学的排列组合
所以,first(S)={a,b,c}
first(A) 和 first(B)很简单,不赘述。
G[A] :
A------> BC
B------>b | ε
C ------->c|ε
答案 | |
---|---|
first(A) | {b,c,ε} |
first(B) | {b,ε} |
first© | {c,ε} |
解析first(A):A----->BC,对B和C都进行替换, A---->bc| bε | εc | εε ,即 A------> bc | bε | c | ε
注:εc 为什么能变成 c,因为 ε后面有个终结符c,而ε代表空串,所以εc可以变成c。
所以,first(A) = {b,c,ε}
G[E]:
E-------> TE’
E’------> +TE’ | ε
T--------> FT’
T’----------> *FT’ | ε
F ------------>(E) | i
答案 | |
---|---|
first(E) | { ( , i } |
first(E’) | { + , ε } |
first(T) | { ( , i } |
first(T’) | { *, ε } |
first(F) | { (, i } |
解析:做完前面的例题,你应该会求first了,就是看能推出的第一个是啥,如果是大写字母(非终结符),则要对其进行替换。
所以,first(E)= { (, i}
所以,first(E’)={ + ,ε }
T ==> F ==> ( | i
所以,first(T) = { ( , i}
T’ ==> * | ε
所以,first(T’)= { ( ,i }
F ==> ( | i
所以,first(F) = { ( , i }
空就是 ε 。 式子就是产生式。
规则②的第二种情况其实和规则①的情况是一样的,因为,当东西推出ε 时,就代表着A后面没有东西,所以,将follow(左)加入
规则②的情况1,如果A后面的东西是终结符(即非大写字母)可以直接加入。
规则②的情况1,如果first(东西)的集合里有 ε ,则
重点:如果求开始符的follow集,必须要将 # 加入。(记住就行,想了解原因的可以去看课本。)
一定要想求出first集,再去求follow集,因为求follow集的时候要用到first集
G[S] :
S ----> ABc ①
A------>a | ε ②
B -------> b | ε ③
为了方便说明,我给每一个产生式标了序号。
答案 | |
---|---|
first(S) | {a,b,c} |
frst(A) | {a,ε} |
first(B) | {b,ε} |
答案 | |
---|---|
follow(S) | { #} |
follow(A) | {b,c} |
follow(B) | {c} |
解析:
follow(S): 因为S是开始符,所以,将 # 加入。然后再看S在哪个产生式的右边出现,发现这3个产生式的右边都没有S出现。所以,follow(S) = { #}
follow(A): 发现A在产生式①的右边出现,A后面有东西,即A后面是B,我们由③可以知道,B可以推出b(非空),也可以推出空 ε ,所以,
当B推不出空时,将first(B)除去ε后加入.
当B推出空时,由于后面有个c,所以,此时相当于变成 S ---->Ac,此时 A后面有东西,所以,将终结符c加入
综上follow(A) = { first(B)除去ε , c} = {b,c }
这题有坑,有些人可能会写成 {b,#},做错的原因就是: 当B推出空时,你没看到后面有个c,你直接把follow(S) 加入了,所以就错写成了 {b,#}
follow(B):发现B在产生式①的右边出现,B后面有个终结符c,所以,将c加入。所以,follow(B) = {c}
G[E]:
E-------> TE’
E’------> +TE’ | ε
T--------> FT’
T’----------> *FT’ | ε
F ------------>(E) | i
先求出first集合
答案 | |
---|---|
first(E) | { ( , i } |
first(E’) | { + , ε } |
first(T) | { ( , i } |
first(T’) | { *, ε } |
first(F) | { (, i } |
再求follow集合
答案 | |
---|---|
follow(E) | {#,)} |
follow(E’) | {#,)} |
follow(T) | {+,#,)} |
follow(T’) | {+,),#} |
follow(F) | {*,+,),#} |
注:因为是集合,所以,里面字符的是无序的。字符是不重复的。和java里的Set是一样的。
解析:
G[E]:
E-------> TE’
E’------> +TE’ | ε
T--------> FT’
T’----------> *F T’ | ε
F ------------>(E) | i
follow(E):E只在 F ------------>(E) | i
这个式子的右边出现。由于E的右边是),是一个终结符,所以,直接将)加入。又因为E是开始符,所以将#加入。所以,follow(E)={#, ) }
follow(E’): E’ 在下面两个式子的右边都出现过,所以,两个式子都要看一下。
E-------> TE‘
E’------> +TE’ | ε
对于 E-------> TE‘ ,由于 E‘ 后面没东西,所以,将follow(E)加入,
对于 E’------> +TE’ | ε,由于E‘ 后面没东西,所以,将follow(E’) 加入。因为咱求得是follow('),所以此时就是自己加入自己,对于集合来说,重复的元素是无意义的。
综上,follow(E’)={#,)}
follow(T): T只在下面两个式子的右边出现。
E-------> TE’
E’------> +TE’ | ε
对于E-------> TE’: T的后面有东西,是E’, 但是,我们要判断一下E’能否推出 ε。由式子 E’------> +TE’ | ε可以知道,E’可以推出非空 也可以推出空。当E’ 推出非空时,将first(E’) 这个集合去掉空后加入;当E’ 推出空时,将follow(E)加入.
对于, E’------> +TE’ | ε ,T的后面有东西,是E’,结果和上面一样,重复的元素加入集合中是没意义的。
综上,follow(T)={+,#,)}
follow(T’):T’只在下面两个式子的右边出现。
T--------> FT’
T’----------> *F T’ | ε
与求follow(T)一样,只要follow(T)会求,这个也必会,不赘述。
follow(T’) = {+,),#}
follow(F):F只在下面这个式子的右边出现。
T--------> FT’
F的右边有东西,是T’, 由 T’----------> *F T’ | ε我们可以知道,T’能推出空和非空。
当T’ 推出非空时,将first(T’)加入
当T’ 推出空时,将follow(左)加入,即将follow(T)加入。
与求follow(T)一样,只要follow(T)会求,这个也必会,不赘述。
follow(T’) = {+,),#}
T--------> FT’
F的右边有东西,是T’, 由 T’----------> *F T’ | ε我们可以知道,T’能推出空和非空。
当T’ 推出非空时,将first(T’)加入
当T’ 推出空时,将follow(左)加入,即将follow(T)加入。