什么是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 使用功能稍弱的解析策略