簡述自頂向下的語法分析

  在咱們獲得了Context-free grammar 以後,下一步就要將它轉換成一棵語法分析樹了,語法分析樹使得咱們的編譯器可以識別輸入串是否符合咱們的Context-free grammar(中文翻譯爲上下文無關語言)算法

有兩種方法可以將Context-free grammar轉換爲語法分析樹。今天咱們只介紹自頂向下的方法。函數

  自頂向下的語法分析是從根節點開始,深度優先地建立語法分析樹的各個節點。有遞歸向下分析和預測分析兩大類方法。ui

遞歸向下分析

  遞歸向下的語法分析可能須要回溯(aka須要重複掃描輸入),考慮如下文法: S -> aBc ,B -> bc | b ,當咱們用遞歸向下分析,輸入爲abc時,語法樹以下圖:spa

  

  當咱們第一次匹配時識別失敗了(a匹配a,bc匹配B,最後一個c未匹配到),輸入必須回到b,用B的另一種方式匹配。翻譯

  遞歸向下的分析十分直觀,實現起來也比較方便,但效率較低,因此通常不採用。遞歸向下的分析方法其實是深度優先搜索+回溯。而下面要說的預測分析則是用高效的動態規劃來實現語法分析。3d

 

遞歸預測向下分析

   在討論使用動態規劃的預測向下分析以前,咱們先來看一種特殊的預測向下分析。它在本質上也是遞歸的,惟一的區別在於它不須要回溯。考慮如下文法:A -> aBb | bAB,僞代碼實現以下:blog

 proc A {遞歸

case 當前標記 {terminal

  ‘a’:匹配a, 移動到下個標記;編譯器

     調用函數B;
     匹配b, 移動到下個標記;
  ‘b’:匹配b,移動到下個標記;
     調用函數A;

     調用函數B;

       }
    }

   其實這種分析方式與前者的區別就在於它用了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)={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文法。
相關文章
相關標籤/搜索