安裝ANTLR
作者的電腦是MAC的操作系統macOS Catalina 10.15.2。
安裝步驟后linux操作的系統的一樣, Windows系統大致步驟一樣,但是環境變量等配置有差別,作者很久沒使用過win系統,只能基於MAC的系統介紹了。
環境准備
ANLTR是用JAVA編寫的,需要先安裝好JAVA,需要的JAVA版本是1.6以上。相信看這篇文章的各位同學電腦上應該都有安裝JAVA。😊
下載ANTLR
使用ANTLR的功能其實很簡單, 下載一個ANTLR的jar包即可。
官方下載地址
配置
最后一步配置環境變量,方便后面在命令行操作ANTLR
打開環境變量文件,作者安裝的是zsh,所以編輯~/.zshrc文件,各位同學應該也清楚環境變量的配置,在文件加入幾行:
export CLASSPATH=".:/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" #設置antlr的jar包到環境變量
alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool' #快速運行ANTLR的解釋器
alias grun='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig' #快速運行ANTLR測試工具
完成上面的准備工作就可以開始體驗ANTLR的強大功能了
第一個語法解釋器
下面用一個簡單的例子展示ANTLR的使用,編譯一個最簡單的賦值語句的語法。
編寫g4文件
新建一個Hello.g4的文件,這個文件是針對語法的描述,相當於告訴ANTLR我的語法規范
Hello.g4內容如下:
grammar Hello; //定義一個名為 Hello 的語法
statement: ID '=' NUM; //匹配類似 a=1 age=100 這樣的語句
ID: [a-z]+; // 定義了一個詞法 ID,由小寫字母組成
NUM:[0-9]+; // 定義了一個詞法 NUM,由數字組成
WS: [ \t\r\n]+ -> skip; //在進行解析的過程中,忽略掉空格,換行
這樣其實就定義好了一個簡單語法。
對於不同的程序語言來說,語法結構越是復雜,想對應的g4文件也會越復雜
這個項目里面有針對目前流行的語言的ANTLR語法定義文件
各位同學可以找找接觸過哪些,看看你用的語言復雜不復雜。反正JAVA文件是很復雜💔
生成解釋器
生成ANTLR的解釋器很簡單,一條命令搞定。
antlr4 Hello.g4
運行完這條命令會生成如下幾個文件:
Hello.interp
Hello.tokens
HelloBaseListener.java
HelloLexer.interp
HelloLexer.java
HelloLexer.tokens
HelloListener.java
HelloParser.java
-
HelloParser.java
該文件包含一個語法解釋器類的定義,負責識別我們定義的語法
public class HelloParser extends Parser { ... }
-
HelloLexer.java
該文件包含一個詞法解釋器類的定義,負責自動識別我們定義的語法中的文法規則和詞法規則。
public class HelloLexer extends Lexer { ... }
-
HelloListener.java和HelloBaseListener.java
這兩個類都是事件監聽類,是留給開發者自己來定義相應的事件。因為ANTLR在進行遍歷解析時,遍歷器會觸發一系列的事件。 比如進入某某標簽,讀到一個數字等。ANTLR開放了這些接口,開發者通過實現這些事件可以做到除了解釋語法以外更復雜的功能。這里就不詳細解釋,后面會再介紹。先挖個坑😊
public interface HelloListener extends ParseTreeListener {
/**
* Enter a parse tree produced by {@link HelloParser#statement}.
* @param ctx the parse tree
*/
void enterStatement(HelloParser.StatementContext ctx);
/**
* Exit a parse tree produced by {@link HelloParser#statement}.
* @param ctx the parse tree
*/
void exitStatement(HelloParser.StatementContext ctx);
}
-
其他非java文件
ANTLR會給每個定義的詞法符號指定一個數字形式的類型,然后將對應關系存儲在這些文件中。當不同的語法有相同的詞時這個文件就有大作用了。
測試解釋器
最后到了驗收結果的時候,測試一下ANTLR的語法解釋器做了什么。下面會展示兩種測試方式。
JAVA代碼
- 將前面生成的4個JAVA文件添加到一個測試工程內,該工程需要引入ANTLR依賴。
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.7.1</version>
</dependency>
- 編寫相關測試代碼
public static void main(String[] args) {
HelloLexer lexer = new HelloLexer(CharStreams.fromString("a = 1"));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
HelloParser parser = new HelloParser(tokenStream);
System.out.println(parser.statement().toStringTree(parser));
}
- 運行后會有如下輸入:
(statement a = 1)
這個代碼ANTLR成功識別到了我們的賦值語句。
命令行
ANTLR也提供了自動的測試工具,可以直接在命令行測試。詳細用法如下
- 編譯java代碼,就跟一般的java代碼一樣我們需要同javac把java文件編譯成class文件。
javac *.java
- 使用ANTLR測試工具,輸入如下命令
grun Hello statement -gui
Hello 對應我們定義的語法 grammar Hello
statement 對應我們定義的詞法 statement: ID '=' NUM;
-gui 表示輸出圖形界面
- 進入測試工具后,輸入a = 1。 MAC電腦結束輸入符號 control+D。
$ grun Hello statement -gui
a = 1
^D
ANTLR會輸出圖形界面
可以看到ANTLR最終解釋出來的語法樹。
總結
這篇文章帶大家完成了第一個ANTLR的語法文件,並展示了測試過程。中間有一些細節沒有在這里仔細講解,在后面的筆記會陸續更新。最后附上一個稍微復雜一點的語法樹的圖。