目錄 |
---|
01 文法和語言、詞法分析複習 |
02 自頂向下、自底向上的LR分析複習 |
03 語法制導翻譯和中間代碼生成複習 |
04 符號表、運行時存儲組織和代碼優化複習 |
開始符號集或首符號集:設\(G=(V_T,V_N,P,S)\)是上下文無關文法。
\(FIRST(\alpha)=\{a \mid\alpha \stackrel{*}{\Rightarrow} a\beta, a\in V_T, \alpha,\beta\in V^*\}\)html
若\(\alpha \stackrel{*}{\Rightarrow} \varepsilon\),則規定\(\varepsilon \in FIRST(\alpha)\),稱\(\varepsilon \in FIRST(\alpha)\)爲\(\alpha\)的開始符號集或首符號集閉包
簡單來講,就是查看該句型推導出的全部句子的首字母集合。函數
例如文法\(G[S]:\)
\(S\rightarrow Ap\)
\(S\rightarrow Bq\)
\(A\rightarrow aA\)
\(A\rightarrow \varepsilon\)
\(B\rightarrow Bb\)
\(B\rightarrow b\)優化
那麼\(FIRST(S)=\{a,b,p\}\),\(FIRST(A)=\{a,\varepsilon\}\),\(FIRST(B)=\{b\}\)spa
FOLLOW集:設\(G=(V_T,V_N,P,S)\)是上下文無關文法,\(A\in V_N\),S是開始符號
\(FOLLOW(A)=\{a\mid S\stackrel{*}{\Rightarrow}\mu A\beta且a\in V_T,a\in FIRST(\beta), \mu\in {V_T}^*, \beta\in V^+\)
若\(S \stackrel{*}{\Rightarrow}\mu A\beta\),且\(\beta \stackrel{*}{\Rightarrow}\varepsilon\),則 \(\# \in FOLLOW(A)\)翻譯
簡單來講,就是查看該句型在被推導先後面跟隨的全部可能的第一個字母的集合。須要將出如今推導式左邊的非終結符往指針
例如以前的文法\(G[S]\),\(FOLLOW(S)=\{\#\}\),\(FOLLOW(A)=\{p\}\),\(FOLLOW(B)=\{b,q\}\)code
選擇符號集:一個產生式的選擇符號集SELECT。給定上下文無關文法的產生式\(A\rightarrow \alpha, A\in V_N, \alpha\in V^*\),若\(\alpha\stackrel{*}{\nRightarrow}\varepsilon\),則\(SELECT(A\rightarrow\alpha)=FIRST(\alpha)\)htm
而若是\(\alpha\stackrel{*}{\Rightarrow}\varepsilon\),則\(SELECT(A\rightarrow\alpha)=(FIRST(\alpha)-\{\epsilon\})\cup FOLLOW(A)\)。blog
求出選擇符號集,是爲了找到哪些符號應該使用該推導。那麼,若是\(A\rightarrow \alpha\)不能推出空串,顯然 從該推導獲得的全部句子的首字母構成的集合 來反向看出 哪些字母應該使用該推導。而若是\(A\rightarrow \alpha\)能推出空串,則還要考慮該非終結符的後跟字符。
一個上下文無關文法是LL(1)文法的充要條件,是對每一個非終結符A的兩個不一樣產生式,\(A\rightarrow\alpha, A\rightarrow\beta\),知足
\[SELECT(A\rightarrow\alpha)\cap SELECT(A\rightarrow\beta)=\emptyset\]
例如文法\(G[S]:\)
\(S\rightarrow aA\)
\(S\rightarrow d\)
\(A\rightarrow bAS\)
\(A\rightarrow \varepsilon\)
有:
\(SELECT(S\rightarrow aA)=\{a\}\)
\(SELECT(S\rightarrow d)=\{d\}\)
\(SELECT(A\rightarrow bAS)=\{b\}\)
\(SELECT(A\rightarrow \varepsilon)=\{a,d,\#\}\)
因此:
\(SELECT(S\rightarrow aA)\cap SELECT(S\rightarrow d)=\{a\}\cap\{d\}=\emptyset\)
\(SELECT(A\rightarrow bAS)\cap SELECT(A\rightarrow \varepsilon)=\{b\}\cap\{a,d,\#\}=\emptyset\)
LL(1)的含義:第1個L 代表 從左向右掃描輸入串,第2個L 代表 分析過程當中將使用最左推導,1代表只需向右看一個符號就知道該選擇哪一個產生式推導。
LL(1)文法的充分條件爲不含左公共因子
例如\(A\rightarrow \alpha\beta\mid \alpha\gamma\),能夠寫成:
\(A\rightarrow \alpha B\)
\(B\rightarrow \beta\)
\(B\rightarrow \gamma\)
通常狀況如\(A\rightarrow \alpha_1\alpha_2...\alpha_n(\beta_1\mid\beta_2\mid...\mid\beta_n)\),能夠寫成:
\(A\rightarrow\alpha_1 A_1\)
\(A_1\rightarrow\alpha_2 A_2\)
\(...\)
\(A_{n-1}\rightarrow\alpha_n B\)
\(B\rightarrow\beta_1\)
\(B\rightarrow\beta_2\)
\(...\)
\(B\rightarrow\beta_n\)
此外,還須要檢查文法是否含有隱式的左公共因子,如:
\((1)A\rightarrow ad\)
\((2)A\rightarrow Bc\)
\((3)B\rightarrow aA\)
將(3)帶入(2),可暴露出左公共因子:
\((1)A\rightarrow ad\)
\((2)A\rightarrow aAc\)
\((3)B\rightarrow aA\)
能夠看到此時(3)爲多餘規則,能夠刪去,最後整理獲得:
\((1)A\rightarrow aB\)
\((2)B\rightarrow Ac\)
\((2)B\rightarrow d\)
改寫後的文法不含空產生式,且無左遞歸時,則改寫後的文法是LL(1)文法
若還有空產生式,則還須要用LL(1)文法的判別方式進行判斷
對於包含直接左遞歸的文法,如\(G[A]:A\rightarrow Ab,A\rightarrow c, A\rightarrow d\)
能夠直接改寫成右遞歸:\(A\rightarrow cA', A\rightarrow dA', A'\rightarrow bA',A'\rightarrow \varepsilon\)
通常狀況下,如\(A\rightarrow A(\beta_1\mid\beta_2\mid...\mid\beta_n), A\rightarrow \alpha_1\mid\alpha_2\mid...\mid\alpha_n\),分爲了包含左遞歸和不含左遞歸的兩部分,能夠變形爲:
\(A\rightarrow \alpha_1 A'\)
\(A\rightarrow \alpha_2 A'\)
\(...\)
\(A\rightarrow \alpha_n A'\)
\(A'\rightarrow \beta_1 A'\)
\(A'\rightarrow \beta_2 A'\)
\(...\)
\(A'\rightarrow \beta_n A'\)
對於包含間接左遞歸的文法,如\(G[S]:\)
\((1)A\rightarrow aB\)
\((2)A\rightarrow Bb\)
\((3)B\rightarrow Ac\)
\((4)B\rightarrow d\)
能夠考慮把(1)和(2)帶入(3):
\((1)B\rightarrow aBc\)
\((2)B\rightarrow Bbc\)
\((3)B\rightarrow d\)
不會引發左遞歸的式子爲(1)和(3),故能夠寫成:
\((1)B\rightarrow aBcB'\)
\((2)B\rightarrow dB'\)
\((3)B'\rightarrow bcB'\)
\((4)B'\rightarrow \varepsilon\)
寫程序時,用getsym來讀入下一個符號,若是有不合法的符號,應當有錯誤處理。
如文法\(L(G[A]): A\rightarrow aBd \mid b, B\rightarrow\varepsilon\mid c\)
\(SELECT(A\rightarrow aBd)=\{a\}\)
\(SELECT(A\rightarrow b)=\{b\}\)
\(SELECT(B\rightarrow \varepsilon)=\{d\}\)
\(SELECT(B\rightarrow c)=\{c\}\)
void PraseA() { if (sym == 'a') { getsym(); PraseB(); if (sym == 'd') getsym(); } else if (sym == 'b') { getsym(); } else { error(); } } void PraseB() { if (sym == 'c') { getsym(); } else if (sym == 'd') { } else { error(); } }
求出全部規則的SELECT集後,根據集合填入預測分析表。如上面的文法:
a | b | c | d | # | |
---|---|---|---|---|---|
A | \(\rightarrow aBd\) | \(\rightarrow b\) | |||
B | \(\rightarrow c\) | \(\rightarrow \varepsilon\) |
下表是對對\(acd\)的分析過程:
步驟 | 分析棧 | 剩餘輸入串 | 推導所用產生式或匹配 |
---|---|---|---|
1 | #A | acd# | A→aBd |
2 | #dBa | acd# | a匹配 |
3 | #dB | cd# | B→c |
4 | #dc | cd# | c匹配 |
5 | #d | d# | d匹配 |
6 | # | # | 接受 |
一開始把起始非終結符放入分析棧,而後會有2種狀況:
自底向上的移進-規約分析要求對輸入符號串自左向右掃描,按句柄進行歸約。
移進:將輸入串的下一個字符移入符號棧
歸約:符號棧中的頂部幾個符號若是能匹配某條推導式的右邊,則用該推導式的左邊替換
自底向上的移進-歸約法是每次對最左邊的內容進行歸約,它的逆過程爲自頂向下的規範(最右)推導。
設文法 \(G[S]\) 爲
\(S\rightarrow aAcBe\)
\(A\rightarrow b\)
\(A\rightarrow Ab\)
\(B\rightarrow d\)
對輸入串\(abbcde\)使用自頂向下的最右推導:
\[S\Rightarrow aAcBe \Rightarrow aAcde \Rightarrow aAbcde \Rightarrow abbcde\]
對應的,咱們能夠獲得它的逆過程,即規約過程。
步驟 | 符號棧 | 輸入符號串 | 動做 |
---|---|---|---|
(1) | # | abbcde# | 移進 |
(2) | #a | bbcde# | 移進 |
(3) | #ab | bcde# | 歸約\((A\rightarrow b)\) |
(4) | #aA | bcde# | 移進 |
(5) | #aAb | cde# | 歸約\((A\rightarrow Ab)\) |
(6) | #aA | cde# | 移進 |
(7) | #aAc | de# | 移進 |
(8) | #aAcd | e# | 歸約\((B\rightarrow d)\) |
(9) | #aAcB | e# | 移進 |
(10) | #aAcBe | # | 歸約\((S\rightarrow aAcBe)\) |
(11) | #S | # | 接受(acc) |
LR(K)分析使用自底向上分析法,從左到右掃描符號,只須要根據分析棧中的符號棧和向右順序查看輸入串的K(K>=0)個符號來肯定分析器接下來是移進仍是規約,於是也能惟一地肯定句柄。
總控程序負責LR分析過程
分析棧分爲狀態棧和文法符號棧。它們均是後進先出。
分析表分爲動做(ACTION)表和狀態轉換(GOTO)表兩個部分。
SP爲棧指針,指向狀態棧和文法符號棧,即狀態棧和符號棧元素數目始終保持一致。
狀態轉換表內容按關係\(GOTO[S_i, X]=S_j\)肯定,即當棧頂狀態爲\(S_i\)遇到棧頂符號\(X\)時應當轉向狀態\(S_j\)
動做表按\(ACTION[S_i,a]\)肯定了棧頂狀態爲\(S_i\)時遇到輸入符號\(a\)應執行的動做。
動做按優先程度排列:
規約:若是棧頂造成了句柄\(\beta\)(它的長度爲\(r\)),且有原來的推導\(A\rightarrow\beta\)來進行規約,則從狀態棧和文法符號棧中自頂向下去掉\(r\)個符號,即對SP減去\(r\)。接着把A移入文法符號棧內,再根據此時修改SP後的棧頂狀態,把知足\(S_j=GOTO[S_i, A]\)的狀態移進狀態棧。
移進:若是棧頂沒有造成句柄,且\(S_j=GOTO[S_i,a]\)成立,則把\(S_j\)移入到狀態棧,把\(a\)移入到文法符號棧。其中\(i\)和\(j\)表示狀態號。
接受acc:當歸約到文法符號棧中只剩下文法的開始符號S,而且輸入符號串只剩下#(表示已經結束),則爲分析成功。
報錯:若是狀態棧頂的當前狀態遇到了不應出現的文法符號時則報錯,說明輸入串不是該文法能接受的句子。
已知文法\(G[S]:\)
\((1)S\rightarrow aAcBe\)
\((2)A\rightarrow b\)
\((3)A\rightarrow Ab\)
\((4)B\rightarrow d\)
對輸入串\(abbcde\#\)用自底向上歸約的方法來分析,因爲到第5步棧中的符號串爲\(\#aAb\),此時狀態棧的棧頂狀態\(0236\)決定了應該用(3)式而不是(2)式來歸約。
分析表和分析過程以下:
爲了更清楚地表示最右推導與最左歸約的關係,能夠在推導過程當中加入一些附加信息。對上面的文法用\([i]\)編號:
\(S\rightarrow aAcBe[1]\)
\(A\rightarrow b[2]\)
\(A\rightarrow Ab[3]\)
\(B\rightarrow d[4]\)
對輸入串abbcde進行最右推導,把序號也帶入:
\(S\Rightarrow aAcBe[1]\Rightarrow aAcd[4]e[1]\Rightarrow aAb[3]cd[4]e[1]\Rightarrow ab[2]b[3]cd[4]e[1]\)
對應的逆過程——最左歸約(規範歸約,即從左到右歸約)爲:
\(ab[2]b[3]cd[4]e[1]\) 用產生式(2)歸約
\(\Leftarrow aAb[3]cd[4]e[1]\) 用產生式(3)歸約
\(\Leftarrow aAcd[4]e[1]\) 用產生式(4)歸約
\(\Leftarrow aAcBe[1]\) 用產生式(1)歸約
\(S\)
這裏用\(\Leftarrow\)表示歸約。
每次歸約前,句型的前部依次爲:
\(ab[2]\),它的前綴爲\(\varepsilon, a, ab\)
\(aAb[3]\),它的前綴爲\(\varepsilon, a, aA, aAb\)
\(aAcd[4]\),它的前綴爲\(\varepsilon, a, aA, aAc, aAcd\)
\(aAcBe[1]\),它的前綴爲\(\varepsilon, a, aA, aAc, aAcB, aAcBe\)
這些規範句型的前部咱們稱之爲可歸前綴。而a, aA, aAc等這些出如今一個或多個可歸前綴的部分,可稱之爲活前綴,它的長度不能超過當前句型句柄的末端。
拓廣文法是指對原文法G增長產生式\(S'\rightarrow S\),其中\(S\)爲原文法G的開始符號。這樣確保新的開始符號\(S'\)只會在推導式的左邊出現(而\(S\)不必定)
使用拓廣文法能夠將上面的文法表示成:
\(S'\rightarrow S[0]\)
\(S\rightarrow aAcBe[1]\)
\(A\rightarrow b[2]\)
\(A\rightarrow Ab[3]\)
\(B\rightarrow d[4]\)
對句子\(abbcde\)列出可歸前綴:
\(S[0]\)
\(ab[2]\)
\(aAb[3]\)
\(aAcd[4]\)
\(aAcBe[1]\)
重要!!!這部分能夠不須要看,由於咱們能夠直接經過構造識別活前綴的DFA來反向求出活前綴以及可歸前綴。
設\(G=(V_N, V_T, P, S)\)是一個上下文無關文法,對於\(A\in V_N\),有
\[LC(A)=\{\alpha\mid S'\mathop{\Rightarrow}\limits_{R}^{*}aA\omega,\alpha\in V^*, \omega\in V^T_*\}\]
其中S'是G的拓廣文法G'的開始符號
\(LC(A)\)代表了在規範推導(最右推導)中在非終結符A左邊出現的符號串集合。
推論:若文法G中有產生式\(B\rightarrow \gamma A\delta\),則有
\[LC(A) \supseteq LC(B) \cdot\{\gamma\}\]
由於對任一形爲\(\alpha B\omega\)的句型,必然有規範推導:
\[S'\mathop{\Rightarrow}\limits_{R}^{*}\alpha B\omega'\mathop{\Rightarrow}\limits_{R}^{*}\alpha\gamma A\delta\omega\]
所以對任一\(\alpha \in LC(B)\),必有\(\alpha \gamma \in LC(A)\),即\(LC(B) \cdot\{\gamma\} \subseteq LC(A)\)
對於文法\(G[S]\):
\(S'\rightarrow S\)
\(S\rightarrow aAcBe\)
\(A\rightarrow b\)
\(A\rightarrow Ab\)
\(B\rightarrow d\)
需列出方程組求解(此處爲正規式):
\[\begin{cases} LC(S') = \varepsilon \\ LC(S) = LC(S') \cdot\varepsilon=\varepsilon \\ LC(A) = LC(S) \cdot a \mid LC(A) \cdot\varepsilon = a \\ LC(B) = LC(S) \cdot aAc = aAc \end{cases}\]
用正規式表示求解結果:
\[\begin{cases} LC(S') = \varepsilon \\ LC(S) = \varepsilon \\ LC(A) = a \\ LC(B) = aAc \end{cases}\]
規定\(LR(0)C(A\rightarrow\beta)=LC(A)\cdot\beta\),這樣包含句柄的活前綴有:
\[\begin{cases} LR(0)C(S'\rightarrow S) = S \\ LR(0)C(S\rightarrow aAcBe) = aAcBe \\ LR(0)C(A\rightarrow b) = ab \\ LR(0)C(A\rightarrow Ab) = aAb \\ LR(0)C(B\rightarrow d) = aAcd \end{cases}\]
包含句柄的活前綴也就是可歸前綴,將它們展開也就獲得了全部的活前綴
對於遞歸型:
\[\begin{cases} LC(E)=\varepsilon \\ LC(A) = LC(E)\cdot a\mid LC(A) \cdot c \end{cases}\]
一直展開能夠看到:
\(LC(A)\)
\(= a\mid LC(A)\cdot c\)
\(=a\mid (a\mid LC(A)\cdot c)\cdot c\)
\(=a\mid ac\mid LC(A)\cdot cc\)
\(=a\mid ac\mid acc\mid LC(A)\cdot ccc\)
\(=...\)
故\(LC(A)=ac^*\)
在文法G'中爲每一個產生式的右部的適當位置添加一個圓點構成項目
例如\(A\rightarrow Ab\)有3個項目:
\([0] A\rightarrow \cdot Ab\)
\([1] A\rightarrow A\cdot b\)
\([2] A\rightarrow Ab\cdot\)
而空產生式\(A\rightarrow\varepsilon\)只有一個項目\(A\rightarrow\cdot\)。
\(\cdot\)左邊的符號表示已經被掃描過的部分,右邊若是還有符號,則它的第一個符號則是下一個將會被掃描的符號。
列出全部項目後,這些項目標上編號用於構造NFA,肯定\(S'\rightarrow \cdot S\)爲初態,有2種狀況:
根據圓點所在位置和圓點後的符號情況,能夠分爲4類:
從NFA構形成DFA的關鍵點僅在於,使用閉包函數,將當前項目(它前面不是由\(\varepsilon\)推出)以及後面用\(\varepsilon\)弧鏈接的全部項目,構成一個新的項目集。
但一個項目集中不能同時存在:
重點來了!從\(I_0\)項目集到最終要進行歸約的式子(即圓點在式子最後)的路徑掃過的符號順序就是這條推導式的活前綴!
好比從上圖就能夠看出:
\(E\rightarrow bB\)的可歸前綴爲\(bB\)
\(A\rightarrow cA\)的可歸前綴爲\(acc^*A\)
現有LR(0)項目集規範族:
\[C=\{I_0, I_1, ..., I_n\}\]
\(I_k\)爲項目集的名,k爲狀態名,令包含\(S'\rightarrow \cdot S\)項目的集合\(I_k\)的下標k做爲分析器的初始狀態。分析表的ACTION表和GOTO表構造步驟以下:
假定一個LR(0)規範族中含有以下的項目集(舉例):
\[I_5=\begin{cases} X\rightarrow\alpha\cdot b\beta \\ A\rightarrow \gamma \cdot \\ B\rightarrow \delta \cdot \end{cases}\]
也就是該項目集中出現了移進—歸約衝突和歸約—歸約衝突。
根據LR(0)分析,此時沒法肯定是移進,仍是歸約,即產生了衝突。但咱們能夠向前查看一個符號(即查看當前剩餘輸入串最前面一個符號),來肯定接下來的動做,這就是SLR(1)分析。
對於上面的例子,要求三個項目中 \(·\) 後面的符號各不相同,即要求它們的FOLLOR集互不相交:
\(FOLLOW(A)\cap\{b\}=\emptyset\)
\(FOLLOW(B)\cap\{b\}=\emptyset\)
\(FOLLOW(A)\cap FOLLOW(B)=\emptyset\)
即說明在狀態5時,若是面臨某輸入符號爲\(a\),則能夠按如下規定決策:
接下來是分析表的修改,好比說產生式2爲\(A\rightarrow \gamma\),產生式3爲\(B\rightarrow \delta\),\(FOLLOW(A)=c\),\(FOLLOW(B)=d\),本來LR(0)時候分析表對應:
狀態 | a | b | c | d | # |
---|---|---|---|---|---|
5 | \(r_2,r_3\) | \(r_2,r_3,S_6\) | \(r_2,r_3\) | \(r_2,r_3\) | \(r_2,r_3\) |
可見衝突很是嚴重,通過修改後,變成了:
狀態 | a | b | c | d | # |
---|---|---|---|---|---|
5 | \(S_6\) | \(r_2\) | \(r_3\) |
此時的分析表知足SLR(1)分析。
現有一文法\(G'\):
\((1)S'\rightarrow S\)
\((2)S\rightarrow aAd\)
\((3)S\rightarrow bAc\)
\((4)S\rightarrow aec\)
\((5)S\rightarrow bed\)
\((6)A\rightarrow e\)
它的識別活前綴的DFA以下:
留意到\(I_5\)中存在移進—歸約衝突,\(FOLLOW(A)\cap\{c\}=\{c,d\}\cap\{c\}=\{c\}\)
以及\(I_7\)中存在移進—歸約衝突,\(FOLLOW(A)\cap\{d\}=\{c,d\}\cap\{d\}=\{d\}\)
它們的交集都不爲空,不知足SLR(1)文法,須要考慮使用LR(1)文法。
在\(I_5\)中,因爲
\(S'\mathop{\Rightarrow}\limits_{R}S\mathop{\Rightarrow}\limits_{R}aAd\mathop{\Rightarrow}\limits_{R}aed\)
\(S'\mathop{\Rightarrow}\limits_{R}S\mathop{\Rightarrow}\limits_{R}aec\)
對於活前綴\(ae\)來講,當面臨符號\(c\)時應該移進,面臨符號\(d\)時應用產生式\(A\rightarrow e\)歸約。由於\(S'\mathop{\Rightarrow}\limits_{R}S\mathop{\nRightarrow}\limits_{R}aAc\),故\(aAc\)不是該文法的規範句型。
若\([A\rightarrow a\cdot B\beta]\in I_n\),則\([B\rightarrow\cdot\gamma]\in I_n\)。能夠考慮把\(FIRST(\beta)\)做爲用產生式\(B\rightarrow\gamma\)歸約的搜索符,成爲向前搜索符,這樣在要決定是歸約仍是移進的時候看看輸入串下一個符號是否屬於\(FIRST(\beta)\)集。向前搜索符一般也放在相應項目的後面。
首先以 \(S'\rightarrow\cdot S,\#\) 做爲初始項目集,\(\#\)爲向前搜索符(表示活前綴\(\gamma\)要規約成\(S\)時,必須面臨輸入符\(\#\)才行)
和LR(0)相比,區別僅在於:若是項目\((A\rightarrow\alpha\cdot B\beta, a)\)屬於該項目集,\(B\rightarrow\gamma\)是文法中的產生式,\(\beta\in V^*\),\(b\in FIRST(\beta a)\),則\((B\rightarrow \cdot\gamma, b)\)屬於該項目集,而且沿着該項目集開始日後\(B\rightarrow \gamma\)的全部項目都用同一個向前搜索符\(b\)。
注意:向前搜索符有可能不止一個!
如今目光來到上圖的項目集\(I_2\)
\(S\rightarrow a\cdot Ad\)
\(S\rightarrow a\cdot ec\)
\(A\rightarrow \cdot e\)
首先\(aAd\)被歸約成\(S\)時,根據惟一推導\(S\)的式子\(S'\rightarrow S\),能夠肯定\(S\)後面沒有符號,故\(S\rightarrow a\cdot Ad\)的向前搜索符爲\(\#\)。
同理,\(S\rightarrow a\cdot ec\)的向前搜索符也爲\(\#\)
如今,因爲項目中有\((S\rightarrow a\cdot Ad,\#)\)和\((A\rightarrow\cdot e,?)\)(這裏用?表示還不知道向前搜索符),在對\(A\rightarrow e\)這條式子歸約以前,能夠看到,顯然歸約是對\(·\)後面的\(A\)進行的,且\(A\)的後面是\(d\),又有整個推導式\(aAd\)的後面是\(\#\),所以\(FIRST(d\#)=d\)。故在歸約前須要判斷當前輸入串的第一個符號是否是爲\(d\)。所以\(A\rightarrow\cdot e\)向前搜索符爲\(d\)
\(S\rightarrow a\cdot Ad, \#\)
\(S\rightarrow a\cdot ec, \#\)
\(A\rightarrow \cdot e, d\)
再舉一個複雜點的例子,如今有\(G[S']:\)
\(S'\rightarrow S\)
\(S\rightarrow BB\)
\(B\rightarrow aB\)
\(B\rightarrow b\)
已知它的初始項目集\(I_0\)爲:
\((1)S'\rightarrow\cdot S\)
\((2)S\rightarrow\cdot BB\)
\((3)B\rightarrow\cdot aB\)
\((4)B\rightarrow\cdot b\)
顯然,(1)和(2)的向前搜索符都爲#
如今關鍵在推導式3和4,由於他們推導時用的都是\(S\rightarrow\cdot BB\)中的第一個\(B\),在歸約的時候要肯定它後面構成的串\(B\#\)的\(FIRST\)集,在這裏\(FIRST(B\#)=\{a,b\}\),故(3)和(4)的向前搜索符應該都爲\(a,b\)
\((1)S'\rightarrow\cdot S,\#\)
\((2)S\rightarrow\cdot BB,\#\)
\((3)B\rightarrow\cdot aB,a/b\)
\((4)B\rightarrow\cdot b,a/b\)