本節書摘來自華章出版社《antlr 4權威指南 》一書中的第3章,第3.1節,[美] 特恩斯·帕爾(terence parr) 著張 博 譯,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
作為我們的第一個antlr項目,我們會構造一個文法,它是c語言或其繼承者java文法的一個很小的子集。具體來說,我們将識别包裹在花括号或者嵌套的花括号中的一些整數,像是{1, 2, 3}和{1, {2, 3}, 4}這樣。這樣的結構可以作為int數組或者c語言中的結構體的初始化語句。在很多情況下,針對這種文法的文法分析器都非常有用。例如,我們可以用它來建構一個對c語言的源代碼進行重構的工具,這個工具能夠完成這樣的工作:如果初始化語句中所有的整數值都能用一個位元組表示,那麼将該整數數組轉換為位元組數組。我們也可以用這個文法分析器将java的short數組轉換為字元串。例如,我們可以将short值當作unicode字元,進而将

轉換為等價的字元串形式:
其中像u0001這樣的unicode字元标記使用四個十六進制數字來表示一個16位的字元。實際上,這樣的字元就是一個short值。
我們這樣做的原因是為了不受java的.class檔案格式的限制。java的class檔案将數組的初始化語句存儲為一系列顯式的數組元素指派語句,上面的初始化語句等價為data[0] = 1; data[1] = 2; data[2] = 3;。這限制了我們能夠使用這種方法來初始化的數組的大小。相比之下,java的class檔案将字元串存儲為連續的short序列,進而不受上述限制限制。将數組的初始化語句轉換為字元串可以得到更緊湊的class檔案,避免了java的對初始化方法的長度限制。
通過這個入門的項目示例,你将會學到如下内容:一些antlr文法的語義元素定義、antlr根據文法自動生成代碼的機制、如何将自動生成的文法分析器和java程式內建,以及如何使用文法分析樹監聽器編寫一個代碼翻譯工具。
3.1 antlr工具、運作庫以及自動生成的代碼
在開始前,我們先浏覽一下antlr的jar包中的内容。在antlr的jar包中存在兩個關鍵部分:antlr工具和antlr運作庫(運作時文法分析)api。通常,當說到“對一個文法運作antlr”時,我們指的是運作antlr工具,即org.antlr.v4.tool類來生成一些代碼(文法分析器和詞法分析器),它們能夠識别使用這份文法代表的語言所寫成的語句。詞法分析器将輸入的字元流分解為詞法符号序列,然後将它們傳遞給能夠進行文法檢查的文法分析器。運作庫是一個由若幹類和方法組成的庫,這些類和方法是自動生成的代碼(如parser,lexer和token)運作所必須的。是以,我們完成工作的一般步驟是:首先我們對一個文法運作antlr,然後将生成的代碼與jar包中的運作庫一起編譯,最後将編譯好的代碼和運作庫放在一起運作。
建構一個語言類應用程式的第一步是建立一個能夠描述這種語言的文法(即合法語句結構的集合)的文法。我們将在第5章中介紹如何編寫文法,現在我們先來看下面這個能夠滿足我們需求的文法。
請将文法檔案arrayinit.g4放入一個單獨的檔案夾,例如/tmp/array(通過複制-粘貼或者從本書網站下載下傳)。然後我們對它運作antlr工具。
根據文法arrayinit.g4,antlr自動生成了很多檔案,如圖3-1所示,正常情況下這些檔案都是需要我們手工編寫的。
目前,我們僅僅需要大緻了解這個過程,下面簡單介紹一下生成的檔案:
1)arrayinitparser.java:該檔案包含一個文法分析器類的定義,這個文法分析器專門用來識别我們的“數組語言”的文法arrayinit。
在該類中,每條規則都有對應的方法,除此之外,還有一些其他的輔助代碼。
2)arrayinitlexer.java:antlr能夠自動識别出我們的文法中的文法規則和詞法規則。這個檔案包含的是詞法分析器的類定義,它是由antlr通過分析詞法規則int和ws,以及文法中的字面值'{'、',',和'}'生成的。回想一下上一章的内容,詞法分析器的作用是将輸入字元序列分解成詞彙符号。它形如:
3)arrayinit.tokens:antlr會給每個我們定義的詞法符号指定一個數字形式的類型,然後将它們的對應關系存儲于該檔案中。有時,我們需要将一個大型文法切分為多個更小的文法,在這種情況下,這個檔案就非常有用了。通過它,antlr可以在多個小型文法間同步全部的詞法符号類型。更多内容請參閱4.1節中的“文法導入”部分。
4)arrayinitlistener.java, arrayinitbaselistener.java:預設情況下,antlr生成的文法分析器能将輸入文本轉換為一棵文法分析樹。在周遊文法分析樹時,周遊器能夠觸發一系列“事件”(回調),并通知我們提供的監聽器對象。arrayinitlistener接口給出了這些回調方法的定義,我們可以實作它來完成自定義的功能。arrayinitbaselistener是該接口的預設實作類,為其中的每個方法提供了一個空實作。arrayinitbaselistener類使得我們隻需要覆寫那些我們感興趣的回調方法(詳見7.2節)。通過指定-visitor指令行參數,antlr也可以為我們生成文法分析樹的通路器(參閱7.5節“使用通路器周遊文法分析樹”部分)。
接下來,我們将使用監聽器來将short數組初始化語句轉換為字元串對象,不過在這之前,我們首先使用一些樣例輸入來驗證我們的文法分析器是否能正常進行比對工作。