阅读:6616回复:0
Antlr v4 介绍
环境准备
1.IntelliJ IDEA 2018.3.2 x64 安装Antlr插件(ANTLR v4 grammar plugin) 2.Antlr的jar包(我是通过maven引入) <dependency>
<groupId>org.antlr</groupId> <artifactId>antlr4-runtime</artifactId> <version>4.7.2</version> </dependency> 一 .Antlr是什么 Antlr是一款用java语言开发的语法分析生成工具。二.Antlr有什么作用 Antlr可用来读取、处理、执行和翻译结构化的文本或二进制文件。三.Antlr语法 1.示例: 在环境准备中创建的项目下新建一个文件,命名为Hello.g4 grammar Hello; r : 'hello' ID ; // 匹配'hello' ID : [a-z]+ ; // 匹配小写字母 WS : [ \t\r\n]+ -> skip ; // 跳过空格、制表符和换行 之后配置Antlr代码生成选项,在g4文件上右键,选择“Configure ANTLR...”选项,弹出配置窗口 图片:antlr04.png 配置好后右键g4文件,选择“Generate ANTLR Recognizer”选项 此时可以看到,Antlr自动在我们配置的目录下生成了一系列的文件: 图片:abtlr06.png 可观察,所有文件都是以g4文件的名称开头。 此时,我们如下操作: 图片:antlr10.png 可以看到,系统将我们输入的文字根据我们编写的语法检测规则自动生成了语法树。2.总述 规则以 “:” 开始, “;” 结束, 多规则以 "|" 分隔。 3.grammer 声明语法头,应该和该语法文件名称相同,即示例中的语法文件应名为Hello.g44.语法分析器规则 r : 'hello' ID ; 识别语言的程序称为语法分析器(parser) 或者句法分析器(syntax analyzer) 。句法(syntax) 是指约束语言中的各个组成部分之间关系的规则 其中r必须为小写字母为开头,后面可以跟字母、数字、下划线 5.词法分析器规则 ID : [a-z]+ ; 其中ID为大写开头 6.注释 和java中类似,/** */只能用在开头,然后是/* */ 和// 用法和java一致 7.->skip 该标志代表跳过此词法,不解析它 四.Antlr遍历模式 遍历模式分为监听器模式与访问器模式。 监听器模式能够对特定规则的进入和退出事件(即识别到某些词组的事件)作出晌应,这些事件分别由语法分析树遍历器在开始和完成对节点的访间时触发。并且监听器方法不负责显式调用子节点的访间方法。 优点:a.实现简单,不用主动设置节点访问顺序 b.语法规则与处理代码解耦,方便重用 缺点:a.不能设置节点访问顺序 b.处理方法没有返回值,若存在值传递问题的话可能需要其他数据结构 实现方式: 首先,我们需要编写一个类,继承BaseListener类。 关于BaseListener类,查看其方法结构: 图片:antlr12.png 可以发现,他会将我们g4文件中规定的语法分析规则r生成了enterR和exitR方法。 我们编写的监听类: public class MyListener extends HelloBaseListener { Map<String, String> props = new HashMap<String, String>() ; @Override public void exitR(HelloParser.RContext ctx) { String r = ctx.getText(); // props.put ("r", r) ; } } 然后我们编写一个测试方法: String filePath = "E:\\t\\hello.txt"; try{ //处理文件 File file = new File(filePath); CharStream input = CharStreams.fromPath(file.toPath()); HelloLexer lexer = new HelloLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); HelloParser parser = new HelloParser(tokens); ParseTree parseTree = parser.r(); // 新建一个标准的ANTLR 语法分析树遍历器 ParseTreeWalker walker = new ParseTreeWalker(); //新建一个监盺器,将其传递给凅历器 MyListener myListener= new MyListener() ; walker.walk(myListener,parseTree); // 遍历语法分析树 System.out.println(myListener.props); //打印结果 }catch (Exception e){ e.printStackTrace(); } 运行这个类,结果为:{r=helloworld} 访问器模式必须显式触发对子节点的访间以便树的遍历过程能够正常进行。因为访间器机制需要显式调用方法来访间子节点,所以它能够控制遍历过程中的访间顺序,以及节点被访间的次数。 优点:a.能够设置节点访问顺序以及访问次数 b.语法规则与处理代码解耦,方便重用 c.处理方法能直接返回值 实现方式: 首先,Antlr在开发工具中生成java类时默认是不会生成visitor相关文件的,我们需要在配置Antlr的java类生成时选中下方的选项: 图片:antlr13.png 然后再次右键g4文件,选择“Generate ANTLR Recognizer”选项,再次生成一遍 图片:antlr14.png 可看到生成了visitor相关文件。 图片:antlr15.png 同样生成了和语法规则名称相同的方法 public class MyVisitor extends HelloBaseVisitor { Map<String, String> props = new HashMap<String, String>() ; @Override public Object visitR(HelloParser.RContext ctx) { String r = ctx.getText(); // props.put ("r", r) ; return super.visitR(ctx); } } 然后写一个测试方法 try{ String filename = "E:\\t\\hello.txt"; File file = new File(filename); CharStream input = CharStreams.fromPath(file.toPath()); HelloLexer lexer = new HelloLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); HelloParser parser = new HelloParser(tokens); ParseTree parseTree = parser.r(); MyVisitor myVisitor = new MyVisitor(); myVisitor.visit(parseTree); System.out.println(myVisitor.props); }catch (Exception e){ e.printStackTrace(); } 同样会输出五.思考 根据以上所罗列的Antlr的特点以及其运用场景,我们可以想到其实Antlr可以做很多很多事。比如说,我们有一个从数据库导出的建表语句。若想获得其中的元数据信息,一般方法为通过正则表达式的方式处理脚本文件。而对于Antlr来说,同样可以做这件事,并且用Antlr编写语法规则文件比用正则表达式要简单一些,门槛相对来说比较低。也就是说,Antlr可以通过一种较简单的指定语法规则的方式去解析具有某种规则的脚本,可扩展性也比较好。六.相关链接 ANTLR 官方网址 http://www.antlr.org/ |
|
最新喜欢:何万里 |