編譯原理之語法分析-自下而上分析(四)

    (一)LR(k)項目算法

      LR(k)項目與以前SLR(1)中的項目有所不一樣,LR(k)項目是一個二元組[ 產生式,終結符 ]的形式閉包

      定義:使得每一個項目都附帶有k個終結符,項目是二元組,通常形式是[ A->α· β ,a1 a2 ....ak],這樣的項目稱爲LR(k)項目。k越大,LR(k)項目越多。函數

      • 顯然,從定義中咱們能得出A->α· β是一個LR(0)項目,由於它後邊二元組的終結符個數爲0。
      • a1 a2 ..... ak是終結符,稱爲向前搜索符串(展望串)
      • α處於棧頂位置
      • 圓點後邊的輸入能夠匹配 β a1 a2 ..... ak

    (二)LR(1)項目學習

      定義:咱們只對k<=1的情形感興趣,經過向前搜索一個符號就能夠肯定移進或歸約,若是K=1,即LR(1)項目,[ A->α· β ,a ]。spa

      • 對於任何移進或待約項目[ A->α· β ,a](β !=  ε),搜索符串a沒有任何做用。
      • 向前搜索符a僅對歸約項目[ A->α β · ,a]有意義。
        • 當它所屬的狀態呈如今棧頂且後續的輸入符號爲a時,才能夠把棧頂上的αβ歸約爲A。
        • 當歸約A->αβ(第i個產生式)時,a時前看符號。把ri填入到ACITON[ s,a ]中。 

      LR(1)項目的構造3d

      • 對於項目[ A->α ·Bβ,a ],添加[  B->γ ,b ] 到項目集,b屬於First(βa)。
      • 與LR(0)相比,僅有閉包的計算方法不一樣。
      • 爲構造有效的LR(1)項目集族咱們須要兩個函數CLOSURE和GO。 

       CLOSEURE(I)的定義blog

       

 

        GO的定義博客

        

    (三)構造LR(1)文法分析表搜索

      下圖中有一增廣文法,求出它的項目集。方法

      

 

       老規矩,直接上答案圖,而後按步驟講解。

 

     

 

    1. 從S' -> ·S且項目集編號爲0開始,S'爲開始符號,二元組終結符部分是#,因此二元組爲[ S' -> ·S,# ]。
      • 根據定義,圓點後爲S(非終結符),將S -> ·BB加入0號項目集,由於S->·BB中的S是從S'->S而來的,在二元組 [S'->·S,# ]求出Follow(S) = { # },因此得出二元組[ S->·BB,# ]
      • 根據定義,圓點後爲B(非終結符),將B -> ·aB加入0號項目集,求出S -> ·BB圓點後第一個符號(第一個B)的Follow集,或求出圓點後從第二個符號開始的(第二個B開始)的First集。求出First(B,#)={a,b},(注意First(B)中的B是S -> ·BB中的第二個B),因此得出二元組[ B -> ·aB,a | b ]
      • 將B->B -> ·b加入0號項目集,(注意這裏產生式左部的B,也是來自於S->·BB中的第一個B),所以咱們只須要求出Follow(第一個B)或者First(第二個B,#)便可,得出First(B)={a,b},加入二元組[  B->·b, a | b ]
      • 至此0號項目集已經完成                

 

     2.項目集0輸入符號B進入項目集2,從S->B·B開始,這裏的S來自於項目集0中的[S->·BB,#],而S->·BB來自於[ S'->·S,# ],所以項目集2中加入二元組[ S->B·B ,#]。

      • 根據定義,S->B·B中,圓點後爲非終結符,加入B -> ·aB,而產生式左部的B來自於項目集2中[ S->B·B ,# ]中的第二個B,因此求出Follow(第二個B)={ # },或First(#)={ # },因此加入二元組[ B -> ·aB ,#]。
      • 項目集2加入B->·aB以後還須要加入B->·b,這個B一樣來自於項目集2中[ S->B·B ,# ]中的第二個B,因此求出Follow(第二個B)={ # },或First(#)={ # },因此加入二元組[ B->·b ,#]。
      • 至此2號項目集已經完成

     3. 項目集0輸入符號a進入項目集3,從B->a·B開始,產生式左部的B來自於項目集0中的[ B->·aB,a | b],而B->·aB又來自於S->·BB,因此求出Follow(第一個B)={ a,b }或First(第二個B,#)={ a,b },因此項目集3中加入[ B->a·B ,a | b]

      • 根據定義,B->a·B中圓點後爲非終結符,加入B->·aB,繼續找出產生式左部B的來源,來自於項目集3中[ B->a·B,a | b ]求出Follow(B)={a , b},First(a|b)={a,b},所以項目集3中加入二元組[B->·aB,a | b]。
      • 一樣項目集3加入B->·b,繼續找出產生式左部B的來源,來自於項目集3中[ B->a·B,a | b ]求出Follow(B)={a , b},First(a|b)={a,b},所以項目集3中加入二元組[B->·b,a | b]。
      • 至此3號項目集已經完成

    由於項目集過多,這裏只選出具備表明性的三個項目集解釋,其餘項目集可按該思路得出。 

    總結:有一產生式 S -> xxx(x表明任意終結符或非終結符),就去查找該S的來源,而後找到源二元組[ E->x·SA,abc ]以後,求出Follow(S),或 First(Aabc)便可。   

       下圖是該文法的LR(1)分析表

       

 

      能夠發現歸約項目集爲四、五、七、八、9,而再查看對應的的LR(1)項目集能夠看出來:

      • 4號項目集終結符爲a,b,所以在ab所在列填入r3(Ri中的 i 爲文法編號,第一個圖)。
      • 5號項目集終結符只有#,所以只在#所在列填寫r1。
      • 7號項目集終結符只有#,所以只在#所在列填寫r3。
      • 8號項目集終結符爲a,b,所以在ab所在列填入r2。
      • 9號項目集終結符只有#,所以只在#所在列填寫r2。

      表中其他內容與LR(0)和SLR(1)基本一致,這裏就再也不介紹。至此LR(1)分析表就構造完成。

      

        對於該文法再給出LR(0)和SLR(1)分析表,能夠作一下對比理解,本身推下3個分析表如何構造:

        

 

        

 

 

         最後給出三個分析表算法的系統語言:

        

 

 

 

          

 

 

           

 

 

           到此爲止,就已經完成LR(0)、SLR(1)、LR(1)分析表的構造以及流程。

          總結一下三個表流程(重點、重點、重點!!!)

        1. 構造增廣文法。
        2. 根據增廣文法列出項目集
        3. 構造NFA(該步驟能夠省略)
        4. 構造LR(0)DFA(這一步很是重要,若是DFA構造錯誤則分析表會出錯,LR(0)和SLR(1)的DFA同樣,LR(1)的DFA中產生式後須要計算終結符 )
        5. 判斷是否是LR(0)文法,若是存在衝突則下一步,若是不存在衝突則該文法是LR(0)文法。(是LR(0)文法則必定是SLR(1)和LR(1)文法)
        6. 判斷衝突可否用SLR(1)的解決方法消除,若是能消除則是SLR(1)文法,若是不是則下一步
        7. 根據LR(0)的DFA或SLR(1)的DFA(一元組形式)計算每一個產生式的展望串,從而得出LR(1)的DFA(二元組形式)。
        8. 根據衝突項目集中終結符去判斷可否消除衝突,若是S-R或R-R衝突的兩個二元組中的終結符沒有交集則視爲能夠消除衝突,若是不能消除至此則該文法不屬於上述3個文法的任意一個。

 

 

           LALR文法就再也不介紹了,若是有興趣能夠查看一下其餘優秀的博客,至此自下而上分析法就已經介紹完畢(該博客爲我的學習總結,若是錯誤或異議歡迎指出,謝謝。)

相關文章
相關標籤/搜索