安装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的语法文件,并展示了测试过程。中间有一些细节没有在这里仔细讲解,在后面的笔记会陆续更新。最后附上一个稍微复杂一点的语法树的图。