Antlr
目錄
?
Antlr是什么?
Antlr能干什么?
傳統(tǒng)解析器工作原理是什么?
Antrl 語(yǔ)法規(guī)則文件
ANTLR兩種遍歷分析樹(shù)的機(jī)制
Parse-Tree Listeners
Parse-Tree Visitor
?
Antlr是什么?
ANTLR(另一種語(yǔ)言識(shí)別工具)是功能強(qiáng)大的解析器生成器,用于讀取,處理,執(zhí)行或翻譯結(jié)構(gòu)化文本或二進(jìn)制文件。它被廣泛用于構(gòu)建語(yǔ)言,工具和框架。ANTLR從語(yǔ)法中生成一個(gè)解析器,該解析器可以構(gòu)建和遍歷解析樹(shù)。
ANTLR?(ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It's widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build and walk parse trees.
?
Antlr能干什么?
ANTLR能夠根據(jù)用戶(hù)定義的語(yǔ)法文件自動(dòng)生成詞法分析器和語(yǔ)法分析器,并將輸入文本處理為語(yǔ)法分析樹(shù)。這一切都是自動(dòng)進(jìn)行的,所需的僅僅是一份描述該語(yǔ)言的語(yǔ)法文件。
ANTLR自動(dòng)生成的編譯器高效、準(zhǔn)備,能夠?qū)㈤_(kāi)發(fā)者從繁雜的編譯理論中解放出來(lái),集中精力處理自己的業(yè)務(wù)邏輯。ANTRL4引入的自動(dòng)語(yǔ)法分析樹(shù)創(chuàng)建與遍歷機(jī)制,極大地提高了語(yǔ)言識(shí)別程序的開(kāi)發(fā)效率。時(shí)至今日,仍然是Java世界中實(shí)現(xiàn)編譯器的不二之選,同時(shí),它也對(duì)其他編程語(yǔ)言也提供了支持。
典型應(yīng)用如下:
1、編程語(yǔ)言處理
識(shí)別和處理編程語(yǔ)言是 Antlr 的首要任務(wù),編程語(yǔ)言的處理是一項(xiàng)繁重復(fù)雜的任務(wù),為了簡(jiǎn)化處理,一般的編譯技術(shù)都將語(yǔ)言處理工作分為前端和后端兩個(gè)部分。其中前端包括詞法分析、語(yǔ)法分析、語(yǔ)義分析、中間代碼生成等若干步驟,后端包括目標(biāo)代碼生成和代碼優(yōu)化等步驟。
Antlr 致力于解決編譯前端的所有工作。使用 Anltr 的語(yǔ)法可以定義目標(biāo)語(yǔ)言的詞法記號(hào)和語(yǔ)法規(guī)則,Antlr 自動(dòng)生成目標(biāo)語(yǔ)言的詞法分析器和語(yǔ)法分析器;此外,如果在語(yǔ)法規(guī)則中指定抽象語(yǔ)法樹(shù)的規(guī)則,在生成語(yǔ)法分析器的同時(shí),Antlr 還能夠生成抽象語(yǔ)法樹(shù);最終使用樹(shù)分析器遍歷抽象語(yǔ)法樹(shù),完成語(yǔ)義分析和中間代碼生成。整個(gè)工作在 Anltr 強(qiáng)大的支持下,將變得非常輕松和愉快。
2、文本處理
當(dāng)需要文本處理時(shí),首先想到的是正則表達(dá)式,使用 Anltr 的詞法分析器生成器,可以很容易的完成正則表達(dá)式能夠完成的所有工作;除此之外使用 Anltr 還可以完成一些正則表達(dá)式難以完成的工作,比如識(shí)別左括號(hào)和右括號(hào)的成對(duì)匹配等。
?
傳統(tǒng)解析器工作原理是什么?
如果一個(gè)程序能夠分析計(jì)算或者執(zhí)行語(yǔ)句,我們就把它稱(chēng)之為解釋器(interpreter)。解釋器需要識(shí)別出一門(mén)特定的語(yǔ)言的所有的有意義的語(yǔ)句,詞組和子詞組。識(shí)別一個(gè)詞組意味著我們可以將它從眾多的組成部分中辨認(rèn)和區(qū)分出來(lái)。
比如我們會(huì)把sp=100;識(shí)別成賦值語(yǔ)句, 這意味著我們能夠辨識(shí)出sp是被賦值的目標(biāo),100則是要被賦予的值。我們也都知道我們?cè)趯W(xué)習(xí)英語(yǔ)的時(shí)候,識(shí)別英語(yǔ)語(yǔ)句,需要辨認(rèn)出一段對(duì)話(huà)的不同部分,例如主謂賓。在識(shí)別成功之后,程序還能執(zhí)行適當(dāng)?shù)牟僮鳌?/p>
識(shí)別語(yǔ)言的程序被稱(chēng)為語(yǔ)法分析器(parser)或者句法分析器(syntax analyzer),syntax是指約束語(yǔ)言中的各個(gè)組成部分之間關(guān)系的規(guī)則。grammar是一系列規(guī)則的集合,每條規(guī)則表述出一種詞匯結(jié)構(gòu)。ANTLR就是能夠?qū)⑵滢D(zhuǎn)成如同經(jīng)驗(yàn)豐富的開(kāi)發(fā)者手工構(gòu)建的一般的語(yǔ)法分析器(ANTLR是一個(gè)能夠生產(chǎn)其他程序的程序)
1、語(yǔ)法解析器
語(yǔ)法解析器是傳統(tǒng)解析器重要組件,語(yǔ)法解析器工作流程包括詞法分析和語(yǔ)法分析兩個(gè)階段。
詞法分析,主要負(fù)責(zé)將符號(hào)文本分組成符號(hào)類(lèi)tokens,把輸入的文本轉(zhuǎn)換成詞法符號(hào)的程序稱(chēng)為詞法分析器(lexer);
語(yǔ)法解析,目標(biāo)就是構(gòu)建一個(gè)語(yǔ)法解析樹(shù)。語(yǔ)法解析的輸入是tokens,輸出就是一顆語(yǔ)法解析樹(shù)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 語(yǔ)法分析示例
語(yǔ)法分析樹(shù)的內(nèi)部節(jié)點(diǎn)是?詞組名,這些名字用于識(shí)別它們的子節(jié)點(diǎn),并可以將子節(jié)點(diǎn)歸類(lèi)。根節(jié)點(diǎn)是比較抽象的一個(gè)名字,在這里是?stat(statement)。
2、解析方法?
根據(jù)推導(dǎo)策略的不同,語(yǔ)法解析分為L(zhǎng)L與LR兩種:LR自低向上(bottom-up)的語(yǔ)法分析方法;LL是自頂向下(top-down)的語(yǔ)法分析方法。兩類(lèi)分析器各有其優(yōu)勢(shì),適用不同的場(chǎng)景,很難說(shuō)誰(shuí)要更好一些。普遍的說(shuō)法是LR可以解析的語(yǔ)法形式更多,LL的語(yǔ)法定義更簡(jiǎn)單易懂。Antrl就是一種自頂向下的解析器;
?
Antrl 語(yǔ)法規(guī)則文件
以一個(gè)計(jì)算器的規(guī)則文件做示例:
grammar Cal;prog: stat+;?//一個(gè)程序由至少一條語(yǔ)句組成/*為了以后的運(yùn)算的方便性,我們需要給每一步規(guī)則打上標(biāo)簽,標(biāo)簽以”#”開(kāi)頭,出現(xiàn)在每一條規(guī)則的右邊。打上標(biāo)簽后,antlr會(huì)為每一個(gè)規(guī)則都生成一個(gè)事件*/stat: ID'='expr?';'#Assign?//變量賦值語(yǔ)句|'print''('expr?')'';'#printExpr???//輸出語(yǔ)句;expr: expr op=('*'|'/') expr #MulDiv??//表達(dá)式可以是表達(dá)式之間乘除| expr op=('+'|'-') expr #AddSub??//表達(dá)式可以是表達(dá)式之間加減| NUM #NUM???//表達(dá)式可以是一個(gè)數(shù)字| ID #ID?//表達(dá)式可以是一個(gè)變臉|'('expr?')'#parens????//表達(dá)式可以被括號(hào)括起來(lái);MUL:'*';DIV:'/';ADD:'+';SUB:'-';ID: [a-zA-Z][a-zA-Z0-9]*;?//變量可以是數(shù)字和字母,但必須以字母開(kāi)頭//負(fù)數(shù)必須要用"()"括起來(lái)NUM: [0-9]+???//正整數(shù)|'(''-'[0-9]+?')'//負(fù)整數(shù)| [0-9]+'.'[0-9]+???//正浮點(diǎn)數(shù)|'(''-'[0-9]+'.'[0-9]+?')'//負(fù)浮點(diǎn)數(shù); WS: [ \t\r\n] -> skip;???//跳過(guò)空格、制表符、回車(chē)、換行
?
Antlr文法概念中的一些關(guān)鍵概念。文法由一組描述語(yǔ)法的規(guī)則組成。其中包括詞法與語(yǔ)法規(guī)則。語(yǔ)法規(guī)則是以小寫(xiě)字母組成。如prog,stat。詞法規(guī)則由大寫(xiě)字母組成。如ID:[a-z A-Z]+。通過(guò)使用 | 運(yùn)算符來(lái)將不同的規(guī)則分割,還可以使用括號(hào)構(gòu)成子規(guī)則。
?
ANTLR兩種遍歷分析樹(shù)的機(jī)制
默認(rèn)情況下,ANTLR使用內(nèi)建的遍歷器訪(fǎng)問(wèn)生成的語(yǔ)法分析樹(shù),并為每個(gè)遍歷時(shí)可能觸發(fā)的事件生成一個(gè)語(yǔ)法分析樹(shù)監(jiān)聽(tīng)器接口?(ANTLR generates a parse-tree listener interface) 。除了監(jiān)聽(tīng)器的方式,還有一種遍歷語(yǔ)法分析樹(shù)的方式:訪(fǎng)問(wèn)者模式(vistor pattern);
Parse-Tree Listeners
為了將遍歷樹(shù)時(shí)觸發(fā)的事件轉(zhuǎn)化為監(jiān)聽(tīng)器的調(diào)用,ANTLR提供ParseTreeWalker類(lèi)。我們可以自行實(shí)現(xiàn)ParseTreeListener的接口,在其中填充自己的邏輯。ANTLR為每個(gè)語(yǔ)法文件生成一個(gè)ParseTreeListener的子類(lèi),在該類(lèi)中,語(yǔ)法的每條規(guī)則都有對(duì)應(yīng)的enter方法和exit方法。
層次遍歷(先序遍歷)訪(fǎng)問(wèn)
層次遍歷(先序遍歷)訪(fǎng)問(wèn)
監(jiān)聽(tīng)器方式的優(yōu)點(diǎn)在于,回調(diào)是自動(dòng)進(jìn)行的。我們不需要編寫(xiě)對(duì)語(yǔ)法分析樹(shù)的遍歷代碼,也不需要讓我們的監(jiān)聽(tīng)器顯式地訪(fǎng)問(wèn)子節(jié)點(diǎn)
Parse-Tree Visitors:
有時(shí)候,我們希望控制遍歷語(yǔ)法分析樹(shù)的過(guò)程,通過(guò)顯式的方法調(diào)用來(lái)訪(fǎng)問(wèn)子節(jié)點(diǎn)。語(yǔ)法中的每條規(guī)則對(duì)應(yīng)接口中的一個(gè)visit方法。
代碼demo
ParseTree tree = ... ;// tree is result of parsingMyVisitor v =newMyVisitor();v.visit(tree);
ANTLR內(nèi)部為訪(fǎng)問(wèn)者模式提供的支持代碼會(huì)在根節(jié)點(diǎn)處調(diào)用visitStat方法,接下來(lái),visitStat方法的實(shí)現(xiàn)將會(huì)調(diào)用visit方法,并將所用的子節(jié)點(diǎn)作為參數(shù)傳遞給它,從而繼續(xù)遍歷的過(guò)程;
Parse-Tree Visitor
為了更好的使用訪(fǎng)問(wèn)者模式我們用以下針對(duì)每個(gè)規(guī)則加了標(biāo)簽的語(yǔ)法文件來(lái)說(shuō)明:
grammar LabeledExpr;//rename to distinguish from Expr.g4prog:stat+ ;stat????:????expr NEWLINE? ? ????????????# printExpr|? ? ?ID '=' expr NEWLINE ???? # assign|? ? ?NEWLINE????????????????????????# blank;expr????:????expr op=('*'|'/') expr? ? ????? # MulDiv|????expr op=('+'|'-') expr? ? ? ? ? # AddSub|????INT????????????????????????????????????# int|? ID? ? ? ? ? ? ? ? ? ? ? ? ????????????????? # id|'('expr')'? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?# parens;????????MUL :'*';? ?//assigns token name to'*'used aboveingrammarDIV :'/';ADD :'+';SUB :'-';ID? :? [a-zA-Z]+ ;//match identifiersINT :? [0-9]+ ;//match integersNEWLINE:'\r'?'\n';//returnnewlines to parser (isend-statement? signal)WS? :? [ \t]+ -> skip ;//toss out whitespace
?
總結(jié)
- 上一篇: python微信语音转发给别人_pyth
- 下一篇: php 轮播图插件下载,jquery全屏