antlr4 简单实用入门——(一)
Antlr4 简介
简介
Antlr4 是一款强大的语法生成器工具,可用于读取、处理、执行和翻译结构化的文本或二进制文件。基本上是当前 Java 语言中使用最为广泛的语法生成器工具。Twitter搜索使用ANTLR进行语法分析,每天处理超过20亿次查询;Hadoop生态系统中的Hive、Pig、数据仓库和分析系统所使用的语言都用到了ANTLR;Lex Machina将ANTLR用于分析法律文本;Oracle公司在SQL开发者IDE和迁移工具中使用了ANTLR;NetBeans公司的IDE使用ANTLR来解析C++;Hibernate对象-关系映射框架(ORM)使用ANTLR来处理HQL语言。参考2
Antlr4 提供了大量的官方 grammar 示例,包含了各种常见语言,非常全面,提供了非常全面的学习教材。
本文简单介绍一个示例,实现一个简单的计算器功能,这个例子在很多资料中都作为第一个示例,可以算是 Antlr4 的 HelloWorld。
基本概念
语法分析器(parser)是用来识别语言的程序,本身包含两个部分:词法分析器(lexer)和语法分析器(parser)。词法分析阶段主要解决的关键词以及各种标识符,例如 INT、ID 等,语法分析主要是基于词法分析的结果,构造一颗语法分析树。大致的流程如下图参考2所示。
语法解析基本流程
因此,为了让词法分析和语法分析能够正常工作,在使用 Antlr4 的时候,需要定义语法(grammar),这部分就是 Antlr 元语言。
语法解析基本流程
元语言
首先,要了解 antlr4 本身的定义 grammar 的语法,相对比较简单。我们以计算器的例子为例,简单讲解其中的概念。
// file: Calculator.g4
grammar Calculator;line : expr EOF ;
expr : '(' expr ')' # parenExpr| expr ('*'|'/') expr # multOrDiv| expr ('+'|'-') expr # addOrSubstract| FLOAT # float;WS : [ \t\n\r]+ -> skip;
FLOAT : DIGIT+ '.' DIGIT* EXPONET?| '.' DIGIT+ EXPONET?| DIGIT+ EXPONET?;fragment DIGIT : '0'..'9' ;
fragment EXPONET : ('e'|'E') ('+'|'-')? DIGIT+ ;
第一行,定义了 grammar 的名字,名字需要与文件名对应。
接下来的 line 和 expr 就是定义的语法,会使用到下方定义的词法,注意 # 后面的名字,是可以在后续访问和处理的时候使用的。一个语法有多种规则的时候可以使用 | 来进行配置。
在 expr 这行,我们注意到四则运算分为了两个非常相似的语句,这样做的原因是为了实现优先级,乘除是优先级高于加减的。
WS 定义了空白字符,后面的 skip 是一个特殊的标记,标记空白字符会被忽略。
FLOAT 是定义的浮点数,包含了整数,与编程语言中的浮点数略有不同,更类似 Number 的定义。
最后的 fragment 定义了两个在词法定义中使用到的符号。
在语法定义的文件中,大部分的地方使用了正则表达式。
生成文件
配置 antlr4 工具,先从官网下载 Antlr4 的 jar 包,点击下载地址进行下载。
alias antlr4="java -jar /path/to/antlr-4.5-complete.jar"
通过命令行工具可以生成 lexer、parser、visitor、listener 等文件。
visitor 是默认不生成的,需要带上参数 -visitor。
$ antlr4 -visitor Calculator.g4# 生成文件如下:
Calculator.interp
CalculatorBaseListener.java
CalculatorLexer.interp
CalculatorLexer.tokens
CalculatorParser.java
Calculator.tokens
CalculatorBaseVisitor.java
CalculatorLexer.java
CalculatorListener.java
CalculatorVisitor.java
使用 Visitor
Visitor 的使用是最为简单方便的,继承 CalculatorBaseVisitor 类即可,内部的方法与 g4 文件定义相对应,对照看即可理解。
public class MyCalculatorVisitor extends CalculatorBaseVisitor<Object> {@Overridepublic Object visitParenExpr(CalculatorParser.ParenExprContext ctx) {return visit(ctx.expr());}@Overridepublic Object visitMultOrDiv(CalculatorParser.MultOrDivContext ctx) {Object obj0 = ctx.expr(0).accept(this);Object obj1 = ctx.expr(1).accept(this);if ("*".equals(ctx.getChild(1).getText())) {return (Float) obj0 * (Float) obj1;} else if ("/".equals(ctx.getChild(1).getText())) {return (Float) obj0 / (Float) obj1;}return 0f;}@Overridepublic Object visitAddOrSubstract(CalculatorParser.AddOrSubstractContext ctx) {Object obj0 = ctx.expr(0).accept(this);Object obj1 = ctx.expr(1).accept(this);if ("+".equals(ctx.getChild(1).getText())) {return (Float) obj0 + (Float) obj1;} else if ("-".equals(ctx.getChild(1).getText())) {return (Float) obj0 - (Float) obj1;}return 0f;}@Overridepublic Object visitFloat(CalculatorParser.FloatContext ctx) {return Float.parseFloat(ctx.getText());}
}
实现了 visitor 之后,就可以完成一个简单的计算器了。
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;public class Driver {public static void main(String[] args) {String query = "3.1 * (6.3 - 4.51) + 5 * 4";CalculatorLexer lexer = new CalculatorLexer(new ANTLRInputStream(query));CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));CalculatorVisitor visitor = new MyCalculatorVisitor();System.out.println(visitor.visit(parser.expr())); // 25.549}
}
使用 Maven
Antlr4 提供了 Maven Plugin,可以通过配置来进行编译。
语法文件 g4 放置在 src/main/antlr4 目录下即可,配置依赖的 antlr4 和 plugin 即可。
生成 visitor 在 plugin 配置 visitor 参数为 true 即可。
注意:antlr4 的库版本要与 plugin 版本对应,antlr4 对生成文件用的版本与库本身的版本会进行对照,不匹配会报错。
...
<properties><antlr4.version>4.7.2</antlr4.version>
</properties><dependencies><dependency><groupId>org.antlr</groupId><artifactId>antlr4</artifactId><version>${antlr4.version}</version></dependency>
</dependencies>
...
<build><plugins><plugin><groupId>org.antlr</groupId><artifactId>antlr4-maven-plugin</artifactId><version>${antlr4.version}</version><configuration><visitor>true</visitor></configuration><executions><execution><id>antlr</id><goals><goal>antlr4</goal></goals></execution></executions></plugin></plugins>
</build>
...
打包
总结
本文较为简单地说了一个计算器的例子,只介绍了 visitor 的大致使用方法,最后还介绍了 maven plugin 的使用方法。
笔者还在学习 antlr4 以及编译原理,想用好语法生成器工具,还是需要对编译原理有一定的理解。
编辑原理:
(11条消息) Java-底层原理-编译原理_迷路剑客个人博客-CSDN博客_java底层原理
代码参考:
zhugezifang/antlr4-helloworld-demo (github.com)
参考:Antlr4 简介 - 分布式编程 (zthinker.com)
(1条消息) 基于 ANTLR 自己实现一个 SQL 解析器_过往记忆大数据-CSDN博客
GitHub - webgjc/sql-parser: 基于antlr4的sql解析,实现格式化,元数据,血源等自定义解析,包括mysql,hive,spark,presto
antlr4 简单实用入门——(一)相关推荐
- lua编程简单实用入门教程,用NodeMCU在OLED上显示温湿度
OLED模块介绍 OLED显示屏是指有机电激发光二极管(Organic Light-Emitting Diode,OLED),具备自发光,所以不需背光源,对比度高,厚度薄,视角广,反应速度快等特性,被 ...
- html+css+小图标,HTML+CSS入门 一个简单实用的CSS loading图标
本篇教程介绍了HTML+CSS入门 一个简单实用的CSS loading图标,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门.< 在web开发中,为了提高用户体验,在加载数据的时 ...
- PS入门教程:简单实用的PS快捷键教程1
今天带来一期超实用的PS快捷键教程.所谓的PS快捷键教程,就是为了在一定程度上提升日常工作中的绘图速度而定义的快捷方式.在工作中我们常看到同事不会去为了一个命令,在菜单和工具栏上寻寻觅觅,只是不停的敲 ...
- PS入门教程:简单实用的PS快捷键教程2
上篇内容从工具箱.文件操作.图层混合.选择功能.视图操作五方面入手分类总结了常用的PS快捷键教程.这篇内容小编再将从编辑操作.图像调整.加点按.取消操作这五方面为大家加码日常都可用到的PS快捷键教程. ...
- matlab简单程序实例_visual basic VB.NET实例系列教程第一节(简单实用抽奖程序)...
近期疫情原因,工作比较不忙,所以打算出一套零基础,VB.NET实例系列入门教程,实用又好玩,带大家进入VB的编程世界里,希望这套图文教程能帮到有需要的人! 第一节(简单实用抽奖程序) 内容准备:编译环 ...
- 【Python】分享几个用Python给图片添加水印的方法,简单实用
今天来分享几种可以给图片添加水印的方法,都是十分的简单实用,大家在看了之后也可以私底下去自己试试,有些方法需要的代码量就比较少,有些方法需要的代码量就稍微多一些,那我们开始吧 opencv模块 首先我 ...
- Emscripten 单词_分享15个英语单词记忆方法,简单实用,赶紧收藏吧!
分享15个英语单词记忆方法,简单实用,赶紧收藏吧! 单词是学习英语的基石,英语程度的好坏,单词是最重要的衡量标准.单词的构成方式其实很简单,就是26个字母的排列组合. 那有什么方法能够让我们更好地把单 ...
- 太妙了!几个用Python给图片添加水印的方法,简单实用!
今天来分享几种可以给图片添加水印的方法,都是十分的简单实用,大家在看了之后也可以私底下去自己试试,有些方法需要的代码量就比较少,有些方法需要的代码量就稍微多一些,那我们开始吧 opencv模块 首先我 ...
- visual basic VB.NET实例系列教程第一节(简单实用抽奖程序)
近期疫情原因,工作比较不忙,所以打算出一套零基础,VB.NET实例系列入门教程,实用又好玩,带大家进入VB的编程世界里,希望这套图文教程能帮到有需要的人! 第一节(简单实用抽奖程序) 内容准备:编译环 ...
最新文章
- vim学习笔记(四)
- 黄埔大学,选址定了!
- decorator java_装饰器模式-Decorator(Java实现)
- Nginx服务器启停方式介绍
- 国家普通话水平智能测试软件,国家普通话水平智能测试系统注意事项
- 第四次学习记录(ROS)
- 测试人员必看——掌握7大技能,做好自动化测试就不是问题!
- firefox关闭窗口问题
- 2020idea插件怎么同步_暴击单身狗,异地情侣居然靠一款插件同步追剧!
- 从开始的一无所有到现在的_我有房有车有高薪,凭什么娶一个“一无所有”的女人?...
- 【图像处理基础】基于matlab GUI图像局部放大【含Matlab源码 1016期】
- 申请ios证书并发布uniapp软件
- IP反向解析查询的方法
- kx驱动中的DSP设置
- 联想android电视软件下载,#联想智能电视普及风暴#绕开“乐商店”,大叔教你一步步在智能电视上安装第三方APK...
- duilib入门简明教程(1)
- Word页码从正文开始-请务必文档格式要规范,这在你未来的工作中的细节是很重要的
- 微信小程序图片加载失败渲染层网络层错误
- 游戏服务器为什么要选择高防服务器
- uni-app跳转连接到QQ