版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
-.z.Antlr簡(jiǎn)介06通訊軟件06382027毅本文主要介紹了什么是ANTLR,以及ANTLR的使用,其中ANTLR的使用包括了ANTLR的安裝及使用,ANTLR語法文件解析,ANTLR規(guī)則(RULE)解析,ANTLR語法實(shí)例—SensorSQL,ANTLRStudio及其功能介紹等。Antlr(ANotherToolforLanguageRecognition)是一個(gè)工具,前身是PCCTS,它為我們構(gòu)造自己的識(shí)別器(recognizers)、編譯器(piler)和轉(zhuǎn)換器(translators)提供了一個(gè)基礎(chǔ)。通過定義自己的語言規(guī)則,Antlr可以為我們生成相應(yīng)的語言解析器,這樣便可以省卻了自己全手工打造的勞苦。它是這樣的一種工具,它可以接受文法語言描述,并能產(chǎn)生識(shí)別這些語言的語句的程序。作為翻譯程序的一部分,你可以使用簡(jiǎn)單的操作符和動(dòng)作來參數(shù)化你的文法,使之告訴ANTLR怎樣去創(chuàng)建抽象語法樹(AST)和怎樣產(chǎn)生輸出。ANTLR知道怎樣去生成識(shí)別程序,語言包括Java,C++,C*和不久的Python。ANTLR知道怎樣構(gòu)建識(shí)別程序,這些程序可以對(duì)以下三種不同的輸入應(yīng)用文法結(jié)構(gòu):(i)字符流,(ii)記號(hào)流,和(iii)兩維的樹結(jié)構(gòu)。很自然的它們分別與詞法分析程序(le*ers,以下簡(jiǎn)稱le*er),語言解析程序和樹遍歷程序向匹配。這個(gè)用于定義這些語法的元語言,在所有情況下幾乎一樣的。一旦你對(duì)ANTLR和類似工具比較順手,你會(huì)開始以一種新的目光來看編程。許多任務(wù)強(qiáng)烈需要語言解決方案,而不是采用傳統(tǒng)編程語言的做法。比如,這些過程的注解都是用特倫斯標(biāo)記語言寫的。而ANTLR則能來將文本(含一些額外的東西和轉(zhuǎn)換)轉(zhuǎn)化為HTML,PDF或者其他那些生成程序的文件格式。最后,ANTLR只是一件工具,僅僅這些。雖然它能通過將容易理解的乏味部分自動(dòng)化來幫助你創(chuàng)建軟件,但卻不能企圖讓你指定整個(gè)編譯器。例如,在單個(gè)的描述里就不行。那些宣稱這類事情非常偉大,可以為發(fā)布刊物文章編寫驚人的“一攬子解決方案”,卻會(huì)悲慘失敗在實(shí)際項(xiàng)目中。詞法分析器(Le*er)詞法分析器又稱為Scanner,Le*icalanalyser和Tokenizer。程序設(shè)計(jì)語言通常由關(guān)鍵字和嚴(yán)格定義的語法結(jié)構(gòu)組成。編譯的最終目的是將程序設(shè)計(jì)語言的高層指令翻譯成物力機(jī)器或虛擬機(jī)可以執(zhí)行的指令。此法分析器的工作是分析量化那些本來毫無意義的字符流,將他們翻譯成離散的字符組(也就是一個(gè)一個(gè)的Token)括關(guān)鍵字,標(biāo)識(shí)符,符號(hào)(symbols)和操作符供語法分析器使用。語法分析器(Parser)編譯器又稱為Syntacticalanalyser。在分析字符流的時(shí)候,Le*er不關(guān)心所生成的單個(gè)Token的語法意義及其與上下文之間的關(guān)系,而這就是Parser的工作。語法分析器將收到的Tokens組織起來,并轉(zhuǎn)換成為目標(biāo)語言語法定義所允許的序列。無論是Le*er還是Parser都是一種識(shí)別器,Le*er是字符序列識(shí)別器而Parser是Token序列識(shí)別器。他們?cè)诒举|(zhì)上是類似的東西,而只是在分工上有所不同而已。ANTLRANTLR將上述兩者結(jié)合起來,它允許我們定義識(shí)別字符流的詞法規(guī)則和用于解釋Token流的詞法分析規(guī)則。然后,ANTLR將根據(jù)用戶提供的語法文件自動(dòng)生成相應(yīng)的詞法/語法分析器。用戶可以利用他們將輸入的文本進(jìn)行編譯,并轉(zhuǎn)換成其他形式(如AST—AbstractSynta*Tree,抽象的語法樹)。Antlr使用安裝及使用到./下載最新版本的ANTLR開發(fā)包和源碼(例如版本3.01)。將antlr-.jar所在目錄配置到你的環(huán)境變量中,寫好語法文件(例如SensorSQL.g),運(yùn)行命令“javaantlr.ToolSensorSQL.g”就可以獲得自動(dòng)生成語法/詞法分析器。ANTLR語法文件解析下面我們對(duì)圖中所描述的ANTLR語法文件做一些詳細(xì)的分析。為了更好的使用ANTLR,你還可以下載ANTLR的Eclipse插件來幫助你完成工作。1.header域:所有出現(xiàn)在這里的部分,都會(huì)出現(xiàn)在由ANTLR編譯之后生成的Java文件的最頂部。在本例中你可以將包名和其他信息放到這一區(qū)域中,生成的結(jié)果如由面對(duì)應(yīng)代碼部分所示。2.你在這一部分所提供的容對(duì)于文件中的每個(gè)語法都是唯一的。這一區(qū)域的容將出現(xiàn)在實(shí)際的類定義之前。也就是說,兩個(gè)import僅屬于類CalcParser,而不屬于在同一個(gè)文件中定義的其他類(如CalcLe*er)3.這里是語法定義部分,你同樣可以將它看成是類定義。4.在Option域中,你可以為你的語法提供可選項(xiàng)。例如是否建立缺省的抽象語法樹,指定LL(K)中的參數(shù)k的值(缺省為1)等等,更詳細(xì)的參數(shù)請(qǐng)參閱ANTLR自帶的手冊(cè)。5.Token部分用來聲明那些在詞法分析器中沒有被聲明的“想象的”token。這些信息通常用在TreeParser中指定“想象”的節(jié)點(diǎn)。6.這是另一個(gè)Action區(qū),ANTLR將會(huì)忠實(shí)地將這一區(qū)域的信息放置到類的定義當(dāng)中,相當(dāng)于類的成員方法,主要為用戶提供一種在Parser種定制可擴(kuò)展方法的途徑。ANTLR規(guī)則(RULE)解析在ANTLR的語法文件中,一個(gè)規(guī)則的定義是與一個(gè)由ANTLR生成的Java源文件相對(duì)應(yīng)的。1,2,3,4:正如你所看到的那樣,我們可以在一個(gè)規(guī)則定義中作與一個(gè)函數(shù)等價(jià)的所有事情。我們可以為規(guī)則指定參數(shù)(像上面的inta),制定返回值(intc),甚至拋出一個(gè)異常。從右半面我們可以清楚地看到,所有在規(guī)則中定義的容都被忠實(shí)而準(zhǔn)確的翻譯到Java源文件的相應(yīng)位置。5:這一可選的部分為我們提供了指定*些可選參數(shù)的能力。例如圖中所示代表告訴ANTLR在生成代碼的時(shí)候不要生成缺省的錯(cuò)誤處理部分,這部分將由用戶自己負(fù)責(zé)。7:在異常處理部分,我們可以指定自定義的異常處理方法。像這里就僅僅是打印錯(cuò)誤棧信息。ANTLR語法實(shí)例—SensorSQLSensorSQL是一個(gè)自定義的簡(jiǎn)化版SQL語言,它所支持的語法定義這里就不詳細(xì)列出了,我只是給出查詢的示例:通常,編譯一個(gè)查詢的目的是要把它轉(zhuǎn)化成*種被查詢?cè)O(shè)備可以理解的形式。通常的做法有兩種,一種是像在上一節(jié)中提到的那樣,寫好詳細(xì)的語法規(guī)則,在ANTLR生成相應(yīng)的Java文件之后,就可以直接使用其運(yùn)行結(jié)果。這樣的例子有很多,其中最典型的就是對(duì)于算數(shù)表達(dá)式的解析了。對(duì)于形如1+2-3*4/5^6這樣的表達(dá)式,只要寫好語法規(guī)則,就可以在解析過程中直接得到運(yùn)算結(jié)果:首先ANTLR將其編譯成逆波蘭結(jié)構(gòu)--(-(+12)(/(*34)(^56)));在生成語法樹的過程中,同步計(jì)算表達(dá)式的值,即類似于2.3節(jié)中看到的表達(dá)式計(jì)算。結(jié)果如下:不過這樣作有一個(gè)缺點(diǎn),就是在很多情況下,你可能并不知道要用什么樣的方法來處理。所以當(dāng)真正要開始寫處理代碼的時(shí)候,就要受限于已有的Parser/Le*er中的代碼。一旦要有所修改,就要重新編譯語法文件,生成新的Java代碼,不勝繁瑣。而且,一旦處理過程有誤,就要反復(fù)調(diào)試修改Antlr生成的代。自動(dòng)生成的代碼嘛,結(jié)構(gòu)著實(shí)也不怎么樣,調(diào)試的時(shí)候也麻煩。所以如果效率允許的話,就沒有必要讓Antlr作額外的工作,干脆就專心于做他的語法分析也就是了,其他的工作等到生成語法樹之后再怎么遍歷或者折騰都可以嘛J。上圖就是剛才演示的SensorSQL語法分析之后產(chǎn)生的結(jié)果。在產(chǎn)生這個(gè)結(jié)果之后,我需要將每一個(gè)語法元素翻譯成字節(jié)序列打包發(fā)送給傳感器網(wǎng)絡(luò)。這時(shí)候,為了保證Where語句中的優(yōu)先級(jí),你就可以按照ANTLR文檔中關(guān)于生成語法樹的一章,生成類似于這樣的結(jié)構(gòu),然后只需前序遍歷這顆語法樹的Where部分就可以達(dá)到目的,至于其他部分,順序遍歷一遍就好了。ANTLRStudio有了前面的基礎(chǔ)之后,我們就可以開始真正的工作了。不過用“記事本或Editplus+命令行”或者干脆寫個(gè)ANT腳本也不是不可以,但是總覺得在集成化IDE滿天飛的時(shí)代用這個(gè)方式有點(diǎn)過于原始,幸好PlacidSystem為我們提供了一個(gè)Eclipse插件來使我們有機(jī)會(huì)直接走出原始社會(huì)。下載地址為:.placidsystems./,目前最新版本是1.1.0。唯一令人遺憾的是這個(gè)插件雖然功能很完善,卻是要收費(fèi)的,否則只有11天的試用期。ANTLRStudio插件的安裝Eclipse下插件的安裝自不必多說,要注意的是從PlacidSystem上提供的license文件,下載之后它的名字為license.lic.t*t,要把它的后綴名.t*t去掉,然后放到ECLIPSE_DIR\plugins\AntlrStudio_*.*.*目錄(這里*.*.*是版本號(hào),例如-1.1.0)。安裝成功之后在Eclipse的工具欄上會(huì)出現(xiàn)一個(gè)詞法分析器的導(dǎo)航按鈕:當(dāng)右鍵單點(diǎn)擊你的工程時(shí),你會(huì)發(fā)現(xiàn)控制是否使用ANTLRStudio的開關(guān):當(dāng)打開一個(gè)文法文件之后,可以看到如下界面:在右面的大綱窗口,列有所有Parser和Le*er的元素,可以看到ProtectedToken(例如Number)和其他普通的Token是不一樣的;在左面,不同的區(qū)域是用不同的顏色塊加亮來區(qū)分的。功能介紹ANTLRStudio在EclipseHelp提供了比較詳盡的文檔描述,所以這里我只介紹一些1.1.0版本的新功能。l完全支持ANTLR,并支持將之前的工程自動(dòng)升級(jí)到1.1.0版本。lSynta*DiagramView,可以方便的查看所輸入的語法結(jié)構(gòu)。l改進(jìn)了Debug功能,可以調(diào)試比較大的文法文件。而在這之前,如果一個(gè)文法文件很大的話,ANTLRStudio就會(huì)拋出異常。l支持自動(dòng)的代碼補(bǔ)全功能,提供一個(gè)ANTLR文檔的比較全面的提示信息(如下所示)。語法圖表視圖(Synta*DiagramView)在Window->ShowView->Other中選擇顯示這個(gè)視圖之后,你就可以使用這個(gè)很酷的功能了利用這個(gè)視圖,你可以很容易的看到你定義語法的語法結(jié)構(gòu),例如,我的SELECT語句定義如下你只需要將光標(biāo)標(biāo)放到selectStatement規(guī)則的任意位置,就可以在Synta*DiagramView中看到:于是完整的語法結(jié)構(gòu)清晰的顯示在了我們面前。這時(shí)你只需要將光標(biāo)放到脫字符號(hào)(^)上面(注:脫字符號(hào)用于指明在生成語法樹的時(shí)候,脫字符號(hào)所在的SubRule要作為樹或子樹的根節(jié)點(diǎn)):就會(huì)看到:對(duì)應(yīng)的SubRule被加亮成粉紅色,而如果你的光標(biāo)放到的位置是一個(gè)Token的話就會(huì)變成淡藍(lán)色,簡(jiǎn)直太酷了。增強(qiáng)的Debug功能想要啟動(dòng)或關(guān)閉ANTLRStudio的Debug功能,需要完成以下步驟:l在工程中啟用/取消ANTLRStudiol右鍵單擊工程,打開“屬性”中的ANTLRStudio選項(xiàng)卡。l選擇/取消'Enabledebuggingingrammarfiles'
做完這些后,我們就可以痛快的使用其Debug功能了。與調(diào)試其他Java文件一樣,我們可以在語法文件的任意位置插入斷點(diǎn):當(dāng)程序運(yùn)行至斷點(diǎn)之后,我們同樣可以像調(diào)試普通應(yīng)用程序一樣使用諸如“跳過”,“繼續(xù)”等Java應(yīng)用程序的Debug方式來進(jìn)行,十分的方便和順手。注:以上資料均來于網(wǎng)絡(luò),鄙人收集整理。ANTLR中文手冊(cè)06通訊軟件06382027毅本文主要概括了一些常用的ANTLR的使用方法,其中有Antlr的主要類,Antlr文法文件形式,生成Java類,如何生成Java類,如何執(zhí)行以及元語言詞匯表。一、Antlr的主要類:Antlr中有主要類有兩種(其實(shí)還有一種TreeLe*er)
Le*er:文法分析器類。主要用于把讀入的字節(jié)流根據(jù)規(guī)則分段。既把長(zhǎng)面條根據(jù)你要的尺寸切成一段一段:)并不對(duì)其作任何修改。
Parser:解析器類。主要用于處理經(jīng)過Le*er處理后的各段。一些具體的操作都在這里。
二、Antlr文法文件形式:
Antlr文件是*.g形式,即以g為后綴名。
例如:t.g
classPe*tendsParser;
startRule
:n:NAME
{System.out.println("Hithere,"n.getTe*t());}
;
classLe*tendsLe*er;
//one-or-morelettersfollowedbyanewline
NAME:(’a’……’z’|’A’……’Z’)NEWLINE
;
NEWLINE
:’\r’’\n’//DOS
|’\n’//UNI*
;
具體成分分析:
1、總體結(jié)構(gòu)
ClassPe*tendsParser
ClassLe*tendsLe*er
兩行同JAVA繼承一樣,P繼承Parser類;L繼承Le*er類。每個(gè).g文件只能各有一個(gè)。
2、Le*er類分析
一般按照類型名:(匹配的具體規(guī)則)的形式構(gòu)成。是分隔字節(jié)流的依據(jù)。同時(shí)可以看到里面可以互相引用。如本例中的類型名NEWLINE出現(xiàn)在NEW的匹配規(guī)則中。
3、Parser類分析
一般按照
起始規(guī)則名:
規(guī)則實(shí)例名:類型名或規(guī)則名
{Java語句……;}
;
起始規(guī)則名:任意。
規(guī)則實(shí)例名:就象Java中“Strings;”的s一樣。規(guī)則實(shí)例名用于在之后的JAVA語句中調(diào)用。
類型名或規(guī)則名:可以是在Le*er中定義的類型名,也可以是Parser中定義的規(guī)則名。感覺就像是int與Integer的區(qū)別。
Java語句:指當(dāng)滿足當(dāng)前規(guī)則時(shí)所執(zhí)行的語句。Antlr會(huì)自動(dòng)嵌入生成的java類中。三、生成Java類
1、從.上下載antlr-*.*.*.jar
2、配置環(huán)境變量:classpath=.;*:\jdk\lib\tools.jar;*:\antlr-*.*.*.jar
3、在t.g所在目錄下執(zhí)行:
javaantlr.Toolt.g
會(huì)在當(dāng)前目錄下生成如下文件:
L.java:Le*er文法分析器java類。
P.java:Parser解析器java類。
PTokenTypes.java:Le*er中定義的類型具體化,供Parser解析器調(diào)用。
PTokenTypes.t*t:當(dāng)外部的(如t2.g)要調(diào)用當(dāng)前的類型或規(guī)則時(shí)要用到本文件。四、執(zhí)行
1、編寫Main類
importjava.io.*;
classMain{
publicstaticvoidmain(String[]args){
try{
Lle*er=newL(newDataInputStream(System.in));
Pparser=newP(le*er);parser.startRule();
}catch(E*ceptione){
System.err.println("e*ception:"e);
}
2、執(zhí)行
c:\>javac*.java
c:\>javaMain
Terence
^Z
Hithere,Terence
c:\>元語言詞匯表空格定義空格,tab符號(hào)和換行符號(hào)在ANTLR分隔諸如標(biāo)識(shí)符這樣的詞匯符號(hào)時(shí)作為分隔符。在這之外,它們是被忽略的。例如,“FirstNameLastName”對(duì)ANTLR來說兩個(gè)標(biāo)記符而不是一個(gè)標(biāo)記符,空格,然后再接著一個(gè)標(biāo)記符。注釋ANTLR接受C語言風(fēng)格的塊注釋和C++風(fēng)格的行注釋。在語法類和規(guī)則中,Java風(fēng)格的文檔注釋也是可以接受的,在需要的時(shí)候,這些注釋可以被傳遞給生成的輸出文件。例如/**Thisgrammarrecognizessimplee*pressions*authorTerenceParr*/classE*prParser;/**Matchafactor*/factor:...;字符集字符常數(shù)像Java中那樣被確定。它們包含八進(jìn)制轉(zhuǎn)義字符集(e.g.,'\377'),Unicode字符集(e.g.,'\uFF00'),和能被Java識(shí)別的常用的字符轉(zhuǎn)義('\b','\r','\t','\n','\f','\'','\\')。在詞法分析器規(guī)則中,單引號(hào)代表一個(gè)可以在輸入字符流中能得到匹配的的字符。在語法分析器中是不被支持單引號(hào)的字符的。文件結(jié)束標(biāo)志EOF標(biāo)記用語法分析器規(guī)則中自動(dòng)生成:rule:(statement)+EOF;你可以在詞法分析器規(guī)則的動(dòng)作中檢測(cè)EOF_CHAR符號(hào)://makesurenothingbutnewlineor//EOFispastthe*endifENDIF{booleaneol=false;}:"*endif"(('\n'|'\r'){eol=true;})"{if(!eol){if(LA(1)==EOF_CHAR){error("EOF");}else{error("Invalidchars");}}};當(dāng)你將文件結(jié)束當(dāng)一個(gè)字符來檢測(cè)時(shí),它實(shí)際上并不是一個(gè)字符,而是一個(gè)條件。你可以在你的詞法分析器語法中覆蓋
CharScanner.uponEOF()函數(shù):/**ThismethodiscalledbyYourLe*er.ne*tToken()*whenthele*erhas*hitEOFcondition.EOFisNOTacharacter.*ThismethodisnotcalledifEOFisreached*duringsyntacticpredicateevaluationorduring*evaluationofnormalle*icalrules,which*presumablywouldbeanIOE*ception.This*trapsthe"normal"EOF*condition.**uponEOF()iscalledafterthepleteevaluation*oftheprevioustokenandonlyifyourparserasks*foranothertokenbeyondthatlastnon-EOFtoken.**Youmightwanttothrowtokenorcharstream*e*ceptionslike:"Heh,prematureeof"oraretry*streame*ception("Ifoundtheendofthisfile,*gobacktoreferencingfile").*/publicvoiduponEOF()throwsTokenStreamE*ception,CharStreamE*ception{}文件結(jié)束條件是一個(gè)位比特。因?yàn)門erence將-1當(dāng)作一個(gè)字符而不是一個(gè)整型數(shù)。(-1是'\uFFFF').字符串字符串常數(shù)一個(gè)由雙引號(hào)括起來的一系列字符。在字符串中的字符可以是作為字符也同樣合法的轉(zhuǎn)義字符(八進(jìn)制,Unicode等)。當(dāng)前,ANTLR實(shí)際上不允許Unicode出現(xiàn)在字符串常量中(你不得不用轉(zhuǎn)義符)。這是因?yàn)樵赼nglr.g文件中設(shè)定charVocabulary選項(xiàng)為ascii.在詞法分析器規(guī)則中,字符串被解釋成可以在輸入流中匹配的一系列字符(例如.,"for"等于'f''o''r').在語法分析器規(guī)則中,字符串代表一個(gè)個(gè)標(biāo)記(tokens),并且每個(gè)獨(dú)立的字符串被分派一個(gè)標(biāo)記類型。然而,ANTLR不會(huì)創(chuàng)建一個(gè)詞法分析器規(guī)則來匹配這些字符串。相反,ANTLR將這些字符串輸入到一個(gè)于詞法分析器關(guān)聯(lián)的字符常量表中。ANTLR將針對(duì)字符常量表來產(chǎn)生代碼檢測(cè)每個(gè)標(biāo)記中的文本,在手動(dòng)關(guān)掉語法分析器對(duì)該標(biāo)記的處理之前獲得一個(gè)匹配時(shí),會(huì)改變標(biāo)記的類型。你也可以執(zhí)行手動(dòng)檢測(cè)――自動(dòng)代碼生成可以通過詞法分析器選項(xiàng)控制。你可能想在你的動(dòng)作中使用這些字符串常量的標(biāo)記的類型值,例如在錯(cuò)誤處理器的同步部分。對(duì)于只由字母字符組成的字符串常量來說,這個(gè)字符串常量的值將是一個(gè)形如LITERAL_***的常量值,這里***是這個(gè)標(biāo)記的名字。例如,文字“return”將有一個(gè)LITERAL_return值與之關(guān)聯(lián)。你也可以用標(biāo)記節(jié)(tokenssection)分派一個(gè)特定的標(biāo)號(hào)給這個(gè)文字。標(biāo)記引用以大寫字符開頭的標(biāo)識(shí)符稱為標(biāo)記引用。接下來的字符可以是任何字符,數(shù)字或下劃線。在語法分析器規(guī)則中一個(gè)標(biāo)記引用將導(dǎo)致匹配特定的標(biāo)記。在詞法分析器中的標(biāo)記引用將導(dǎo)致調(diào)用一個(gè)詞法規(guī)則來匹配該標(biāo)記的字符。換句話說,在詞法分析器中的標(biāo)記引用將對(duì)當(dāng)作一個(gè)規(guī)則引用。標(biāo)記定義在詞法分析器中的標(biāo)記定義由和語法規(guī)則中相同的定義。但是當(dāng)做標(biāo)記而不是語法規(guī)則。例如,classMyParsere*tendsParser;idList:(ID)+;//parserruledefinitionclassMyLe*ere*tendsLe*er;ID:('a'..'z')+;//tokendefinition規(guī)則引用以小寫字母開頭的標(biāo)識(shí)符是為ANTLR的語法規(guī)則。接下來的字符可以是任意字母,數(shù)字或下劃線。詞法規(guī)則不能引用語法規(guī)則。動(dòng)作.在尖括號(hào)中的字符序列是語義動(dòng)作(可能是嵌套的)。在字符串和字符中的尖括號(hào)不是動(dòng)作分隔符。動(dòng)作參數(shù)在方括號(hào)中的字符序列是動(dòng)作參數(shù)(可能是嵌套的)。在字符串和字符中的方括號(hào)不是動(dòng)作分隔符。在[]中的參數(shù)是用被生成的語言的語法定義的,并且用逗號(hào)分開。codeBlock[intscope,Stringname]//inputargumentsreturns[int*]//returnvalues:...;//pass2args,getreturntestcblock{inty;} : y=cblock[1,"John"] ;許多人喜歡我們用普通的括號(hào)來括住參數(shù),但是括號(hào)在EBNF中已經(jīng)被很好的用來定義語法組符號(hào)(grammaticalgroupingsymbols)。符號(hào)下面的表統(tǒng)計(jì)了在ANTLR中使用的標(biāo)點(diǎn)符號(hào)和關(guān)鍵字。符號(hào)描述(...)子規(guī)則(...)*閉包子規(guī)則(零和多個(gè))(...)+正閉包子規(guī)則(一個(gè)和多個(gè))(...)"可選(零個(gè)和一個(gè)){...}語義動(dòng)作[...]規(guī)則參數(shù){...}"語義謂詞(...)=>語法謂詞|可選符..圍符~非.通配符=賦值:標(biāo)號(hào)符,規(guī)則開始;規(guī)則結(jié)束<...>元素選項(xiàng)class語法類e*tends指定語法基類returns指定返回類型optionsoptions節(jié)tokenstokens節(jié)headerheader節(jié)tokenstoken定義節(jié)Header節(jié)一個(gè)header節(jié)包含了一些將直接被替換到輸出的語法分析器中的源碼,這些源碼將在所有的ANTLR生成的代碼之前。這個(gè)主要用在C++的輸出中,因?yàn)镃++需要一些元素在引用之前必須被聲明。在Java中,這可以用來為最后的語法分析器指定一些包文件。一個(gè)header節(jié)看起來像下面這樣:header{sourcecodeinthelanguagegeneratedbyANTLR;}header節(jié)是語法文件的第一個(gè)節(jié)。根據(jù)選擇的目標(biāo)語言的不同,不同類型header節(jié)都是可能出現(xiàn)的??锤髯缘母戒?。語法分析器類定義所有的語法規(guī)則必須和一個(gè)語法分析器關(guān)聯(lián)。一個(gè)語法文件(.g)只包含一個(gè)語法分析器類定義(和詞法分析器和樹遍歷器一起)一個(gè)語法分析器定義在它的選項(xiàng)(options)和規(guī)則定義之前。一個(gè)語法文件中的語法分析器定義通常是這個(gè)樣子:{optionalclasscodepreamble}classYourParserClasse*tendsParser;optionstokens{optionalactionforinstancevars/methods}parserrules...當(dāng)在面向?qū)ο笳Z言中生成代碼時(shí),語法分析器類將導(dǎo)致在輸出中是一個(gè)類,規(guī)則都會(huì)變成這個(gè)類的成員函數(shù)。在C中,類將導(dǎo)致生成一個(gè)結(jié)構(gòu),一些名字混淆(name-mangling)算法將用在上面使最終的規(guī)則函數(shù)是全局唯一的??蛇x的類的預(yù)定義可以是包含在{}中的任意文本。這個(gè)預(yù)定義,如果它存在的話,將被直接輸出到生成類文件中,并且在類定義之前。封閉的尖括號(hào)不能用來分隔類,因?yàn)橐粋€(gè)左尖括號(hào)在文件頂就很難跟蹤與之匹配的右括號(hào)在文件的時(shí)。相反,一個(gè)語法分析器類假定是連續(xù)的,知道碰到下一個(gè)類的語句。你可以指定語法分析器超類,它將作為被生成的語法分析器的超類。這個(gè)超類必須是完整定義的,在雙引號(hào)中。它自己必須是antlr.LlkParser的子類。例如classTinyCParsere*tendsParser("antlr.debug.ParseTreeDebugParser");詞法分析器類定義一個(gè)語法分析器類將導(dǎo)致一個(gè)知道如何根據(jù)輸入流的標(biāo)記來應(yīng)用語法結(jié)構(gòu)的語法分析器對(duì)象。為了執(zhí)行詞法分析,你需要指定一個(gè)詞法分析器類,它描述了如何將輸入流分離成標(biāo)記流。它的語法類似于語法分析器類:{optionalclasscodepreamble}classYourLe*erClasse*tendsLe*er;optionstokens{optionalactionforinstancevars/methods}le*errules...包含在詞法分析器中的詞法規(guī)則在產(chǎn)生的類中變成成員方法。每個(gè)語法文件(.g)只包含一個(gè)詞法分析器。語法分析器和詞法分析器可以以任何順序出現(xiàn)??蛇x類的開頭是括在{}中的任意文本。這個(gè)開頭部分,如果它存在,將輸出到被生成的類文件中,在類定義的之前。你可以定義一個(gè)詞法分析器的超類,它可以被用來作為產(chǎn)生的詞法分析器的超類。這個(gè)超類將是完整定義的(fully-qualified),在雙引號(hào)中,它自身是antlr.CharScanner子類。樹分析器定義一個(gè)樹分析器像語法分析器,不同的是它處理二維的由節(jié)點(diǎn)組成的抽象語法樹,而不是處理由標(biāo)記組成的流。樹分析器必須唯一指定給語法分析器,除非規(guī)則定義中包含特殊形式致使它遞歸下降到樹中。同樣,一個(gè)特定的語法文件(.g)中僅僅包含一個(gè)樹分析器。{optionalclasscodepreamble}classYourTreeParserClasse*tendsTreeParser;optionstokens{optionalactionforinstancevars/methods}treeparserrules...你可以定義一個(gè)樹分析器的超類,它可以被用來作為產(chǎn)生的樹解析器的超類。這個(gè)超類將是完整定義的(fully-qualified),在雙引號(hào)中,它自身是antlr.TreeParser子類注:以上資料均來于網(wǎng)絡(luò),鄙人收集整理。計(jì)算器及文法文件06通訊軟件06382027毅本文主要介紹了利用ANTLR達(dá)到計(jì)算器需求以及利用ANTLR生成C++描述的分析程序。一.利用ANTLR達(dá)到計(jì)算器需求1.運(yùn)算符:+,-,×,÷,(,)2.支持整型和浮點(diǎn)型測(cè)試樣例1.1+2*3+5-4/22.(1+2)*3+5-4/(2+2)3.(1.2*2.5)+8/(4-3)*2.7下面就讓我們動(dòng)手完成一個(gè)計(jì)算器,:)
先搭個(gè)框架。文件名是calc.goptions{
language=“Cpp”;
}classCalcParsere*tendsParser;classCalcLe*ere*tendsLe*er;這些就是基本框架了。
options里設(shè)置language為”Cpp”,表示要生成c++代碼。
CalcParser是我們的計(jì)算器的語法解析類,繼承ANTLR里的Parser類。
同理,CalcLe*er是詞法分析類,繼承ANTLR里的Le*er類。
接著定義計(jì)算器的詞法規(guī)則。首先是運(yùn)算符。
PLUS:‘+’;
SUB:‘-’;
MUL:‘*’;
DIV:‘/’;
LPAREN:‘(’;
RPAREN:‘)’;接著是操作數(shù)。
NUM:(’0′..’9′)+{$setType(INT);}(’.’(’0′..’9′)+{$setType(REAL);})";(注:$setType是ANTLR置函數(shù),用來設(shè)置token類型。就是當(dāng)匹配到(’0′..’9′)*后,設(shè)置token類型為INT,當(dāng)發(fā)現(xiàn)后面跟著小數(shù)點(diǎn)和數(shù)字后,重新設(shè)置token類型為REAL。)
WS:(’‘
|‘\t’
|‘\n’
|‘\r’)+
{
$setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP);
}
;statement:me*pr((PLUS|SUB)me*pr)*
;
me*pr:e*pr((MUL|DIV)e*pr)*
;
e*pr:INT
|REAL
|LPARENstatementRPAREN
;一個(gè)計(jì)算器的語法程序就寫好了。讓我們來生成c++代碼,實(shí)際測(cè)試一下.
$java-cp/usr/share/java/antlr.jarantlr.Toolcalc.g
ANTLRParserGeneratorVersion2.7.6(20060528)1989-2005
$ls
calc.gCalcParser.cppCalcParserTokenTypes.t*t
CalcLe*er.cppCalcParser.hpp
CalcLe*er.hppCalcParserTokenTypes.hpp
$
我們可以看到,生成了6個(gè)文件。
CalcTest.cpp:*include“CalcLe*er.hpp”
*include“CalcParser.hpp”
*include
usingnamespacestd;
usingnamespaceantlr;intmain()
{
try{
CalcLe*erle*er(cin);
CalcParserparser(le*er);
parser.statement();
}catch(e*ception&e){
cout<<e.what()<<endl;
}
}編譯之:
$g++-oCalcCalcTest.cppCalcParser.cppCalcLe*er.cpp-lantlr測(cè)試用例:$./Calc
1+2*3+5-4/2
$./Calc
(1+2)*3+5-4/(2+2)
$./Calc
(1.2*2.5)+8/(4-3)*2.7
$二.利用ANTLR生成C++描述的分析程序文法文件文法就是語言識(shí)別的規(guī)則。它是ANTLR生成程序的依據(jù)。文法文件是ANTLR的核心,是程序員和ANTLR進(jìn)行交流的接口。文法文件的編寫基本是面向被解決的問題的。程序員只需要集中精力思考解決問題的邏輯,而不是羈絆于*種程序設(shè)計(jì)語言的實(shí)現(xiàn)細(xì)節(jié),因此降低了出現(xiàn)錯(cuò)誤的可能性。文法文件的語法簡(jiǎn)介(轉(zhuǎn)自ANTLR中文手冊(cè))本文只是簡(jiǎn)單地介紹一個(gè)文法文件的語法,具體容可以參閱ANTLR的相關(guān)文檔。文法文件一般包括header塊、options塊、文法分析器類(parser)及規(guī)則定義、詞法分掃描器類(le*er)及token定義。其中最為重要的是規(guī)則和token的定義。規(guī)則的定義形式和編譯理論中的擴(kuò)展巴科斯式(EBNF)極為相似,包括規(guī)則名、規(guī)則體、一個(gè)用作結(jié)束標(biāo)志的分號(hào)和異常處理部分(可省略)。例如如下的規(guī)則就描述了C語言中的賦值語句的語法:assignment_stat:
id'='e*pr';'
;其意義是:一條賦值語句是由一個(gè)id、一個(gè)等號(hào)、一個(gè)表達(dá)式和一個(gè)分號(hào)順序組成的。Token的定義方法與規(guī)則類似。例如如下的token定義就表示一個(gè)十進(jìn)制的整數(shù):NUM:
('1'..'9')('0'..'9')*
;其意義是:數(shù)字(NUM)的第一字符是‘1’到‘9’中的一個(gè)字符,后面是0個(gè)或多個(gè)‘0’到‘9’之間的字符。需要注意的一點(diǎn)是:規(guī)則的名字必須是小寫字母開始,而token的名字則必須是大寫字母開始。設(shè)定ANTLR生成的語言(轉(zhuǎn)自ANTLR中文手冊(cè))ANTLR有很多選項(xiàng),可以通過在文法文件中的options塊中進(jìn)行設(shè)置,其中包括ANTLR最終生成的語言。如果要生成C++描述的分析器程序,就要如下設(shè)定:options{language="Cpp";//Otheroptions}language選項(xiàng)的默認(rèn)值是“Java”。如果您希望生成的程序是C*的,將language設(shè)為“Csharp”就可以了。C++程序的例子下面就給出一個(gè)ANTLR生成的C++描述的分析器的實(shí)例。該分析器的功能是分析用戶輸入的一個(gè)算術(shù)表達(dá)式,給出該表達(dá)式的最終結(jié)果。在該表達(dá)式中允許出現(xiàn)的運(yùn)算符除了加減乘除之外,還包括求冪運(yùn)算符“^”,以及sin、cos和tan三個(gè)三角函數(shù)。編寫文法文件header{*include<stdlib.h>*include<stdio.h>*include<math.h>}options{language="Cpp";}classE*prParsere*tendsParser;{}//rulese*prreturns[doublevalue=0]{double*;}:value=term(PLUS*=term{value+=*;}|MINUS*=term{value-=*;})*;e*ceptioncatch[ANTLR_USE_NAMESPACE(antlr)ANTLRE*ception&e*]{//catchalle*ceptionsandreportitreportError(e*.toString());}termreturns[doublevalue=0]{double*;}:value=factor(STAR*=factor{value*=*;}|SLASH*=factor{value/=*;})*;factorreturns[doublevalue=0]{double*;}:value=atom(TOK_POW*=atom{value=pow(value,*);})*;atomreturns[doublevalue=0]{double*;}:i:NUM{value=atof((i->getTe*t()).c_str());}|TOK_SIN*=atom{value=sin(*);}|TOK_COS*=atom{value=cos(*);}|TOK_TAN*=atom{value=tan(*);}|LPARENvalue=e*prRPAREN;e*ceptioncatch[ANTLR_USE_NAMESPACE(antlr)ANTLRE*ception&e*]{reportError(e*.toString());}clas
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 河南科技大學(xué)《設(shè)計(jì)軟件基礎(chǔ)》2021-2022學(xué)年第一學(xué)期期末試卷
- 衛(wèi)生防疫:從理論到實(shí)踐-全面理解并應(yīng)對(duì)公共衛(wèi)生挑戰(zhàn)
- 創(chuàng)意設(shè)計(jì)與企業(yè)招聘-人力資源經(jīng)理演講
- 河北地質(zhì)大學(xué)《影視特效處理》2022-2023學(xué)年第一學(xué)期期末試卷
- 創(chuàng)新三年級(jí)教學(xué)利器-以教具提升學(xué)生學(xué)習(xí)效率
- 陜西省榆林市定邊縣2024-2025學(xué)年七年級(jí)上學(xué)期期中考試語文試題
- 河北地質(zhì)大學(xué)《室內(nèi)裝飾材料及施工工藝》2022-2023學(xué)年第一學(xué)期期末試卷
- 河北地質(zhì)大學(xué)《居住空間室內(nèi)設(shè)計(jì)》2023-2024學(xué)年第一學(xué)期期末試卷
- 創(chuàng)新教學(xué)方法分享-教育專家演講
- 露營(yíng)用睡袋細(xì)分市場(chǎng)深度研究報(bào)告
- 2023水利系統(tǒng)職稱考試題庫及答案
- 中藥調(diào)劑員知識(shí)競(jìng)賽考試題庫(附答案)
- LY/T 3354-2023土地退化類型與分級(jí)規(guī)范
- 北京市商業(yè)地產(chǎn)市場(chǎng)細(xì)分研究
- 新媒體視覺設(shè)計(jì)之新媒體視覺設(shè)計(jì)基本要素
- 《大衛(wèi)科波菲爾(節(jié)選)》《老人與?!仿?lián)讀課件17張高中語文選擇性必修上冊(cè)
- HSK五級(jí)必過考前輔導(dǎo)課件
- 自動(dòng)化機(jī)械設(shè)備項(xiàng)目評(píng)價(jià)分析報(bào)告
- 北師大版-八年級(jí)上冊(cè)數(shù)學(xué)知識(shí)點(diǎn)及習(xí)題
- 醫(yī)療美容消費(fèi)服務(wù)合同
- 地球的形成和演化
評(píng)論
0/150
提交評(píng)論