在我們得到了context-free grammar 之後,下一步就要將它轉換成一棵語法分析樹了,語法分析樹使得我們的編譯器能夠識別輸入串是否符合我們的context-free grammar(中文翻譯為上下文無關語言)
有兩種方法能夠將context-free grammar轉換為語法分析樹。今天我們只介紹自頂向下的方法。
自頂向下的語法分析是從根節點開始,深度優先地建立語法分析樹的各個節點。有遞迴向下分析和**分析兩大類方法。
遞迴向下的語法分析可能需要回溯(aka需要重複掃瞄輸入),考慮以下文法: s -> abc ,b -> bc | b ,當我們用遞迴向下分析,輸入為abc時,語法樹如下圖:
當我們第一次匹配時識別失敗了(a匹配a,bc匹配b,最後乙個c未匹配到),輸入必須回到b,用b的另外一種方式匹配。
遞迴向下的分析十分直觀,實現起來也比較方便,但效率較低,所以一般不採用。遞迴向下的分析方法實際上是深度優先搜尋+回溯。而下面要說的**分析則是用高效的動態規劃來實現語法分析。
在討論使用動態規劃的**向下分析之前,我們先來看一種特殊的**向下分析。它在本質上也是遞迴的,唯一的區別在於它不需要回溯。考慮以下文法:a -> abb | bab,偽**實現如下:
proc a
}其實這種分析方式與前者的區別就在於它用了case語句來**a的兩種可能性,從而做出不同的判斷。但這種方式的效率也是不如動態規劃的。
非遞迴**向下分析是表驅動的分析方法,也叫做ll(1)分析。第乙個"l"表示從左到右掃瞄。第二個"l"表示產生最左推導。"1"表示每次只要往前走一步就可以決定語法分析的動作。
所謂表驅動就是通過查表的方式來分析乙個輸入流是否符合文法。假設我們已經得到了這張語法分析表,現在來具體分析這種方式是如何工作的。
首先我們需要乙個棧來儲存start symbol,即語法樹的根。然後從表中查詢當棧頂為s,輸入為a時對應的文法,然後將s替換為aba(注意入棧順序),然後a與輸入的a匹配,非終結標誌b對應到了b,此時查詢表中相應的文法,將b彈出棧,將bb壓入棧(注意順序)。以此類推直到棧底的終止字元匹配到了輸入的終止字元,表示匹配成功。
上面是例項,下面我們給出乙個高度的分析行為概括:
當棧頂為x,當前輸入為a時,有以下四種分析行為:
1.如果x和a都為終止符號$,匹配成功,停止匹配。
2.如果x和a都是同一種終結標誌(terminal symbol),將x彈出棧,將輸入移動到下個標誌。(表示該標誌成功匹配,準備匹配下個標誌)
3.如果x是非終結標誌(nonterminal symbol),查詢語法分析表,找到[s,a],如果[s,a]為 x->y1y2y3...yk,則將y1y2y3...yk逆序放入棧中。(即y1為棧頂)
4.不符合以上三種情況,匹配失敗,進入錯誤恢復模式。
可以看到,有了這張語法分析表之後分析起來非常的方便。那麼我們如何構建這張語法分析表呢?
首先我們需要用到兩個函式first(a),follow(a),下面詳細解釋兩個函式的含義以及如何計算他們。
first(a) : 可以從a推導得到的串的首符號(終結符號)的合集。
計算規則如下:
1.如果x是終結符號,first(x)=
2.如果x是非終結符號且x->ε是乙個文法規則,那麼ε屬於first(x)
3.如果x是非終結符號且x->y1y2y3...yn是乙個文法規則,那麼:①如果終結符號a在first(yi)中且ε在所有的first(yj) (j-1,2,...i-1)中,那麼a也屬於first(x) ②如果ε在所有的first(yj) (j=1,2...n) 那麼ε也屬於first(x)
4.如果x本身為ε,那麼first(x)=
以上的規則將一直使用直到沒有元素能夠加入到任何first()當中。
follow(a):從a之後可以立即得到(可以理解為與a相鄰)的終結符號的集合,其中a是非終結符號。
計算規則如下:
1.如果a->abb是乙個文法規則,那麼所有在first(b)中的元素除了ε都包含在follow(b)中。
2.如果a->ab是乙個文法規則或者a->abb是乙個文法規則且ε包含在first(b)中,那麼在follow(a)中的所有元素都在follow(b)中。即follow(a)屬於follow(b)
以上的規則也將一直使用直到沒有元素能夠加入到任何follow()當中。
下面給出兩個例項讓讀者自行思考。
接下來讓我們使用這兩個函式來完成語法分析表構建的演算法。
對於在語法合集g中的每條語法 ,(以a->a來表示):
for 每個終結符號 p in first(a):
將a->a 加入到表中的m[a,p]
if ε in first(a)
for 每個follow(a)中的終結符號p:
將a->a 加入到m[a,p]
if ε in first(a) 並且 $ 屬於follow(a):
將a->a 加入到m[a,$]
當然並不是所有的語法規則都是ll文法的,也就是說有可能出現在乙個表中的某行某列存在多個文法規則,比如下圖
在m[e,e]中出現了兩個文法規則使得語法分析產生了二義性(ambiguity)。可以看出ll文法並不是萬能的。那麼如果我們碰到了這樣的情況應該怎麼辦呢?
首先我們可以先將存在左遞迴的文法消除成非左遞迴的文法。其次我們還可以提取左公因子,如果這樣處理之後還是不行的話那麼說明這個語法本身就存在二義性或者它天生就不是ll文法。
語法分析 自頂向下分析
確定的自頂向下分析方法,首先要解決從某文法的開始符號出發,對給定的輸入符號串如何根據當前的輸入符號 單詞符號 唯一地確定選用哪個產生式替換相應非終結符往下推導,或構造一棵相應的語法樹,若能夠推導出給定的輸入符號串,或能構造出語法樹其末端結點以從左向右的順序連線正好為給定的輸入符號串,則所給的輸入符號...
語法分析 自頂向下分析
確定的自頂向下分析方法,首先要解決從某文法的開始符號出發,對給定的輸入符號串如何根據當前的輸入符號 單詞符號 唯一地確定選用哪個產生式替換相應非終結符往下推導,或構造一棵相應的語法樹,若能夠推導出給定的輸入符號串,或能構造出語法樹其末端結點以從左向右的順序連線正好為給定的輸入符號串,則所給的輸入符號...
語法分析 自頂向下分析方法
前陣子弄完詞法分析後,這一周開始語法分析的課程。語法分析 在電腦科學和語言學中,語法分析 英語 syntactic analysis,也叫 parsing 是根據某種給定的形式文法對由單詞序列 如英語單詞序列 構成的輸入文字進行分析並確定其語法結構的一種過程。摘自維基百科 其實學習語法分析,並不是一...