(轉載請表明出處 http://www.cnblogs.com/BlackWalnut/p/4472122.html )
LL(K)語法分析技術是建立在預測分析的技術之上的。我們先來了解預測分析技術。考慮以下文法:
當使用該文法對(1*2-3)+4和(1*2-3)進行分析,前者因該調用E->E+T,而后者應該調用E->T,怎么確定到底使用哪個產生式呢?這就要使用預測分析技術來構建預測分析語法分析器,LL(k)是其一種。預測分析技術的關鍵是構建一個無沖突的預測分析表。所謂預測分析表就是程序可以根據當前的狀態來查詢該表,然后確定下一步使用哪個產生式。
構建預測分析表要要用到兩個集合,分別是first集合和follow集合。γ是終結符和非終結符組成的字符串,first(γ)是從γ中可以推到出的任意字符串中所包含的開頭終結符所組成的集合。A是一個非終結符,follow(A)的意思可以直接跟在A后面的所有終結符的集合。這兩個集合的求法可以描述為如下:
First集合的求法:
First集合最終是對產生式右部的字符串而言的,但其關鍵是求出非終結符的First集合,由於終結符的First集合就是它自己,所以求出非終結符的First集合后,就可很直觀地得到每個字符串的First集合。
1. 直接收取:對形如U-a…的產生式(其中a是終結符),把a收入到First(U)中
2. 反復傳送:對形入U-P…的產生式(其中P是非終結符),應把First(P)中的全部內容傳送到First(U)中。
2. 反復傳送:對形入U-P…的產生式(其中P是非終結符),應把First(P)中的全部內容傳送到First(U)中。
Follow集合的求法:
Follow集合是針對非終結符而言的,Follow(U)所表達的是句型中非終結符U所有可能的后隨終結符號的集合,特別地,“#”是識別符號的后隨符。
Follow集合是針對非終結符而言的,Follow(U)所表達的是句型中非終結符U所有可能的后隨終結符號的集合,特別地,“#”是識別符號的后隨符。
1.反復傳送:對形如U-…P的產生式(其中P是非終結符),應把Follow(U)中的全部內容傳送到Follow(P)中
2. 直接收取:注意產生式右部的每一個形如“…Ua…”的組合,把a直接收入到Follow(U)中。
3.直接收取:對形如“…UPA…”(P是非終結符)的組合,把First(P)直接收入到Follow(U)中。如果P的first集合包含由空(ε),則first(A)也要放入Follow(U)中。
需要注意的是,空是只能在First集合中不能在follow集合中。
需要注意的是,空是只能在First集合中不能在follow集合中。
從上面的求法中可以知道,其實first集合就是一個非終結符的等價終結符的可選集合,也就是說A可以直接推到出這些終結符,如果first集合可以為空,則說明A可以直接忽略,這個時候,為了預測A為空后的情形,我們構建了follow集合。可見,者兩個完全是為了預測分析而產生的集合。
預測分析表是一個二維表,用非終結符符標注每行,用終結符好標注每一列,根據這first和follow兩個集合,我們使用如下規則構建一個預測分析表:從產生式集合中取出一個產生式A->γ,如果終結符a在first(γ)中,則講A->γ放入(A,a)確定的位置中,如果γ可以為空且a在follow(A)中,也則講A->γ放入(A,a)確定的位置中。這樣我們根據文法以下文法得到其相應的預測分析表:


如何使用這個分析表呢?要知道,我們所分析的數據是由詞法分析其產生的,對於語法分析器而言,詞法分析器產生的數據都是終結符。我們利用堆棧(用到堆棧的地方一般也可以用遞歸來解決,可以參考虎書英文版的第47頁代碼)來記錄當前正在分析的非終結符,從詞法分析器得到一個終結符a,以及棧頂的數據來查表,然后確定使用的產生式,如果產生式的右面有非終結符,將其從右到左壓棧(保證每次從對產生式的最左面的非終結符開始推到,稱為左推到),然后繼續使用使用a對棧頂元素分析。直到找到一個產生式的右只包含終結符a,然后將a拋棄,重新讀取新的終結符,繼續分析。如果在過程中無法得到只包含終結符a的產生式,那么說明有語法錯誤。
上面的算法過程就是一個預測分析過程我們稱為LL(1)算法,第一個L是left to right parse,第二個L是leftmost derivation ,1是1-symbol lookahead.意思就是從左到右的分析詞法分析器產生的數據,采用最左推到原則,每次只看超前查看一個終結符來確定后續動作。
但是就對上面這張表而言,(Z,d)的位置有兩個產生式,那么說明該文法是二義的,說明它是不是LL(K)文法。就不能使用預測分析技術來解析該語言,要使用功能更強大的LR(k)技術。
這里介紹兩種可能產生二義性的例子,第一個為左遞歸。查看下左圖,因為first(T)正好是first(E+T)的子集合,所以,一定會產生沖突。我們使用右圖來替換原來的產生式,稱為消除左遞歸。


還有一種情況,我們解決的辦法稱為提取右因子。


以上就是LL(K)文法的全部,相比LR(k)文法,它的功能不夠強大(我們在LR(K)中進行比較),但是想要構造一個預測分析表卻十分的簡單。對於某些LR(k)處理不了的情況,我們可以快速的建立相應的LL(K)分析表來解決。