编译原理FIRST集和FOLLOW集的求法
由于最近要期末考试了,所以要从头到尾复习(预习)一遍了。陈意云老师写的课本比较抽象,看不太懂,最后又找了中科大的编译原理课,可能听的时候太困了没有集中精力,又跑去看了以前曾经看过的哈工大的公开课,应该是看懂了,所以就厚颜无耻的来捋一捋,欢迎交流,批评指正。
废话不多说,直接看怎么计算的吧。
首先看FIRST集,文字描述如下:
1.FIRST(X):可以从X推导出的所有串首终结符构成的集合
如果X=>*ε,那么ε∈FIRST(X)
举个栗子
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | {} | {} |
E’-> +TE’|ε | {} | {} |
T-> FT’ | {} | {} |
T’->*FT’|ε | {} | {} |
F-> (E)|id | {} | {} |
我是这样做的,首先看有终结符的表达式F-> (E)|id可以得到FIRST(F)={(, id};
再看有终结符的表达式T’->FT’|ε,得到FIRST(T’)={*, ε}
再看E’-> +TE’|ε,得到FIRST(E’)={+ , ε},所得得到以下结果:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | {} | {} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | {} |
T-> FT’ | {} | {} |
T’->*FT’|ε | FIRST(T’)={*, ε} | {} |
F-> (E)|id | FIRST(F)={(, id} | {} |
然后再从头看每个表达式可以得到FIRST(E)=FIRST(T),所以去求FIRST(T);
所以来看表达式T-> FT’,得到FIRST(T)=FIRST(F),又因为F无法推导出ε,所以FIRST(T)=FIRST(F);
同理可得FIRST(E)=FIRST(T)=FIRST(F);
所以表就更新为以下结果:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | {} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | {} |
T-> FT’ | FIRST(T)={(, id} | {} |
T’->*FT’|ε | FIRST(T’)={*, ε} | {} |
F-> (E)|id | FIRST(F)={(, id} | {} |
这时候,我们FIRST集就已经求完了,接下来看FOLLOW集:
同样先来文字描述:
FOLLOW(A):可能在某个句型中紧跟在A后边的终结符a的集合
FOLLOW(A)={a| S=>*αAaβ, a∈VT, α,β∈(VT∪VN)*
如果A是某个句型的最右符号,则将结束符“$”添加到FOLLOW(A)中。
还是上面的栗子:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | {} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | {} |
T-> FT’ | FIRST(T)={(, id} | {} |
T’->*FT’|ε | FIRST(T’)={*, ε} | {} |
F-> (E)|id | FIRST(F)={(, id} | {} |
我是首先找处在句子最右边的非终结符有哪些,由上面的表达式可以看出,分别有E’、T’所以首先把"$"填进去:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | {} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | FOLLOW(E’)={$} |
T-> FT’ | FIRST(T)={(, id} | {} |
T’->*FT’|ε | FIRST(T’)={*, ε} | FOLLOW(T’)={$} |
F-> (E)|id | FIRST(F)={(, id} | {} |
然后从头开始看,首先看E,先直观的看E后面跟有哪些终结符;很容易可以看到有“)”;
又因为E为开始符号,所以FOLLOW(E)中有“$”符
再看T,T后面跟的是E’,所以FOLLW(T)要包含FIRST(E’);又由于E’可以推导出空串,所以T也可以是最右符号;
再看T’,T’首先是最右符号,所以FOLLOW(T)包含结束符;
最后看F,F后面跟的是T’,所以FOLLOW(F)包含FIRST(T’),又由于T’可以推导出空串,所以F也可以是最右符号。
所以得到以下列表:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | FOLLOW(E)={), $} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | FOLLOW(E’)={$} |
T-> FT’ | FIRST(T)={(, id} | FOLLOW(T)={+, $} |
T’->*FT’|ε | FIRST(T’)={*, ε} | FOLLOW(T’)={$} |
F-> (E)|id | FIRST(F)={(, id} | FOLLOW(F)={*, $} |
接下来再看有表达式推导得到的FOLLOW集是否发生改变:
又由于E->TE’,所以FOLLOW(E)=FOLLOW(E’);
又因为T->FT’,所以FOLLOW(T)=FOLLOW(T’)
所以有些FOLLOW集需要更新如下所示:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | FOLLOW(E)={), $} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | FOLLOW(E’)={$, )} |
T-> FT’ | FIRST(T)={(, id} | FOLLOW(T)={+, $} |
T’->*FT’|ε | FIRST(T’)={*, ε} | FOLLOW(T’)={$, +} |
F-> (E)|id | FIRST(F)={(, id} | FOLLOW(F)={*, $} |
再看有些表达式能够推出空串,所以右边非终结符的FOLLW集合需包含左边非终结符的FOLLW集合,如E -> TE’,由于E’能够推导出空串,所以FOLLW(T)要包含FOLLW(E),根据这条规则,对FOLLW集做以下更新:
表达式 | FIRST集 | FOLLOW集 |
---|---|---|
E -> TE’ | FIRST(E)={(, id} | FOLLOW(E)={), $} |
E’-> +TE’|ε | FIRST(E’)={+ , ε} | FOLLOW(E’)={$, )} |
T-> FT’ | FIRST(T)={(, id} | FOLLOW(T)={+, $, )} |
T’->*FT’|ε | FIRST(T’)={*, ε} | FOLLOW(T’)={$, +, )} |
F-> (E)|id | FIRST(F)={(, id} | FOLLOW(F)={*, $, +,)} |
总结
FIRST集没什么问题,很好求,但是FOLLOW集合想对就比较麻烦,需要考虑的地方比较多,在做题目的时候千万不要遗漏!
欢迎批评指正,交流。