什么是ANTLR
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根據語法,可以生成對應的語法分析器,並自動建立語法分析樹(一種描述語法和輸入文本匹配關系的數據結構),ANTLR能夠自動生成分析器的遍歷器,通過遍歷器,用戶可以方便地執行自定義的業務邏輯代碼。
ANTLR廣泛用於學術及工業領域,是眾多語言、工具及框架的基石。Hive使用ANTLR實現SQL的詞法和語法解析,Hibernate框架使用ANTLR來處理HQL語言。
ANTLR環境搭建
ANTLR包含了兩部分:
- 一個將語法轉換成詞法分析器和語法分析器的工具;
- 生成的詞法分析器、語法分析器依賴的運行時環境;
安裝ANTLR僅僅需要下載一個jar包:antlr-4.7.2-complete.jar
,該包中包含了運行ANTLR的工具和編譯、執行ANTLR產生的識別程序所依賴的全部運行庫——包括復雜的樹形結構生成庫和StringTemplate。
該工具庫能夠將語法文件轉換成可以識別該語法文件所描述的語言的程序。
下載jar包並安裝ANTLR:
cd /usr/local/lib
sudo curl -O https://www.antlr.org/download/antlr-4.7.2-complete.jar
# 設置環境變量
export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH"
檢查ANTLR是否正確安裝:
# 啟動org.antlr.v4.Tool
java -jar /usr/local/lib/antlr-4.7.2-complete.jar
# 直接調用Tool類
java org.antlr.v4.Tool
# ANTLR Parser Generator Version 4.7.2
# -o ___ specify output directory where all output is generated
# -lib ___ specify location of grammars, tokens files
# -atn generate rule augmented transition network diagrams
# -encoding ___ specify grammar file encoding; e.g., euc-jp
# -message-format ___ specify output style for messages in antlr, gnu, vs2005
# -long-messages show exception details when available for errors and warnings
# -listener generate parse tree listener (default)
# -no-listener don't generate parse tree listener
# -visitor generate parse tree visitor
# -no-visitor don't generate parse tree visitor (default)
# -package ___ specify a package/namespace for the generated code
# -depend generate file dependencies
# -D<option>=value set/override a grammar-level option
# -Werror treat warnings as errors
# -XdbgST launch StringTemplate visualizer on generated code
# -XdbgSTWait wait for STViz to close before continuing
# -Xforce-atn use the ATN simulator for all predictions
# -Xlog dump lots of logging info to antlr-timestamp.log
# -Xexact-output-dir all output goes into -o dir regardless of paths/package
為了簡化啟動命令,可以設置別名,以后使用antlr4命令即可:
alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
可以將上述命令添加到.bash_profile
文件中,避免重復設置環境參數:
# 設置到~/.bash_profile中
sudo vim ~/.bash_profile
# .bash_profile添加內容
export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH"
alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
# 為后文需要使用的命令設置別名
alias grun='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
ANTLR實現HelloWorld
安裝好ANTLR運行環境之后,我們來編寫一個簡單的Hello World
程序來初步認識ANTLR。首先,需要創建一個HelloWorld.g4
文件,文件內容如下:
grammar HelloWorld; // 定義一個名為Hello的語法
r : 'hello' ID ; // 匹配一個關鍵字hello和一個緊隨其后的標識符
ID : [a-z]+ ; // 匹配小寫字母組成的標識符
WS : [ \t\r\n]+ -> skip ; // 忽略空格 、Tab、換行以及\r
語法名為HelloWorld
,必須跟文件名保持一致。語法規則為r
,必須為小寫字母。ID
和WS
為詞法規則,必須為大寫字母。然后使用前文定義的antlr4
命令來生成語法分析器和詞法分析器:
# 生成語法分析器和詞法分析器
antlr4 HelloWorld.g4
# 查看生成文件
ls
# HelloWorld.g4 HelloWorld.tokens HelloWorldLexer.interp HelloWorldLexer.tokens HelloWorldParser.java
# HelloWorld.interp HelloWorldBaseListener.java HelloWorldLexer.java HelloWorldListener.java
# 編譯生成的java文件
javac *.java
ANTLR提供了一個名為TestRig的調試工具,可以詳細列出匹配輸入文本過程中的信息,該工具類似於一個main方法,參數中接收一個語法名
和一個起始規則名
。前文已經將如下設置別名的命令加入到.bash_profile
文件中:
alias grun='java org.antlr.v4.gui.TestRig'
使用如下命令顯示識別過程中生成的詞法符號:
# 使用Hello語法和r規則啟動TestRig
grun HelloWorld r -tokens
# 輸入要識別的語句
hello world
# 輸入回車符結束輸入(Mac下輸入Crtl+D,Win下輸入Ctrl+Z)
# [@0,0:4='hello',<'hello'>,1:0]
# [@1,6:10='world',<ID>,1:6]
# [@2,12:11='<EOF>',<EOF>,2:0]
每行輸出代表一個詞法符號,以world
詞法符號為例,輸出結果為[@1,6:10='world',<ID>,1:6]
,@1
表示第二個詞法符號(從0開始),由輸入文本的第6個位置到第10個位置的文本組成(從0開始),內容是world
,詞法符號類型為ID
,位於文本的第1行(從1開始),第6個位置處(從0開始)。
使用-gui
參數可以使用圖形化界面展示出語法分析樹:
grun HelloWorld r -gui
hello world
如果想要查看grun
的幫助信息,可以在命令行直接輸入grun
:
grun
# java org.antlr.v4.gui.TestRig GrammarName startRuleName
# [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]
# [-trace] [-diagnostics] [-SLL]
# [input-filename(s)]
# Use startRuleName='tokens' if GrammarName is a lexer grammar.
# Omitting input-filename makes rig read from stdin.
# -tokens 打印出詞法符號流
# -tree 以Lisp格式打印語法樹
# -gui 可視化方式展示語法樹
# -ps file.ps 以PostScript格式生成可視化語法樹,然后存儲到file.ps中
# -encoding encodingname 指定編碼
# -trace 打印規則名稱,及離開規則時的詞法符號
# -diagnostics 開啟解析過程中的調試信息輸出
# -SLL 使用功能稍弱的解析策略