如何消除左遞歸

  首先,什麼叫作左遞歸呢? 一個左遞歸的語法一般有這樣的形式 :  A-> Aa .而自頂向下的語法分析是沒法處理左遞歸語法的。爲何呢?不管是遞歸分析仍是預測分析或者是LL文法分析,在碰到左遞歸這種語法時都會陷入死循環當中。若是咱們用遞歸分析,那麼在分析A這個非終結符號的時候就會調用functionA,functionA將A分解成A,a,而後在咱們再次碰到A的時候又會調用functionA,這樣便造成了無限遞歸。若是咱們用非遞歸的LL文法分析,那麼在咱們將把A->Aa無限次地壓入到棧中,即每次彈出A都會壓入Aa。因此咱們必須採起手段消除左遞歸,下面給出標準方法。spa

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

其實原理在於經過轉換將A的語法不從非終結符號(A自己)開始,而是從終結符號β1...β開始。雖然A的原語法是從A自己開始的,可是第一個符號必定是β1...βn中的一個,而不多是任何一個α。因此咱們經過一箇中間變量A'來表示剩下的α,然而不要忘記因爲A->αA'  這條規則,A-> ε 必須也存在於語法規則中,不然末尾將沒法匹配完成。遞歸

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

 

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

 

從 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' | ε 
請注意,以上的解決方案是基於右遞歸的文法,並非徹底適用於全部的狀況。咱們獲得的文法可能含有 ε表達式,而且可能會改變語法的結合律。解決方案就是保留左遞歸的語法,不用自頂向下的方式分析。
相關文章
相關標籤/搜索