α的first集,即first(α)被定義為:可從α推導得到的串的首符號的集合,其中α是任意的文法符號串。如果α經過若干步的推導得到乙個ε,那麼ε也在first(α)中。
比如:
①a=>cγ
a可以推導出cγ這個串,這個串的首符號為c,因此c在first(a)中。
②e=>+te|ε
e可以推導出+te,而+te的首符號為+,並且e經過推導之後可以得到乙個ε,因此+、ε在first(e)中,即first(e)=。
計算各個文法符號x的first(x)時,不斷應用下列規則,直到再沒有新的終結符號或ε可以被加入到任何first集合中為止。
1)如果x是乙個終結符號,那麼first(x) = x,即first(a) = a
2)如果x是乙個非終結符號,且x—>y1y2…yk是乙個產生式,其中k>=1,那麼如果對於某乙個yi,它的產生式的首字元為乙個終結符(比如為a),且first(y1)、first(y2)、…、first(yi-1)中都有ε,那麼就把a加到first(x)中。
3)如果x是乙個非終結符號,且x—>y1y2…yk是乙個產生式,其中k>=1。如果對於所有的j=1,2,3,…,k, ε在first(yj)中,那麼將ε加入到first(x)中。
4)如果x—>ε是乙個產生式,那麼將ε加入到first(x)中。
現在,我們可以計算串x1x2…xn的first集合。先向first(x1x2…xn)加入f(x1)中所有的非ε符號。如果ε在first(x1)中,再加入first(x2)中所有非ε符號。如果ε在first(x2),那麼再加入first(x3)中所有非ε符合,以此類推。如果對於所有的i,ε都在first(xi)中,那麼就將ε新增到first(x1x2…xn)中。
//對於每乙個非終結符號,都進行初始化
foreach(nonterminal t)
first(t) = {}
//如果有first集在變化,那麼就繼續進行迴圈,直到所有的first集合都不變
while(some set
is changing)
foreach(production p:n->β1...βn)//遍歷n的每一條產生式
foreach(βi from β1 upto βn)//對於每一條產生式從左往右遍歷
if(βi == a...)//如果βi首字元是乙個終結符
first(n) u= //把a新增到n的first集合中
if(βi == m...)//如果βi的首字元是乙個非終結符
first(n) u= first(m)//把m的first集新增到n的first集中
if(m is not in nullable)//如果m不能推導出ε
//如果m可以推導出ε,那麼要繼續迴圈,對下乙個符號進行判斷
break;//跳出最內層的迴圈,進行一下條產生式的判斷
我們給出乙個文法g(e):
①e → te』
②e』 → +te』
③e』 →ε
④t → f t』
⑤t』 → *f t』
⑥t』 →ε
⑦f → (e)
⑧f → id
首先,我們分析能推出ε的文法符號,它們為:
有上述的偽**可知,一開始我們先進行初始化,因此每乙個左側非終結符號的first集都為空。
n\first01
23ee』
tt』f
下面進行第一輪的迭代:
我們看第①個產生式:e → te』
首符號為t,t為非終結符,此時表中t的first集為{},因此,此時e的first集仍為{}。
n\first01
23ee』
tt』f
我們看第②個產生式:e』 → +te』
首符號為+,+為終結符,因此把+新增到e』的first集中。
n\first01
23ee』
tt』f
我們看第③個產生式:e』 →ε
由規則4)可知,此時應將ε新增到e』的first集中。
n\first01
23ee』
tt』f
第④個產生式:t → f t』
首符號為f,此時first(f) = {},因此first(t) = {}。
n\first01
23ee』
{}tt』f
第⑤個產生式:t』 → *f t』
首符號為*,是乙個終結符號,因此first(t』) u= 。
n\first01
23ee』
tt』f
第⑥個產生式:t』 →ε與第③個產生式同理:將ε新增到t』的first集中。
n\first01
23ee』
tt』f
第⑦個產生式:f → (e)
首符號為(是乙個終結符號,因此直接新增到first(f)中。
n\first01
23ee』
tt』f
第⑧個產生式:f → id
首符號為id是乙個終結符號,因此直接新增到first(f)中。
n\first01
23ee』
tt』f
一輪迴圈之後,我們發現first集發生了變化,因此我們需要繼續進行一次迭代。
還是從第①個產生式e → te』開始看起,此時首符號t的first集仍然為空,因此e的first集還是為{}。
n\first01
23ee』
tt』f
第②、③個產生式與第一次時一樣
n\first01
23ee』
tt』f
第④個產生式t → f t』,首符號為f,此時first(f)為,因此first(t) u= first(f),而f無法推出ε,因此不用繼續看f的後跟符號t』。
n\first01
23ee』
tt』f
第⑤、⑥、⑦、⑧產生式與上一次一樣
n\first01
23ee』
tt』f
此時first(t)中發生了變化,所以我們還要繼續進行迭代
還是從第乙個產生式e → te』看起,首符號t的first集此時不再為,因此要把first(t)中的元素新增到first(e)中。
n\first01
23ee』
tt』f
之後的產生式,產生的first集並沒有發生變化,所以這一次迭代之後,只有first(e)發生了改變。
n\first01
23ee』
tt』f
因為first(e)發生了變化,所以我們還要進行一次迭代,這一次迭代後我們會發現與上一次迭代的結果完全相同,也就是所有的first集都沒有發生改變,所以迭代結束。
∴最終的結果為:
nfirst(n)ee』
tt』f
編譯原理 自頂向下分析
從頂部的根節點到底部的葉節點分析方法叫做自頂向下分析。我們知道頂部的根節點可以表示成乙個文法的開始符號s,所以說,自頂向下分析可以看成是從文法的開始符號s推導出詞串w的過程。例如,我們以輸入id id id 為例分析自頂向下的分析方法。首先從開始符號e 也就是樹的根節點 開始推導。首先用第乙個產生式...
編譯原理之自頂向下分析
編譯原理之自頂向下分析 daywolf原創 自頂向下分析演算法通過最左推導中描敘出各個步驟來分析記號串輸入,一般用遞迴下降分析和ll 1 分析。其中ll 1 分析表示從左向右地處理輸入,它為輸入串描述乙個最左推導,只用乙個符號來 分析的方向。現在在一般的程式裡都是使用ll 1 分析方法,我們在這裡就...
編譯原理 自頂向下語法分析
對於任何輸入串,從文法開始符號 根節點 出發,自上而下,從左到右地為輸入串建立語法分析樹。簡而言之,就是尋找輸入串的最左推導的過程。之前我們了解到,一旦有左遞迴存在便無法構建這樣的語法樹,所以用自頂向下語法分析必須先去除左遞迴。同樣,由於使用最左推導,也不能處理有複雜回溯的輸入串。自頂向下的語法分析...