antlr v4簡介
antlr是一個強大語言解析工具,可以用於處理結構化文本、二進制文件。說白了,其實可以這么認為,antlr是一個更強大的正則表達式工具。它可以完成更多正則表達式無法完成的工作。正則表達式更適合於做一些文本匹配、拆分、替換的工作,也就是說,正則表達式關注的是文本大區塊。相對於antlr這類語言解析工具來說,正則表達式是一個粗粒度的工具,antlr則側重於細粒度。antlr可以具體到每一個語法、詞法。熟知Java api的猿糞們都知道,java的正則api會有棧溢出的bug,這也正是正則表達式難以處理復雜文本結構的一個例證。
通常情況下,在平常的編程過程中,正則表達式可以解決絕大部分的問題。我曾經在職業生涯的第一年,就接觸過只使用正則表達式來完成文本解析入庫的一套數據采集框架。而要解析的文本是從通信設備中采集回來的數據。當然這些數據是很規則的,行、列都遵照既定的數據格式。
那么antlr可以做什么呢?可以舉這么一個例子,如何將java源碼轉換成字節碼呢?對於這樣的需求,antlr就可以派上用場了。實現這個需求,需要按照java規范,將源碼中的每個詞法(如public、class、package)、類名、包名等轉換成對應的字節碼。那么如何取得這些詞、類名、包名、變量名呢? 正則表達式在這里可能就顯得力不從心了。因為除了要尋找這些詞法外,還需要處理復雜的上下文關系(如變量的作用范圍)。這些正是antlr擅長的地方。
當然,antlr也不是唯一的,它的鼻祖級工具是lex、yacc。Java語言則是JavaCC。有興趣的朋友,可以搜索一下這方面的資料。
antlr的作者自稱有二十幾年的語言解析方面的研究經驗,做出來的這個東西也確實很強大,很好用。而且提供的開發工具也相當給力,主流IDE都有對應的插件可用。另外,antlr的學習曲線也相對較低,如果有正則表達式的基礎,學習起antlr來可以事半功倍。沒有也不要緊,學會了antlr,等於正則表達式也學會了一半。
好了,先瞅一眼antlr的廬山真面目吧。antlr由兩個東西組成,一個叫詞法,一個叫語法,語法是由一個個詞法堆積而成的。在antlr中,英文的說法是Lexer、Parser,分別對應詞法、語法。通俗地說,詞法就是:
- 標識符,即各類編程語言中所說的以下划線、字母開頭的字符串
- 字面量,英文叫Literal,其實就是可以當作值的東西,放在操作符兩邊。如數字、單引號字符串、雙引號字符串、各個進制寫法等
- 字符,單字符(!、~、=、>等)、雙字符(>=、<=)等
- 關鍵字,如Java中的class、package、import、public等
語法就很容易理解了,比如變量定義、類定義,這些都是語法。所以antlr就是由這兩個東西組成的,分別放在兩個文件里,一個叫xxxLexer.g4,一個叫xxxParser.g4。當然名字是否包含Lexer、Parser不是強制的,看各人喜好。不過兩個文件內容的第一行可以看出來是lexer還是parser。此外antlr也提供一個combine模式,即把lexer、parser寫在同一個文件里。為求簡便,下面的例子先用這個方法寫一個例子吧。
grammar Hello; //Definea grammar called Hello
r :'hello' ID; //match key word hello followed by an identifier
ID : [a-z]+; //match lower-case identifiers
WS : [\t\r\n ]+->skip; //skip spaces,tabs,newlines,\r(Windows)
這是一個完整的antlr例子。
- 第一行是語法文件名Hello,保存之后文件要按這個名字取,即Hello.g4
- 第二行以小寫字母開頭,是一個語法規則。hello后面跟着一個ID標識符。ID標識符的定義在第三行定義
- 第三行以大寫字母開頭,是一個詞法規則。ID由a-z這26個英文小寫字母的一個或多個組成
- 第四行以大寫字母開頭,是一個詞法規則。WS由制表符、換行符的一個或多個組成。->skip是action,表示當處理這個詞法規則時采取的處理方法。skip表示跳過,不處理制表符、換行符,直接處理下一個詞法規則。