Antlr4学习2-Java开发
Antlr4学习2-Java开发
0x00 系列文章目录
0x01 摘要
本文主要讲下使用Java来围绕Antlr开发和应用。
0x02 简单例子
2.1 Maven依赖
在pom.xml里加入以下依赖:
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.7.1</version>
</dependency>
2.2 解析文件
新建一个解析文件SelectExample1.g4
:
grammar SelectExample1;
sql : 'select' WHAT 'from' tables ';';
WHAT : [a-z]+ ;
tables : WHAT;
WS : [ \t\r\n]+ -> skip ;
这是一个很简单的例子,匹配一条最简单的sql。
2.3 自动生成解析相关java类
在类上点右键,然后如下图所示操作:
可以找到生成的一批java类如下图:
我们按需把这些文件拷贝到目录下。
2.4 编写解析测试类
创建一个SelectDemo.java
文件如下内容:
package demos.antlr.select.demo1;
import demos.antlr.select.demo1.gen.SelectExample1Lexer;
import demos.antlr.select.demo1.gen.SelectExample1Parser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
/**
* Created by chengc on 2018/9/30.
*/
public class SelectDemo
{
public static void main(String[] args)
{
// first, form input charstream from string
CharStream input = CharStreams.fromString("select name from studetnt;");
// 1. Lexer-Lexical analysis
// Create a lexer that feeds off of input CharStream.
SelectExample1Lexer lexer = new SelectExample1Lexer(input);
// 2. Create a buffer of tokens pulled from the lexer.
CommonTokenStream tokens = new CommonTokenStream(lexer);
// 3. Parser-Syntax analysis
// Create a parser that feeds off the tokens buffer.
SelectExample1Parser parser = new SelectExample1Parser(tokens);
// 4. Begin parsing at "select" rule.
ParseTree tree = parser.sql();
System.out.println(tree.toStringTree(parser));
}
}
运行该main方法,输出的解析语法树结果如下:
(sql select name from (tables studetnt) ;)
0x03 语法树遍历模式
在idea里面通过.g4
文件生成java代码的时候,可配两种方式:
默认是listener模式。
3.1 Listener模式 (观察者模式,通过结点监听,触发处理方法)
在遍历语法树时,自动回调Listener中回调方法。
实现简单,全自动,只需要实现listener中的各个接口方法。即可完成语义表达。并采用深度优先遍历。
优点:
- 程序员不需要显示定义遍历语法树的顺序,实现简单
缺点:
- 不能控制遍历语法树的顺序
- 动作代码与文法产生式解耦,利于文法产生式的重用
- 没有返回值,需要使用map、栈等结构在节点间传值
3.2 Vistor模式 (访问者模式,主动遍历)
则提供了可以控制遍历过程的一种方式,通过显示调用visit方法,可以访问子树节点。
特点如下:
- 程序员可以显示定义遍历语法树的顺序
- 不需要与antlr遍历类ParseTreeWalker一起使用,直接对tree操作
- 动作代码与文法产生式解耦,利于文法产生式的重用
- visitor方法可以直接返回值,返回值的类型必须一致,不需要使用map这种节点间传值方式,效率高
0xFE 总结
这是一个总结