提示:学习本文章之前,建议先学会FIRST集。因为求FOLLOW集经常要用到FIRST集。
提示:本文建议先看例题,有不懂的地方再结合相应的文字部分。
先讲3个概念:
非终结符就是大写字母。
终结符就是非终结符以外的所有符号(注意是符号,而不只局限于字母,终结符包括小写字母,数字,加号,减号,逗号等等)。
代入:对于产生式S → ABc, 箭头两侧是等价的,当箭头右部出现S时,就可以用ABc等价代替,可以方便地称为“代入”,这个做题时很好用。代入是用箭头右部代替左部,不能用左部代替右部。
为什么叫FOLLOW集?
follow的意思就是“跟随”。所以求符号A的FOLLOW集,就是求出这个符号A后面能跟些什么,也就是求跟随A的元素都有哪些。注意,并不是跟在A后面的所有元素都是它的FOLLOW集,我们只要A后面的且与A能够相邻的。注意这里的用词,是“ 能够相邻的 ”,而不是“ 相邻的 ”,有什么不同呢?可以理解为“ 相邻的 ”是“ 能够相邻的 ”的子集。比如给出这样一个串“ ADBfj ”,f本来并不与A相邻,但我可以通过D → ε使原来的串变为“ ABfj ”,那么继续再加一个式子B → ε使得式子变成“ Afj ”,也就是通过一系列代入 f 成功上位成为了A的小跟班,从此过上了FOLLOW集的生活。
这里先简单了解一下,等会再回来看,下面步入正题。
怎么求FOLLOW集?
给出文法如下:
S → ABc
A → a|ε
B → b|ε
每一个文法都一定有一个开始符号。开始符号一般是一个非终结符,那么怎么找开始符号呢?
开始符号特点:只出现在箭头左侧。
就拿上面的文法举例,出现在箭头左侧的有S,A,B,其中在箭头左侧出现的只有S,所以S是开始符号。
注意:如果是增广文法,里面会有一句文法,形如S’ → S,箭头右侧的就是开始符号,也就是S(这个在学FOLLOW集阶段用不到,但在后面学LR(0)自动机时会遇到,现在可以作为了解)。
求FOLLOW集的步骤:
0.如果文法是增广文法,先去掉S’->S这个式子,在剩下的文法中求FOLLOW集(初学者先忽略,不影响)。
1.找开始符号。
2.在开始符号的FOLLOW集中写入#(或者$),这是规定。
3.对所有非终结符逐个分析,分析能不能最终推出ε,也就是“非终结符 → ε”的形式,将这些非终结符列举出来。
对步骤3举例:
S → AB
A → a|ε
B → b|ε
S最终能够推出 ε。因为S → AB, 而A → ε,所以变成了S → B,又因为B → ε,所以变成了S → ε。当然,显而易见本题A和B也能最终推出ε。
这个过程并不难理解,只是有些繁琐,一步一步代入即可。
注意:
接下来的所有步骤都只需在箭头右部找。
4.找出含有所求符号的所有式子。(只在箭头右侧部分中找)
5.对步骤4的每个式子单独分析,找出这个串中与所求符号能够相邻的所有符号(只找右相邻的,不找左相邻);但有的式子中所求符号就在最右侧,右边就没有任何相邻的,这种情况用步骤6解决。
记住这是步骤5,因为需要再看一遍上面的“ 为什么叫FOLLOW集 ”那一段文字。
6.分析这些能够相邻的符号,如果是终结符,直接写入所求符号的FOLLOW集;如果是非终结符,将该非终结符的FIRST集写入所求符号的FOLLOW集。(注意FOLLOW集中不能出现ε ,所以将FIRST集写入FOLLOW集时注意去掉ε,这是规定 )
7.如果有的式子中所求符号就在最右侧。把这个式子箭头左侧符号的FOLLOW集写入所求符号的FOLLOW集中,如果箭头左侧就是所求符号,那么就不用写任何东西。
7.对,这一步仍然是第7步。十分的特殊。这个特殊性就和上面提到的 “ 相邻的 和能够相邻的 ”一样。这里是“最右侧和能够最右侧”。最右侧就是上面那个第7步讲的。那么“能够最右侧”是什么意思呢?其实就是本来不是在最右侧,不过经过一系列代入后,就能够变成最右侧。
步骤7“能够最右侧”例题:
S → BH
H → a
H → ε
B → b直观的看,现在B不是最右侧的情况,不过因为 H → ε ,代入S → BH中得到S → B,这就变成了“最右侧”。
那么,做题的时候我就都要代入挨个的试吗?并不是的:首先,如果B右侧的串存在终结符,那么最终B一定不会成为“最右侧”,比如S → BHe此时不用代入。那如果全是非终结符怎么办?比如S → BHYJI , 因为第3步列举了一些非终结符,如果B右侧的串中存在这些非终结符以外的符号,同样也不会变成“最右侧”。不满足以上这两条,就是B最终“能够最右侧”。由此可见第3步的重要性。
想知道为什么吗?按照这个步骤多做题,很快就能思考出来,现在先跟着我做道例题。
最后强调一点:FOLLOW集不能出现ε。
最最后强调一点:FOLLOW集不能出现ε。
重要的事情说三遍:FOLLOW集不能出现ε。
这7条步骤先浏览一遍即可,结合实践,在做题中学习理解,上例题。
例题:已知文法G和FIRST集,求FOLLOW集
终结符 | FIRST集 |
---|---|
S | d,e,ε,b,a |
H | e,ε |
K | d,ε |
L | e |
M | d,ε,b |
题目文法等价于:
S → MH
S → a
H → LSo
H → ε
K → dML
K → ε
L → eHf
M → K
M → bLM
按照上面的步骤来:
1.开始符号是S
2.FOLLOW(S)={#}
3.最终能推出ε的非终结符有:S , H , K , M。如果有疑问,去读一下上面的步骤3举例那个例子。先求S的FOLLOW集:
4.含有S的式子有:H → LSo
5.能够相邻的只有o
6.o是终结符,FOLLOW(S)={#,o}
再求H的FOLLOW集:
4.含有H的式子有:S → MH , eHf
5.能够相邻的有f
6.f是终结符,FOLLOW(H)={f}
7.S → MH中H在最右部,FOLLOW(H)={f , FOLLOW(S)} , 将FOLLOW(S)代入即可。FOLLOW(H)={#,o , f}
求K的FOLLOW集:
4.含有K的式子有:M → K
5.没有相邻的
6.
7.M → K中K在最右侧,FOLLOW(K)={ FOLLOW(M) },因为FOLLOW(M)还没有求出来,等会再代入。
求L的FOLLOW集:
4.含有L的式子:H → LSo,K → dML,M → bLM
5.能够相邻的:S,o , M
6.o是终结符,写入L的FOLLOW集;S,M都是非终结符,将FIRST(S)和FIRST(M)写入L的FOLLOW集。(除去ε )
7.根据K → dML,将FOLLOW(K)写入FOLLOW(L), 对于M → bLM,因为L的右侧有非终结符M,且M出现在步骤3里面,所以M → bLM可以写成M->bL,所以将FOLLOW(M)写入FOLLOW(L)。因为FOLLOW(M)还没有求出来,等会再代入。
求M的FOLLOW集:
4.含有M的式子:S → MH, K → dML, M → bLM
5.能够相邻的:H, L
6.将FIRST(H)和FIRST(L)写入FOLLOW集。(除去ε )
7.M → bLM,因为箭头左侧就是M,所以不用写。但是通过S → MH,可以得到S → M,所以将FOLLOW(S)写入。
最终答案见下表:
非终结符 | FOLLOW集 |
---|---|
S | # , o |
H | #,o , f |
K | e , # , o |
L | a , b , d , e , o, # |
M | e , # , o |
练习题:
答案: