FIRST集
FIRST集
1.什么是FIRST集?
一个符号的FIRST集表示一个符号或句型可以推导出的句子的首符号的集合。
举个例子:A→aa|bb|cc。a,b,c是终结符,则FIRST(A)={a,b,c}
通过上面的定义解释一下,符号A可以推导出三个句子{aa,bb,cc},那么,这三个句子的首符号集合FIRST(A)={a,b,c}。
2.FIRST集求法
再给出最终结论之前,首先看以下的几种情况
求一个终结符号的FIRST集
终结符号经过推导(0步推导)后,推导出自己本身,所以如果a是一个终结符号,则FIRST(a)={a}
可以推导出空串的非终结符号的FIRST集
如果一个非终结符号可以推导出空串,则有以下两种情况:
对于经过若干步可以推导出空串的非终结符号,有以下结论:
不能推导出空串的非终结符号的FIRST集
如果一个非终结符号不能推导出空串,它可以被形式的描述为:
对于上面的情况,首先FIRST(Y1)-{ε}(这里减去{ε}的原因下面说)是FIRST(X)的一个子集,因为经过推导之后,用产生式的右部(多个Y)替换了X,则第一个字符就是Y1,所以,FIRST(Y1)-{ε}是FIRST(X)的一个子集(或者说,将FIRST(Y1)-{ε}加入FIRST(X))。
减去{ε}的原因:如果Y1可以推导出ε,则ε属于FIRST(Y1),但是仅仅Y1可以推导出空串,还不足以说明X可以推导出空串,只有X可以推导出ε,才可以将ε加入FIRST集(上面讨论的情况)。Y2可能不能推导出空串,所以X就不能推导出空串。
举个例子:
如上图的例子,我们可以看到,我们上面讨论的Y1就是A,所以,FIRST(A)-{ε}是FIRST(X)的一个子集(或者说将FIRST(A)-{ε}加入FIRST(X)),因为X只有一条产生式,这个产生式有这一条“线索”,因此分析到这里,就分析结束了,也就是说FIRST(X)=FIRST(A)-{ε}。
所以,问题变成了求FIRST(A),这里,A有三个产生式,分别推导出终结符号a,b,c。也就是说,对于每一个产生式,Y1分别为a,b,c。FIRST(a)-{ε},FIRST(b)-{ε},FIRST( c)-{ε}都是FIRST(A)的子集,也就是说,FIRST(A)=FIRST(a)-{ε}+FIRST(b)-{ε}+FIRST( c)-{ε}={a,b,c}(终结符号的FIRST集就是它自己构成的集合,我们上面讨论过的)
继续分析,上面的情况,我们忽略了Y1可能推导出空串的情况。也就是说,如果将文法做一下修改,变成如下分文法:
想一下,如果X在推导过程中,A使用了空串产生式,那么,B就变成了第一个符号,因此FIRST(B)-{ε}也应该是FIRST(X)的子集。也就是说,如果Y1有空串产生式,则Y2的FIRST集-{ε}是FIRST(X)的子集。
继续进行归纳,如果Y1和Y2都有空串产生式,再将文法修改一下:
如果在X推导过程中,A和B都使用空串产生式,则C就变成了第一个符号,因此FIRST( C)-{ε}也应该是FIRST(X)的子集。也就是说,如果Y1,Y2有空串产生式,则Y3的FIRST集-{ε}是FIRST(X)的子集。
通过归纳,我们可以得到结论,设产生式X→Y1Y2Y3…Yk。则,如果Y1Y2Y3…Yi-1可以推导出空串,也就是说从Y1到Yi,每一个符号都能推导出空串,则Yi的FIRST集-{ε}是FIRST(X)的子集。Y1,Y2…Yi-1这些符号不使用空串产生式时,它们中的每一个都可能成为第一个符号,它们的FIRST集-{ε}都是FIRST(X)的子集。也就是说,对于这种情况,FIRST(X)=FIRST(Y1)-{ε}+FIRST(Y2)-{ε}+…+FIRST(Yi)-{ε}
当然,如果Y1Y2Y3…Yk可以推导出空串,也就是X推导出了空串,这就变成了我们上面讨论的情况。
3.总结
- 如果X是终结符号,则FIRST(X)={X}。
- 如果X是非终结符号,且X可以推导出ε,则将ε加入FIRST(X)。
- X→Y1Y2Y3…Yk,若ε∈FIRST(Y1Y2Y3…Yi-1)(i<k),则将(FIRST(Y1)-{ε}+FIRST(Y2)-{ε}+…+FIRST(Yi)-{ε})加入FIRST(X),否则,将(FIRST(Y1)-{ε})加入FIRST(X)。如果Y1Y2Y3…Yk可以推导出空串,则就变成了情况2。
- 补充一条规则,X→Y1Y2Y3…Yk,FIRST(X)⊇FIRST(Y1Y2Y3…Yk)
总结方法
如果要求FIRST(X),首先找到X在左部的产生式,然后对这些产生式应用上面的规则,每应用一次规则,会计算出一个FIRST集的子集,将这些子集加入FIRST(X)。
需要应用两次规则的产生式:对于X→Y1Y2Y3…Yk,如果Y1Y2Y3…Yk可以推导出ε,则就说明X可以推导出ε,因此,就可以利用规则2和规则3,也就是两条规则
举个例子:
求FIRST(E),首先,找到E在左部的产生式
可以看到,产生式的形式属于,X→Y1Y2Y3…Yk,首先,将FIRST(T)-{ε}加入FIRST(X)。(应用第三条规则,因为T不能推导出空串,所以不需要讨论E’)
问题又变成了求FIRST(T),找到T在左部的产生式,
同理,将FIRST(T)=FIRST(F)-{ε}(同样,因为F不能推导出ε,而且这里只有一条产生式,且只用了一次规则,所以,可以确定FIRST(T)=FIRST(F)-{ε})
因此,又要先求FIRST(F)
找到F在产生式左部的产生式
可以看到,F在左部的产生式有两个,因此,FIRST(F)=FIRST(()-{ε}+FIRST(i)-{ε}={(, i}FIRST(T) = FIRST(F)-{ε} = {(, i}
FIRST(E) = FIRST(E)-{ε} = {(, i}
经过上面的分析,我们得到FIRST(E)=FIRST(T)=FIRST(F)={(, i}
接下来分析稍复杂的FIRST(E’),还是那样,需要找到E’在产生式左部的产生式
有两个产生式,一个是空串产生式,应用规则3;另一个应用规则3,再将这两个结果求并集即可,FIRST(E’)={ε}+(FIRST(+)-{ε})={ε, +}
同理,FIRST(T’)={ε, *}
FIRST(E’T’)=? 句型E’T’是符合应用两次规则的句型。
第一次应用规则:应用规则3,(FIRST(E’)-{ε}+FIRST(T’)-{ε})是FIRST(E’T’)的子集。
第二次应用规则:应用规则2,又因为E’T’可以推导出空串,所以ε∈FIRST(E’T’)。
将两条“线索”得到的结果求并集,FIRST(E’T’)=FIRST(E’)-{ε}+FIRST(T’)-{ε}+{ε}={+}+{*}+{ε}={+,*,ε}