如何消除左遞歸


  首先,什么叫做左遞歸呢? 一個左遞歸的語法通常有這樣的形式 :  A-> Aa .而自頂向下的語法分析是無法處理左遞歸語法的。為什么呢?無論是遞歸分析還是預測分析或者是LL文法分析,在碰到左遞歸這種語法時都會陷入死循環當中。如果我們用遞歸分析,那么在分析A這個非終結符號的時候就會調用functionA,functionA將A分解成A,a,然后在我們再次碰到A的時候又會調用functionA,這樣便形成了無限遞歸。如果我們用非遞歸的LL文法分析,那么在我們將把A->Aa無限次地壓入到棧中,即每次彈出A都會壓入Aa。所以我們必須采取手段消除左遞歸,下面給出標准方法。

  其中β1...β不是從A開始

其實原理在於通過轉換將A的語法不從非終結符號(A本身)開始,而是從終結符號β1...β開始。雖然A的原語法是從A本身開始的,但是第一個符號一定是β1...βn中的一個,而不可能是任何一個α。所以我們通過一個中間變量A'來表示剩下的α,然而不要忘記由於A->αA'  這條規則,A-> ε 必須也存在於語法規則中,否則末尾將無法匹配完成。

  但是,上述方法只適用於立即左遞歸,還有一種更隱蔽的非立即左遞歸,如 S -> Aa | b , A -> Sc | d ,我們如果用自頂向下的分析方法會陷入 S -> Aa -> Sca 這樣的死循環中。當然,也有相應的解決辦法。

 

將所有非終端符號以某個固定的順序A_1, \ldots A_n排列

 

從 i = 1 到 n {
從 j = 1 到 i – 1 {
  • A_j的生成規則為
A_j \rightarrow \delta_1 | \ldots | \delta_k
  • 將所有規則 A_i \rightarrow A_j \gamma換成
A_i \rightarrow \delta_1\gamma | \ldots | \delta_k\gamma
  • 移除A_i規則中的直接左遞歸
}
}

也許看上面的規則過於抽象,我們用S -> Aa | b , A -> Sc | d 來實踐一下上述的方法。我們以S,A的順序排列。則只需執行一次主程序體,且A為A,Aj為S。則:
A -> Aac | bc | d, 然后再運用前面的規則消除直接左遞歸可得:A -> bcA' | dA' , A'  -> acA' | ε 
請注意,以上的解決方案是基於右遞歸的文法,並不是完全適用於所有的情況。我們得到的文法可能含有 ε表達式,並且可能會改變語法的結合律。解決方案就是保留左遞歸的語法,不用自頂向下的方式分析。

 


免責聲明!

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



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