一個編譯器的實現2——從文法到LL(1)分析表的概念和算法


關於編譯原理基礎概念可參考http://www.cnblogs.com/bitzhuwei/archive/2012/10/22/SmileWei_Compiler.html 

關於下列代碼的基礎數據結構參見http://www.cnblogs.com/bitzhuwei/archive/2012/03/09/compiler_basic_data_structure.html

一、      消除直接左遞歸

設P -> Pα1 | Pα2 | ... | Pαn | β1 | β2 | ... |βm

其中每個α不為ε(ε就是空,什么都沒有的意思,類似null),每個β不以P開頭。

則非終結符P可改寫為

P -> β1P’ | β2P’ | ... | βmP’

P’ -> α1P’ | α2P’ | ... | αnP’ | null

解釋:原來的P展開就是βxαi..αiαj..αj...αt..αt的形式,即某個β開頭,各種阿爾法跟隨的一個串。所以與改寫形式所表達的東西是一樣的。

 

二、      消除間接左遞歸

給定文法G,若G不含回路(P經過若干步推導又得到P)且不含以ε為右部的產生式。

則其消除左遞歸的算法如下:

  1. 對G的非終結符按任意順序排列,如A1, A2, A3, ... , An
  2. for (i = 1; i <= n; i++)
        for (j = 1; j <= i - 1; j++)
        {
            把形如Ai -> Ajγ的產生式改寫成Ai -> δ1γ | δ2γ | ... | δkγ的形式,其中Aj -> δ1 | δ2 | ... | δk是關於Aj的全部規則
            消除Ai規則中的直接左遞歸
        }
  3. 簡化由上一步得到的文法,即去掉多余的規則

 

三、      FIRST集

若文法G為二型文法且不含左遞歸,則G的非終結符的每個候選式α的終結首符集FIRST(α)為FIRST(α) = { a | α經過0或多步推導為a...的形式,其中a∈VT }

解讀:FIRST集的含義是:候選式經過推導,最后就是一個終結符的串,推導過程不同,會有多個不同的串(可能是無限個),這些串里的第一個字符組成的集合就是這個候選式的FIRST集。有了這個FIRST集,就可以知道這個候選式是否能匹配接下來要解析的單詞流了。

 

四、      FOLLOW集

設上下文無關文法(二型文法)G,開始符號為S,對於G中的任意非終結符A,其FOLLOW(A) = { a | S 經過0或多步推導會出現 ...Aa...的形式,其中a∈VT或#號 }

解讀:FOLLOW集的含義是:G的一切句型中,能夠緊跟着非終結符A之后的一切終結符或井號#。#是當出現 ...A 這樣的情況,即A為最后一個字符。

 

五、      構造FOLLOW集的算法

  1. 令#∈FOLLOW(S)
  2. 若文法G中有形如A –> αBβ的規則,且β≠ε,則將FIRST(β)中的一切非終結符加入FOLLOW(B)
  3. 若文法G中有形如A -> αB或A -> αBβ的規則,且ε∈FIRST(β),則將FOLLOW(A)中的全部元素加入FOLLOW(B)
  4. 反復使用前兩條規則,直到所有的FOLLOW集都沒有改變。

 

六、      構造LL(1)分析表的算法

輸入:文法G

輸出:G的LL(1)分析表M(Ax, ay),其中A為非終結符,a為終結符

算法:

  1. 求出G的FIRST集和FOLLOW集
  2. for (G的每個產生式 A -> γ1 | γ2 | ... | γm)
    {
        if (a ∈ FIRST(γi)) 置 M(A, a) 為 “A -> γi”
        if (ε ∈ FIRST(γi))
            for (每個 a ∈ FOLLOW(A))
                置 M(A, a)為 “A -> γi”(實際上此處的γi都是ε)
    }
    置所有無定義的 M(A, a)為出錯。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM