[转载] ANTLR——编译原理基础知识
來(lái)源:ANTLR中文網(wǎng)站:http://www.antlr.org.cn
?
編譯是將計(jì)算機(jī)高級(jí)語(yǔ)言如C++、Java、C#編寫(xiě)的源程序翻譯成可以在計(jì)算機(jī)上執(zhí)行的機(jī)器語(yǔ)言的翻譯過(guò)程。編譯過(guò)程中分:詞法分析、語(yǔ)法分析、語(yǔ)義分析、源代碼優(yōu)化、代碼生成和目標(biāo)代碼優(yōu)化幾個(gè)過(guò)程。ANTLR解決的是詞法分析和語(yǔ)法分析的問(wèn)題,下面介紹一下編譯原理中有關(guān)詞法分析和語(yǔ)法分析的基本知識(shí)。
?
?
詞法分析是對(duì)源程序一個(gè)一個(gè)字符地讀取,從字符中識(shí)別出標(biāo)識(shí)符、關(guān)鍵字、常量等相對(duì)獨(dú)立的記號(hào)(token,也叫符號(hào)或單詞),形成記號(hào)序列記號(hào)流的過(guò)程。如c、l、a、s、s 五個(gè)字符構(gòu)成了關(guān)鍵字class,2、3構(gòu)成了一個(gè)整型數(shù)23。詞法分析過(guò)程中會(huì)濾掉源程序中的空格、換行符和注釋等不屬于源程序的字符,還可以將記號(hào)歸類(lèi),哪些記號(hào)屬于標(biāo)識(shí)符,哪些記號(hào)屬于關(guān)鍵字、整數(shù)、浮點(diǎn)數(shù)等。記號(hào)流是語(yǔ)法分析的基礎(chǔ)。
語(yǔ)法分析是根據(jù)詞法分析輸出的記號(hào)流,分析源程序的語(yǔ)法結(jié)構(gòu),并添加代表語(yǔ)法結(jié)構(gòu)的抽象單詞(如:表達(dá)式、類(lèi)、方法等),按照語(yǔ)法結(jié)構(gòu)生成語(yǔ)法樹(shù)的過(guò)程。前面講的詞法分析后形成的記號(hào)序列是描述程序的直接標(biāo)識(shí)符序列,是線性的。它沒(méi)有反映出源程序的結(jié)構(gòu)。而語(yǔ)法分析后生成的語(yǔ)法樹(shù)是可以表示源程序結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),語(yǔ)法樹(shù)的葉子節(jié)點(diǎn)就是記號(hào)。下面舉一個(gè)簡(jiǎn)單的例子說(shuō)明詞法分析和語(yǔ)法分析之關(guān)的系統(tǒng),有如下的源程序:
class T {
string Name;// name of T
object GetValue() {
}
}
進(jìn)行詞法分析后形成記號(hào)流:
class T { string Name ; object GetValue ( ) { } }。
?
?
?
?
?
?
進(jìn)行語(yǔ)法分析后形成語(yǔ)法樹(shù):
我們這里不介紹編譯原理的其它部分,因?yàn)锳NTLR只涉及到了詞法分析和語(yǔ)法分析這兩個(gè)部分。讀者可以去參考原理的書(shū)籍。了解ANTLR在編譯過(guò)程中所處的位置后。我們來(lái)詳細(xì)學(xué)習(xí)一下有關(guān)詞法分析和語(yǔ)法分析的基礎(chǔ)概念。
2.1什么是文法
一種程序設(shè)計(jì)語(yǔ)言的語(yǔ)法是規(guī)定源程序的寫(xiě)法是否合法的規(guī)則,它存在于詞法分析和語(yǔ)法分析兩個(gè)階段。如:詞法分析中 123表示合法整數(shù),1_23是不合法整數(shù)。在語(yǔ)法分析中if(boolVar) {}是合法的語(yǔ)句,if(boolVar) { 是不合法的語(yǔ)句。那么我們?cè)鯓觼?lái)定義語(yǔ)法規(guī)則呢?定義語(yǔ)法規(guī)則的工具是文法(grammar),文法是由若干定義語(yǔ)法規(guī)則的推導(dǎo)式組成的。下面例子中用文法定義了人類(lèi)語(yǔ)言的語(yǔ)法規(guī)則:
語(yǔ)言 =>(句子)+
句子 => 主語(yǔ) 謂語(yǔ)
謂語(yǔ) => 動(dòng)詞 賓語(yǔ)
主語(yǔ) => 名詞
賓語(yǔ) => 名詞
名詞 =>‘張三’| ‘代碼’
動(dòng)詞 =>‘編寫(xiě)’
如,‘張三編寫(xiě)代碼’這句話在文法中的推導(dǎo)過(guò)程是:
語(yǔ)言 => 主語(yǔ) 謂語(yǔ)
=> 張三 動(dòng)詞賓語(yǔ)
=> 張三 編寫(xiě)名詞
=> 張三編寫(xiě) 代碼
另外編譯原理中一般用大寫(xiě)字母表示一個(gè)文法的名稱(chēng),再加上文法的啟始規(guī)則組成文法的表示符號(hào)。如上面的文法如果名稱(chēng)為G,可以表示為G[語(yǔ)言]文法。
2.2符號(hào)表、符號(hào)串、推導(dǎo)式和句子
不管是人類(lèi)語(yǔ)言還是計(jì)算機(jī)語(yǔ)言都是用符號(hào)組成的,英文由字母、數(shù)字和標(biāo)點(diǎn)符號(hào)等組成,中文由漢字、數(shù)字和標(biāo)點(diǎn)符等組成,計(jì)算機(jī)語(yǔ)言由關(guān)鍵字、字母、數(shù)字和一些專(zhuān)用符號(hào)組成。
這些組成語(yǔ)言的基本符號(hào)加上推導(dǎo)出基本符號(hào)的抽象符號(hào)集合在一起稱(chēng)為符號(hào)表,用V來(lái)表示,符號(hào)表是不允許為空的。如G[語(yǔ)言]文法的符號(hào)表是:{語(yǔ)言,句子,主語(yǔ),謂語(yǔ),賓語(yǔ),名詞,動(dòng)詞,‘張三’,‘代碼’,‘編寫(xiě)’},符號(hào)表中可以繼續(xù)推導(dǎo)的中間符號(hào)稱(chēng)為非終結(jié)符,用Vn表示,不能再繼續(xù)推導(dǎo)的符號(hào)稱(chēng)為終結(jié)符,用Vt表示。G[語(yǔ)言]文法的非終結(jié)符集合為:{語(yǔ)言,句子,主語(yǔ),謂語(yǔ),賓語(yǔ),名詞,動(dòng)詞},終結(jié)符集合為{‘張三’,‘代碼’,‘編寫(xiě)’}。
符號(hào)表中符號(hào)的任意有窮組合序列稱(chēng)為符號(hào)串。‘張三張三’、‘張三代碼編寫(xiě)’、‘張三語(yǔ)言句子賓語(yǔ)賓語(yǔ)’都是G[語(yǔ)言]文法符號(hào)串。很明顯一種文法的符號(hào)串不一定是這種文法的合法句子。符號(hào)串是有長(zhǎng)度的,它的長(zhǎng)度是符號(hào)的個(gè)數(shù),如‘張三張三’的長(zhǎng)度是2,張三語(yǔ)言句子賓語(yǔ)賓語(yǔ)’的長(zhǎng)度是5。
文法是定義語(yǔ)法規(guī)則的工具,語(yǔ)法規(guī)則簡(jiǎn)稱(chēng)規(guī)則(rule)又稱(chēng)推導(dǎo)式或產(chǎn)生式。假設(shè)a和b都是一個(gè)文法的符號(hào)串,我們用a => b表示一個(gè)規(guī)則,其中a不能為空。也就是說(shuō)“句子 =>”是合法的規(guī)則“ => 主語(yǔ)”是不合法的,一個(gè)文法要由至少要有一個(gè)規(guī)則。規(guī)則a => b使用b來(lái)替換a的過(guò)程叫做推導(dǎo),反用b來(lái)替換a的過(guò)程叫歸約。
如G[S]是一個(gè)文法,S為啟始規(guī)則,從S推導(dǎo)若干次后形成的符號(hào)串叫做G[S]文法的句型。如果推導(dǎo)出的符號(hào)串全都由終結(jié)符組成此符號(hào)串叫做G[S]的句子。前面示例中“張三動(dòng)詞賓語(yǔ)”是G[語(yǔ)言]文法的句型,而“張三編寫(xiě) 代碼”是G[語(yǔ)言]文法的句子。編譯原理中也使用四元組來(lái)表示文法G[Vn,Vt,P,S],其中G為文法句稱(chēng),Vn為非終結(jié)符的集合,Vt為終結(jié)符的集合,P是文法規(guī)則的集合,S為啟始規(guī)則。
2.3文法的類(lèi)型
一個(gè)文法G[S],S為啟始規(guī)則,如果它的所有規(guī)則符合形如:a => b 其中a和b都是G[S]文法的符號(hào)串,但a中至少要有一個(gè)非終結(jié)符,這時(shí)G[S]文法是短語(yǔ)文法。G[語(yǔ)言]為例“賓語(yǔ)張三 => 名詞張三”是短語(yǔ)文法的規(guī)則,“張三編寫(xiě)=> 名詞張三”則不是短語(yǔ)文法,因?yàn)椤皬埲焙汀熬帉?xiě)”都是終結(jié)符規(guī)則左則沒(méi)有非終結(jié)符。我們可以看出短語(yǔ)文法是對(duì)規(guī)則做了一些限制后形成的,下面的文法是對(duì)短語(yǔ)文法做進(jìn)一步限制形成的。
如果G[S]的所有規(guī)則都滿足形如:a => b其中a的長(zhǎng)度要小于等于b,這時(shí)G[S]文法是上下文有關(guān)文法(context-free grammars)。上下文有關(guān)文法的更形象的定義是:文法的所有規(guī)則滿足aBc => abc的形式,其中B是非終結(jié)符,a、b、c是符號(hào)串。也就是說(shuō)B => b只在前面有a后面有c的情況下才能推導(dǎo),所以是上下文有關(guān)的。例如:“張三動(dòng)詞程序 => 張三編寫(xiě)程序”是上下文有關(guān)文法的規(guī)則。
如果G[S] 的所有規(guī)則都滿足形如:a => b其中a是一個(gè)非終結(jié)符,b是符號(hào)串,這時(shí)G[S]文法是上下文無(wú)關(guān)文法(context-sensitive grammars)。就是說(shuō)a推導(dǎo)出b與其前后是什么符號(hào)串無(wú)關(guān)。上面G[語(yǔ)言]的文法就是上下文無(wú)關(guān)文法。
如果G[S] 的所有規(guī)則都滿足形如:A=> aB或A=>a其中A和B是非終結(jié)符,a是終結(jié)符,這時(shí)G[S]文法是正規(guī)文法(regular grammars)。就是說(shuō)規(guī)則的右則要以終結(jié)符開(kāi)頭。如:“謂語(yǔ) => 編寫(xiě) 賓語(yǔ)”,“動(dòng)詞 => 編寫(xiě)” 都是正規(guī)文法的規(guī)則簡(jiǎn)稱(chēng)正規(guī)式,“謂語(yǔ) => 動(dòng)詞賓語(yǔ)” 就不是正規(guī)式。
這四種文法是對(duì)規(guī)則的限制逐步加強(qiáng)形成的。正規(guī)文法是上下文無(wú)關(guān)文法的特例,上下文無(wú)關(guān)文法是上下文有關(guān)文法的特例,上下文有關(guān)文法是短語(yǔ)文法的的特例。文法產(chǎn)生的語(yǔ)言就是該文法的語(yǔ)言,如:上下文無(wú)關(guān)文法產(chǎn)生的語(yǔ)言就是上下文無(wú)關(guān)語(yǔ)言,正規(guī)文法產(chǎn)生的語(yǔ)言就是正規(guī)語(yǔ)言。文法是語(yǔ)言模型。計(jì)算機(jī)語(yǔ)言中普遍采用上下文無(wú)關(guān)文法來(lái)定義語(yǔ)法規(guī)則。下面我們介紹上下文無(wú)關(guān)文法的語(yǔ)法樹(shù)。
圖2.2
2.4語(yǔ)法樹(shù)
編譯技術(shù)中用語(yǔ)法樹(shù)來(lái)更直觀的表示一個(gè)句型的推導(dǎo)過(guò)程。前面我們已經(jīng)提到過(guò)語(yǔ)法樹(shù),相信讀者已經(jīng)對(duì)語(yǔ)法樹(shù)有了一定的認(rèn)識(shí),這里我們給出上下文無(wú)關(guān)文法語(yǔ)法樹(shù)的定義:給定上下文無(wú)關(guān)文法G[S],它的語(yǔ)法樹(shù)的每一個(gè)節(jié)點(diǎn)都有一個(gè)G[S]文法的符號(hào)與之對(duì)應(yīng)。S為語(yǔ)法樹(shù)的根節(jié)點(diǎn)。如果一個(gè)節(jié)點(diǎn)有子節(jié)點(diǎn)。則這個(gè)節(jié)點(diǎn)對(duì)應(yīng)的符號(hào)一定是非終結(jié)符。如果一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的符號(hào)為A,它的子節(jié)點(diǎn)對(duì)應(yīng)的符號(hào)分別為A1,A2,A3…..Ak,那么G[S]文法中一定有一個(gè)規(guī)則為:A=>A1 A2 A3 …..Ak。滿足這些規(guī)定的樹(shù)語(yǔ)法樹(shù)也叫推導(dǎo)樹(shù)。下面給出一下文法K[S2]和K[S2]文法的一個(gè)語(yǔ)型,我們用語(yǔ)法樹(shù)來(lái)顯示這個(gè)語(yǔ)型的推導(dǎo)過(guò)程。
K[S2]文法: S2 => aA
A=> bABc
A=>a
B=>d
K[S2]文法對(duì)于語(yǔ)型abadc的推導(dǎo)樹(shù)為:
推導(dǎo)的過(guò)程中優(yōu)先選擇不同的規(guī)則進(jìn)行推導(dǎo)會(huì)使推導(dǎo)過(guò)程有所不同。下面舉一個(gè)例子。
K[S3]文法:S3 => ABD
A=>a
B=>bC
C=>c
D=>d
下面是對(duì)于句型abcd的三種不同推導(dǎo)過(guò)程。
① S3=> ABD => aBD => abCD => abcD => abcd
② S3=> ABD =>AbCD=>AbcD=>abcD=>abcd
③ S3=> ABD =>ABd=>AbCd=>Abcd=>abcd
我們可以注意到①過(guò)程中所有推導(dǎo)都是選擇的最左邊的非終結(jié)符進(jìn)行替換。③過(guò)程中所有推導(dǎo)都是選擇的最右邊的非終結(jié)符進(jìn)行替換。其中①被稱(chēng)為最左推導(dǎo),③被稱(chēng)為最右推導(dǎo)。這三種推導(dǎo)都對(duì)應(yīng)一棵語(yǔ)法樹(shù),這說(shuō)明語(yǔ)法樹(shù)反應(yīng)了此句型的所有推導(dǎo)過(guò)程。
但是對(duì)于有些句型來(lái)說(shuō),它對(duì)應(yīng)的語(yǔ)法樹(shù)不一定唯一的。也不是說(shuō)一棵語(yǔ)法樹(shù)不一定能反應(yīng)一個(gè)句型的所有推導(dǎo)過(guò)程,如下面給定文法。
S4[E]文法:
E => E + E
E => E * E
E => (E)
E => i
對(duì)于 i + i * i 句型,我們可以寫(xiě)出下面兩種最左推導(dǎo)的過(guò)程:
① E => E + E => E + E * E => i + E * E => i + i * E
② E => E * E => E + E * E => i + E * E => i + i * E
①過(guò)程中第一步使用了E => E + E規(guī)則,②過(guò)程中第一步使用了E => E * E規(guī)則,不管選擇哪個(gè)規(guī)則都是最左推導(dǎo)。下面有兩棵語(yǔ)法樹(shù)與之對(duì)應(yīng)。對(duì)于一個(gè)文法的句型如果有多于一棵的語(yǔ)法樹(shù)與之對(duì)應(yīng),則這個(gè)文法是有二義性的文法。也可以用另一種方法判斷,如果一個(gè)文法的最左或最右推導(dǎo)的過(guò)程是不唯一的也可以說(shuō)這個(gè)文法是有二義性的文法。
??????????? 推導(dǎo)1的語(yǔ)法樹(shù)???????????????????????????????? 推導(dǎo)2的語(yǔ)法樹(shù)
二義性文法是在開(kāi)發(fā)語(yǔ)法分析器時(shí)需要解決的問(wèn)題,我們將S4[E]加入操作符優(yōu)先關(guān)系改成下面形式可以去掉文法的二義性。
S5[E]文法:
E => T + T
E => T
T => F * F
T => F
F => (E)
F => i
使用S5[E]文法對(duì)于 i + i * i 句型的推導(dǎo)過(guò)程和語(yǔ)法樹(shù)是唯一的:
E => T + T => T + F * F => F + F * F => i + F * F => i + i * F => i + i * i
?
由于文法簡(jiǎn)單所以二義性比較容易解決,但是當(dāng)文法很復(fù)雜的時(shí)候,檢查文法中是否存在二義性就困難了。但ANTLR的開(kāi)發(fā)者不用擔(dān)心,ANTLR會(huì)象我們編譯普通源程序那樣提示文法中的問(wèn)題,其中包括文法的二義性問(wèn)題,這使我們可以很容易的找到存在二義性的規(guī)則。
?
?
2.5分析方法
前面講到了句型的推導(dǎo)過(guò)程和生成語(yǔ)法樹(shù)的過(guò)程,有了語(yǔ)法樹(shù)就已經(jīng)很清晰的看到了句型的結(jié)構(gòu),我們可以很容易的從語(yǔ)法樹(shù)中獲得我們相要的信息,這個(gè)過(guò)程就是語(yǔ)法分析。如圖2.3顯示了對(duì)于SELECT F1, F2 FROM Table1 WHERE F1=”a”的語(yǔ)句進(jìn)了語(yǔ)法分析后生成的語(yǔ)法樹(shù),利用非終結(jié)符節(jié)點(diǎn)SeletctList很容易對(duì)應(yīng)Select語(yǔ)句的F1,F2部分。
圖2.3
我們前面的推導(dǎo)是靠自己主觀判斷,選擇適當(dāng)?shù)囊?guī)則進(jìn)行推導(dǎo)的。那么如何用程序來(lái)實(shí)現(xiàn)這個(gè)過(guò)程呢?語(yǔ)法分析方法分兩大類(lèi):自頂向下的分析方法和自下而上的分析方法。ANTLR使用的是自頂向下的分析方法。自頂向下的分析方法的思路是從起始規(guī)則開(kāi)始選擇適當(dāng)?shù)囊?guī)則反復(fù)推導(dǎo),直到推導(dǎo)出待分析的語(yǔ)型。如果推導(dǎo)失敗則反回選擇其它規(guī)則進(jìn)行推導(dǎo)(這個(gè)過(guò)程叫做回朔(backtrack)),如果所有規(guī)則都失敗說(shuō)明這個(gè)句型是非法的。下面舉一個(gè)分析的示例。
D1[S]文法:
S => aBd
B => b
B = > bc
對(duì)于abcd句型進(jìn)行自頂向下分析,第一步唯一的選擇規(guī)則S => aBd,第二步對(duì)非終結(jié)符B的推導(dǎo),先選擇B => b推導(dǎo)出S => abd這和句型abcd不同所以推導(dǎo)失敗。現(xiàn)在返回到對(duì)B的推導(dǎo),選擇另一個(gè)規(guī)則B => bc行出S => abcd這次推導(dǎo)成功。
自下而上的分析方法與自頂向下分析方法相反,過(guò)程是逐個(gè)的掃描句型的符號(hào)使用適當(dāng)?shù)囊?guī)則進(jìn)行反復(fù)歸約,直到歸約成啟始規(guī)則S。如果這個(gè)過(guò)程失敗,則返回選擇其它規(guī)則進(jìn)行歸約。我們使用自下而上的分析方法對(duì)D1[S]示例進(jìn)行分析。首先是掃描到了第一個(gè)符號(hào)a,a無(wú)法歸約沒(méi)有象X => a這樣的規(guī)則。然后繼續(xù)掃描符號(hào)b,b可以用B = > b來(lái)歸約得出aB。然后掃描到符號(hào)c,這時(shí)aBc不能繼續(xù)進(jìn)行歸約造成過(guò)程失敗。所以要返回前一步使用B => bc來(lái)歸約得出aBd,aBd可以用S => aBd歸約到S。
不管是自下而上的分析方法還是自頂向下分析方法如果選擇的規(guī)則不正確,就要返回重新嘗試用其它規(guī)則進(jìn)行推導(dǎo)或歸約。這在實(shí)際操作中會(huì)浪費(fèi)很多時(shí)間分析程序的執(zhí)行效率會(huì)降低。為了解決這個(gè)問(wèn)題,在編譯技術(shù)中使用一種向前探測(cè)符號(hào)的方法(lookahead)保證可以正確選擇規(guī)則。如D1[S]示例的自頂向下分析的第二步如果選擇B => b則得出ab句型后面的符號(hào)為c,如果選擇B => b規(guī)則推導(dǎo)將得出abd,所以不能選擇B => b規(guī)則。如果選擇B => bc可以得出abc和后面的符號(hào)d相符,所以應(yīng)該選擇B => bc規(guī)則。
在自下而上的分析方法中讀取前兩個(gè)符號(hào)ab時(shí)b可以用規(guī)則B=>b歸約,這時(shí)向前探測(cè)一符號(hào)為c可以得出aBc,但aBc沒(méi)有規(guī)則可以歸約。所以再讀取一個(gè)符號(hào)c符,選擇B=>bc規(guī)則歸約。向前探測(cè)一符號(hào)為d,aBd可以規(guī)約成S分析成功。
2.6有害規(guī)則
在文法可能會(huì)出現(xiàn)一些無(wú)用的、造成文法二義性的規(guī)則。如左右兩側(cè)相同的規(guī)則A =>A,這種規(guī)則在文法中沒(méi)有意義,如果還有一條規(guī)則S => A,當(dāng)我們用A歸約時(shí)A=>A會(huì)干擾使分析器不知道應(yīng)該用哪一個(gè)規(guī)則歸約同,如果不斷使A => A歸約會(huì)造成死循環(huán)。如果一個(gè)非終結(jié)符不出現(xiàn)在任何規(guī)則的右部,那么這個(gè)非終結(jié)符是不可達(dá)的,也就是說(shuō)沒(méi)有句型在推導(dǎo)或歸約過(guò)過(guò)程中會(huì)用到這個(gè)非終結(jié)符。如一個(gè)文法中有規(guī)則 A => a但是沒(méi)有形如X => A的規(guī)則那么A=>a在文法中是多余的。還有一種叫做不可終止的非終結(jié)符,如一個(gè)文法中對(duì)于A非終結(jié)符來(lái)說(shuō)只有A => Aa這個(gè)規(guī)則,可以看出A無(wú)法推導(dǎo)出一個(gè)句子它也是多余的。這些規(guī)則應(yīng)該在文法中刪除。
2.7左遞歸、右遞歸
形如A => Ab的規(guī)則,A的定義是遞歸的可以推導(dǎo)出Abbbb…b,左側(cè)的非終結(jié)符A可以不斷地推導(dǎo)出Ab,這種處于規(guī)則左側(cè)的遞歸叫左遞歸。遞歸也可能出現(xiàn)在多個(gè)非終結(jié)符之間A=>Bd,B=>Bc這里的A=>Bd也是左遞歸。例如我們要定義一個(gè)整型數(shù)其規(guī)則為:INT => INT Digital,Digital => 0|1|2|3|4|5|6|7|8|9,規(guī)則INT用左遞歸實(shí)現(xiàn)了多位整型數(shù)的定義。相反形如A => bA的規(guī)則,A的定義也是遞歸的但和左遞歸相反非終結(jié)符A在規(guī)則的右側(cè)這樣遞歸叫做右遞歸。我們可以把整型數(shù)定義的規(guī)則用右遞歸的方法定義為INT => Digital INT,Digital => 0|1|2|3|4|5|6|7|8|9。使用這兩種遞歸的方法時(shí),要看語(yǔ)法分析程序的分析方式,如果語(yǔ)法分析程序是從左向右分析的,那么使用右遞歸比較適合,反之使用左遞歸比較適合。
2.8文法定義基礎(chǔ)
ANTLR的文法定義使用了類(lèi)似EBNF(Extended Backus-Naur Form)的定義方式,是一種強(qiáng)大簡(jiǎn)潔的文法定義方式。本章前面的文法定義的寫(xiě)法比較繁瑣,定義復(fù)雜的文法時(shí)非常不便,文法的可讀性也會(huì)較差。ANTLR的文法定義方式形象直觀,可以用很短的行數(shù)描述以前要很多行才能表示的文法內(nèi)容。
規(guī)則的表示:文法是由規(guī)則組成的,本章前面的規(guī)則都是用A=>a形式來(lái)表示的。ANTLR用A : a;來(lái)表示規(guī)則,“:”代替了“=>”。ANTLR的規(guī)則要以分號(hào)“;”結(jié)束。在規(guī)則中有幾種運(yùn)算關(guān)系,選擇、連接、重復(fù)、可選。
連接“ ”:規(guī)則A : a b c; a、b、c之間用空格分隔。此規(guī)則接收句型abc,符號(hào)a、b、c是按順序連接起來(lái)的關(guān)系。
選擇“| ”:規(guī)則A : a | b | c; “|”表示“或”的關(guān)系,符號(hào)A可以推導(dǎo)出a或b或c,也就是在a、b、c中選擇。這要比寫(xiě)成A : a; A : b; A : c;方便得多。連接和選擇可以聯(lián)合起來(lái)使用,如A : a b c | c d e;。有進(jìn)也會(huì)使句型的數(shù)量增多如:A : B D; B : a | b; D : c | d;這時(shí)符號(hào)A推導(dǎo)出的句型有 ac、ad、bc、bd四種。
重復(fù)“*,+”:規(guī)則A : a*; “*”表示a可以出現(xiàn)0次或多次。A : a*; 相當(dāng)于A : A a | ;。這樣可以避免遞歸的定義,可文法定義中遞歸往往引起文法的二義性。如果a至少要出現(xiàn)一次可以表示為A : a+; “+”表示a可以出現(xiàn)1次或多次。相當(dāng)于A : A a | a;。重復(fù)可以和連接、選擇一起使用如:A : a* b | c+ d;。
可選“?”:規(guī)則A : a?; “?”表示a可以出現(xiàn)0次或1次,即a可有可無(wú)。相當(dāng)于A : a | ;。可選可以和連接、選擇、重復(fù)一起使用如:A : a* b? | c+ d?;。
子規(guī)則“()”:規(guī)則A : (a b) | b; a與b在括號(hào)中,這樣“(a b)”形成了一個(gè)子規(guī)則,也就是說(shuō)可以把規(guī)則寫(xiě)成A : B | b; B : a b;兩個(gè)規(guī)則表示,我們把B規(guī)則用括號(hào)括起來(lái)放到A規(guī)則中這樣就是A規(guī)則的子規(guī)則了。利用子規(guī)則也可以把多個(gè)符一起進(jìn)行描述,A : (a b c)* 規(guī)則中a、b、c三個(gè)符號(hào)可以一起重復(fù)0次或多次。子規(guī)則有利于我們把很復(fù)雜的多個(gè)規(guī)則寫(xiě)到一起,有時(shí)這樣寫(xiě)會(huì)使文法既簡(jiǎn)練又直觀。子規(guī)則和前面的各種特性用到一起可以把復(fù)雜的文法寫(xiě)的很濃縮。如:A : (a b c)* | (c d)+ e?;。
值得注意的是如果我們的規(guī)則中有“()”的字符該如何表示?因?yàn)樽右?guī)則也是用“()”表示的。在ANTLR中表示字符要用“’”單引號(hào)括起來(lái),用‘(’ ‘)’來(lái)表示括號(hào)字符。前面講到的表示文法規(guī)則的符號(hào)“| * + () ?”叫做文法的元符號(hào)。
注釋“// /**/”:和一般編程語(yǔ)言一樣,ANTLR在文法定義中也可以添加注釋。用//來(lái)添加單行注釋,如規(guī)則E : ‘(’ E ‘)’ | INT // E表示算術(shù)表達(dá)式。用/*…*/添加多行注釋,與C++相同。
2.9本章小結(jié)
本章學(xué)習(xí)了編譯原理的基礎(chǔ)知識(shí)。包括:什么叫詞法分析和語(yǔ)法分析,ANTLR在編譯技術(shù)中所處的位置。什么叫文法,規(guī)則。什么叫短語(yǔ)文法,上下有關(guān)文法,上下文法無(wú)關(guān)文法,正規(guī)文法。語(yǔ)法樹(shù),句型的最左推導(dǎo)最右推導(dǎo)和文法的二義性,自頂向下的分析方法和自下而上的分析方法。ANTLR的文法定義方法。
轉(zhuǎn)載于:https://www.cnblogs.com/6DAN_HUST/archive/2008/12/24/1361553.html
總結(jié)
以上是生活随笔為你收集整理的[转载] ANTLR——编译原理基础知识的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 剧本翻译之SHUFFLE 6月24日
- 下一篇: 从网游策划谈《梦幻西游》的成功之道