LL(1)分析法和遞歸下降分析法同屬于自頂向下分析法。相對(duì)于遞歸下降而言,LL通過(guò)顯示
地維護(hù)一個(gè)棧來(lái)進(jìn)行語(yǔ)法分析,遞歸下降則是利用了函數(shù)調(diào)用棧。
LL分析法主要由分析棧、分析表和一個(gè)驅(qū)動(dòng)算法組成。其實(shí)LL的分析算法還是很容易懂的,
主要就是一個(gè)匹配替換的過(guò)程。而要構(gòu)造這里的分析表,則還涉及計(jì)算first集和follow集
的算法。
個(gè)人覺得龍書在解釋這些算法和概念時(shí)都非常清楚細(xì)致,雖然也有人說(shuō)它很晦澀。
first集和follow集的計(jì)算,拋開書上給的嚴(yán)密算法,用人的思維去理解(對(duì)于compiler
compiler則需要用程序去構(gòu)造這些集合,這是讓計(jì)算機(jī)去理解),其實(shí)很簡(jiǎn)單:
1、對(duì)于某個(gè)非終結(jié)符A的first集(first(A)),簡(jiǎn)單地說(shuō)就是由A推導(dǎo)得到的串的首符號(hào)的
集合:A->aB,那么這里的a就屬于first(A),很形象。
2、follow(A),則是緊隨A的終結(jié)符號(hào)集合,例如B->Aa,這里的a就屬于follow(A),也很形
象。
當(dāng)然,因?yàn)槲姆ǚ?hào)中有epsilon,所以在計(jì)算上面兩個(gè)集合時(shí)則會(huì)涉及到一種傳遞性。例
如,A->Bc, B->epsilon,B可以推導(dǎo)出epsilon,也就是基本等同于沒有,那么first(A)中
就會(huì)包含c符號(hào)。
在了解了first集和follow集的計(jì)算方法后,則可以通過(guò)另一些規(guī)則構(gòu)造出LL需要的分析表。
編譯原理里總有很多很多的理論和算法。但正是這些理論和算法,使得編譯器的實(shí)現(xiàn)變得簡(jiǎn)
單,代碼易維護(hù)。
在某個(gè)特定的編程語(yǔ)言中,因?yàn)槠湮姆ㄒ欢?,所以?duì)于其LL(1)實(shí)現(xiàn)中的分析表就是確定的
。我們也不需要在程序里動(dòng)態(tài)構(gòu)造first和follow集合。
那么,要實(shí)現(xiàn)一個(gè)LL(1)分析法,大致步驟就集中于:設(shè)計(jì)文法->建立該文法的分析表->編
碼。
LL分析法是不能處理左遞歸文法的,例如:expr->expr + term,因?yàn)樽筮f歸文法會(huì)讓對(duì)應(yīng)
的分析表里某一項(xiàng)存在多個(gè)候選式。這里,又會(huì)涉及到消除左遞歸的方法。這個(gè)方法也很簡(jiǎn)
單,只需要把文法推導(dǎo)式代入如下的公式即可:
A -> AB | C 等價(jià)于:A -> CX, X -> BX | epsilon
最后一個(gè)問(wèn)題是,如何在LL分析過(guò)程中建立抽象語(yǔ)法樹呢?雖然這里的LL分析法可以檢查文
法對(duì)應(yīng)的語(yǔ)言是否合法有效,但是似乎還不能做任何有意義的事情。這個(gè)問(wèn)題歸結(jié)于語(yǔ)法制
導(dǎo)翻譯,一般在編譯原理教程中語(yǔ)法分析后的章節(jié)里。
LL分析法最大的悲劇在于將一棵在人看來(lái)清晰直白的語(yǔ)法樹分割了。在遞歸下降分析法中,
一個(gè)樹節(jié)點(diǎn)所需要的屬性(例如算術(shù)運(yùn)算符所需要的操作數(shù))可以直接由其子節(jié)點(diǎn)得到。但
是,在為了消除左遞歸而改變了的文法式子中,一個(gè)節(jié)點(diǎn)所需要的屬性可能跑到其兄弟節(jié)點(diǎn)
或者父節(jié)點(diǎn)中去了。貌似這里可以參考“繼承屬性”概念。
不過(guò),綜合而言,我們有很多業(yè)余的手段來(lái)處理這種問(wèn)題,例如建立屬性堆棧。具體來(lái)說(shuō),
例如對(duì)于例子代碼中計(jì)算算術(shù)表達(dá)式,就可以把表達(dá)式中的數(shù)放到一個(gè)棧里。
例子中,通過(guò)在文法表達(dá)式中插入動(dòng)作符號(hào)來(lái)標(biāo)識(shí)一個(gè)操作。例如對(duì)于文法:
expr2->addop term expr2,則可以改為:expr2->addop term # expr2。當(dāng)發(fā)現(xiàn)分析棧的棧
頂元素是'#'時(shí),則在屬性堆棧里取出操作數(shù)做計(jì)算。例子中還將操作符壓入了堆棧。
下載例子,例子代碼最好對(duì)照arith_expr.txt中寫的文法和分析表來(lái)看。
PS,最近在云風(fēng)博客中看到他給的一句評(píng)論,我覺得很有道理,并且延伸開來(lái)可以說(shuō)明我們
周圍的很多現(xiàn)象:
”很多東西,意識(shí)不到問(wèn)題比找不到解決方法要嚴(yán)重很多。比如one-pass 這個(gè),覺得實(shí)現(xiàn)
麻煩不去實(shí)現(xiàn),和覺得實(shí)現(xiàn)沒有意義不去實(shí)現(xiàn)就是不同的。“
對(duì)于以下現(xiàn)象,這句話都可以指明問(wèn)題:
1、認(rèn)為造輪子沒有意義,從不考慮自己是否能造出;
2、常告訴別人某個(gè)技術(shù)復(fù)雜晦澀不利于團(tuán)隊(duì)使用,卻并不懂這個(gè)技術(shù);
3、籠統(tǒng)來(lái)說(shuō),【覺得】太多東西沒有意義,雖然并不真正懂這個(gè)東西。