筆者使用的是 劉堅編著的《編譯原理基礎(第二版)》2008年9月第2版 2012年5月第8次印刷的版本。
書P74頁中
算法3.5 計算X的FIRST集合
輸入:文法符號X。
輸出:X的FIRST集合。
方法:應用下述規則,
(1)若X是終結符,則FIRST(X) = {X}。
(2)若X是非終結符且有X→ε,則加入ε到FIRST(X)中。
(3)若X是非終結符且有X→Y1Y2…Yk,並令Y0=ε,Yk+1=ε,則從左到右對所有j(0≤j≤k),若a∈FIRST(Yj+1)且ε∈FIRST(Yj),則加入a到FIRST(X)中。
以下為自己的一些想法,如有紕漏,還望指正!
首先,解釋一下什么是FIRST集:
對於一個符號X最后轉化為實例(只由終結符組成)時,這個實例的第一個字符(如果實例長度為0則用ε表示這個字符)的所有可能情況組成的集合稱為X的FIRST集合,簡稱FIRST(X)。
對於算法3.5執行流程,我的理解是這樣的:
規則(1):對於終結符a,因為它的實例只有a一個,所以FIRST(a)必然是{a}。
規則(2):對於非終結符A,存在文法 A→ε,那么A的實例為空,即長度為0所以用ε表示該實例的第一個字符,將ε加入到FIRST(A)中。
規則(3):對於非終結符A,存在文法 A→BCDE,將該文法的右部看成εBCDEε,
①判斷ε∈FIRST(ε),如果符合的話則將FIRST(B)加入到FIRST(A)中;
②判斷ε∈FIRST(B),如果符合的話則將FIRST(C)加入到FIRST(A)中;
③判斷ε∈FIRST(C),如果符合的話則將FIRST(D)加入到FIRST(A)中;
④判斷ε∈FIRST(E),如果符合的話則將ε加入到FIRST(A)中。
對於規則(1)(2)較為容易理解,我也並沒有什么可改進的。
對於規則(3)我的理解如下:
按照FIRST集的定義,對於文法A→BCDE,FIRST(A)是指A的所有實例第一個字符的集合,那么我們將BCDE轉換為實例有兩種可能:
1) B不為空時,這時符號A的第一個字符必然屬於B不為空時的所有可能第一個字符的集合,即應該將 FIRST(B)-{ε} 加入 FIRST(A) ;
2) B為空時,這時文法A→BCDE就縮減成A→CDE,這個時候只需要重復上面的步驟即可。
那么我們需要考慮的問題是如下:
算法3.5 為什么要做
從左到右對所有j(0≤j≤k),若a∈FIRST(Yj+1)且ε∈FIRST(Yj),則加入a到FIRST(X)中
我們再看上面的算法執行流程:
①判斷ε∈FIRST(ε),如果符合的話則將FIRST(B)加入到FIRST(A)中;
②判斷ε∈FIRST(B),如果符合的話則將FIRST(C)加入到FIRST(A)中;
③判斷ε∈FIRST(C),如果符合的話則將FIRST(D)加入到FIRST(A)中;
④判斷ε∈FIRST(E),如果符合的話則將ε加入到FIRST(A)中。
~
在第一步做看似毫無意義的判斷ε∈FIRST(ε)的原因是:符號B作為文法A→BCDE右部的第一個符號,必然需要將FIRST(B)加入到FIRST(A)中,所以判斷本身並不重要,但做判斷后能提高算法的統一性和表達的簡潔性,如果單列出來,算法會顯得過於冗長;
在后續步驟中,不斷判斷ε∈FIRST(B/C/D/E)的原因是:考慮到B/C/D/E有可能為空,則文法形式可能會不斷縮減,極端的實例是BCDE都為空,則文法變成A→ε,所以在最后將ε加入FIRST(A)。
這么看來算法3.5好像沒有什么問題,但我注意到:
推論:如果B絕對不為空,即文法A→BCDE絕對不會縮減成A→CDE,這時會怎么樣?也就是說無論CDE是否可能為空,那么文法一定是A→B……,那么對於這個文法,FIRST(A)必然等於FIRST(B)。
那么按照這個設定(ε∉FIRST(B),ε∈FIRST(C)),我們再看算法的執行過程
①判斷ε∈FIRST(ε),符合!將FIRST(B)加入到FIRST(A)中;
②判斷ε∈FIRST(B),不符合;
③判斷ε∈FIRST(C),符合!將FIRST(D)加入到FIRST(A)中;
這個時候FIRST(A)包含了FIRST(B)和FIRST(D),但是按照我們推論,FIRST(A)必然等於FIRST(B),而FIRST(B)和FIRST(D)之間的關系是不明確的,所以按照算法3.5得到的結果存在問題!
所以我認為該算法應該做一定修改,以下是我做出修改后的算法
算法3.5改 計算X的FIRST集合
輸入:文法符號X。
輸出:X的FIRST集合。
方法:應用下述規則,
(1)若X是終結符,則FIRST(X) = {X}。
(2)若X是非終結符且有X→ε,則加入ε到FIRST(X)中。
(3)若X是非終結符且有X→Y1Y2…Yk,對於j(1≤j≤k),若ε∈FIRST(Yj),則將到 FIRST(Yj)-{ε} 加入 FIRST(X)中,其中若j=k,則將ε加入 FIRST(X)中;否則,將FIRST(Yj)加入 FIRST(X)中,直接結束算法。
按照這個修改后的算法執行設定(ε∉FIRST(B),ε∈FIRST(C)):
①判斷ε∈FIRST(B),不符合!將FIRST(B)加入到FIRST(A)中,結束算法;
這時FIRST(A)等於FIRST(B),符合預期。
原創文章,轉載請全文轉載並注明出處
