一.ANTRL 是什么

当我们实现一种语言时,我们需要构建读取句子(sentence)的应用,并对输入中的元素做出反应。如果应用计算或执行句子,我们就叫它解释器(interpreter),包括计算器、配置文件读取器、Python解释器都属于解释器。如果我们将句子转换成另一种语言,我们就叫它翻译器(translator),像Java到C#的翻译器和编译器都属于翻译器。不管是解释器还是翻译器,应用首先都要识别出所有有效的句子、词组、字词组等,识别语言的程序就叫解析器(parser)或语法分析器(syntax analyzer)。我们学习的重点就是如何实现自己的解析器,去解析我们的目标语言,像DSL语言、配置文件、自定义SQL等等。

手动编写解析器是非常繁琐的,所以我们有了ANTLR。只需编写ANTLR的语法文件,描述我们要解析的语言的语法,之后ANTLR就会自动生成能解析这种语言的解析器。也就是说,ANTLR是一种能写出程序的程序。而用来声明我们语言的ANTLR语言的语法,就是元语言(meta-language)。

二.ANTRL 语法

文件结构

/** Optional javadoc style comment */
grammar Name;
options {...}
import ... ;tokens {...}
channels {...} // lexer only
@actionName {...}rule1 // parser and lexer rules, possibly intermingled
...
ruleN

grammar 声明语法头,类似于java类的定义

grammar  SPL;

options 选项,如语言选项,输出选项,回溯选项,记忆选项等等

options { output=AST;  language=Java; }options { tokenVocab=MySqlLexer; }

rule 表示规则,以 “:” 开始, “;” 结束, 多规则以 "|" 分隔

ID : [a-zA-Z0-9|'_']+ ;    //数字
STR:'\'' ('\'\'' | ~('\''))* '\'';
WS: [ \t\n\r]+ -> skip ; // 系统级规则 ,即忽略换行与空格sqlStatement: ddlStatement | dmlStatement     | transactionStatement| replicationStatement     | preparedStatement| administrationStatement     | utilityStatement;

注释

  • 单行、多行、javadoc风格
  • javadoc风格只能在开头使用
/** * This grammar is an example illustrating the three kinds* of comments.*/
grammar T;/* a multi-linecomment
*//** This rule matches a declarator for my language */decl : ID ; // match a variable name

标识符

  • 符号(Token)名大写开头
  • 解析规则(Parser rule)名小写开头,后面可以跟字母、数字、下划线
ID, LPAREN, RIGHT_CURLY // token names
expr, simpleDeclarator, d2, header_file // rule names

ANTLR 语法识别一般分为二个阶段:

1.词法分析阶段 (lexical analysis)

对应的分析程序叫做 lexer ,负责将符号(token)分组成符号类(token class or token type)

2.解析阶段

根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)

3.递归下降解析器

ANTLR生成的解析器叫做递归下降解析器(recursive-descent parser),属于自顶向下解析器(top-down parser)的一种。递归下降指的就是解析过程是从语法树的根开始向叶子(token)递归.

。还是以前面的赋值表达式解析为例,其递归下降解析器的代码大概是下面这个样子:

Assign很简单,直接顺序读取输入字符,不用做任何选择。相比之下,根结点Stat要复杂一些,因为它有多种选择。解析时,要向前看(lookahead)一些字符才能确认走哪个分支代码,有时甚至要读取完所有输入才能预测出,而ANTLR默默为我们处理了一切!

三. 解析树上的应用

如下图所示,解析树的叶子节点指向Token流中的Token,而Token中的起止字符索引指向字符流,而非拷贝子字符串。而像空格这种不与任何Token相关的字符会直接被Lexer丢弃掉。

ANTLR为每个Rule都会生成一个Context对象,它会记录识别时的所有信息。

四.树遍历

ANTLR提供了Listener和Visitor两种遍历机制。

Listener是全自动化的,ANTLR会主导深度优先遍历过程,我们只需处理各种事件就可以了。而Visitor则提供了可控的遍历方式,我们可以自行决定是否显示地调用子结点的visit方法。

String sql = "DELETE FROM T1 WHERE COL1 = TRUE AND (COL2 - COL3 <= (SELECT COUNT(*) FROM T2) OR MAINCOL/2 > 100.2);".toUpperCase();
final MySqlLexer mySqlLexer = new MySqlLexer(CharStreams.fromString(sql));
//字符组成单词(token)
final CommonTokenStream commonTokenStream = new CommonTokenStream(mySqlLexer);
//词法分析:将负责将符号(token)分组成符号类
final MySqlParser mySqlParser = new MySqlParser(commonTokenStream);
//根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)
final ParseTree tree = mySqlParser.root();
//遍历树节
ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
ExtractInterfaceListener extractor = new ExtractInterfaceListener(parser);
walker.walk(extractor, tree); // initiate walk of tree with listener

String sql = "DELETE FROM T1 WHERE COL1 = TRUE AND (COL2 - COL3 <= (SELECT COUNT(*) FROM T2) OR MAINCOL/2 > 100.2);".toUpperCase();
final MySqlLexer mySqlLexer = new MySqlLexer(CharStreams.fromString(sql));
//字符组成单词(token)
final CommonTokenStream commonTokenStream = new CommonTokenStream(mySqlLexer);
//词法分析:将负责将符号(token)分组成符号类
final MySqlParser mySqlParser = new MySqlParser(commonTokenStream);
//根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)
final MySqlParser.RootContext selectStatementContext = mySqlParser.root();
//遍历树节点
MySqlParserBaseVisitor visitor = new MySqlParserBaseVisitor();
visitor.visit(selectStatementContext);

四.实践

准备工作

1 安装IDE插件

我这里使用的是Intellij IDEA,所以就去Plugins中搜“ANTLR v4 grammar plugin”插件,重启IDEA即可使用。如果想在IDE外使用,需要下载ANTLR包,是JAVA写成的,后面在IDEA中的各种操作都可以手动执行命令来完成。

2 编写.g4文件

创建一个文件,后缀名是g4,只有这样在文件上点右键才能看到ANTLR插件的菜单。

/*
这个grammar的名称为ArrayInt ,必须与文件名相同
*/
grammar ArrayInt;/* 一条rule  符号(token)分组*/
init : '{' value (',' value)* '}' ;
/* 一条rule*/
value : init| INT;
/* lexer 词法分析规则*/
INT : [0-9]+ ;
WS : [ \t\r\n]+ -> skip ;

3.自动生成代码

在.g4文件上右键就能看到ANTLR插件的两个菜单,分别用来配置ANTLR生成工具的参数(在命令行中都有对应)和触发生成文件。首先选配置菜单,将目录选择到main/java或test/java。注意:ANTLR会自动根据Package/namespace的配置,生成出包的文件夹,不用预先创建出来。

之后就点生成菜单,于是就在我们配置的目录下,自动生成出的如下代码:

4 构建应用代码

有了生成好的解析器,我们就可以在它上面构建出好玩的应用了。

在开始编写应用代码之前,我们要引入ANTLR运行时。因为我们的解析器其实只是一堆回调hook,真正的通用解析流程实现是在ANTLR runtime包中。所以,以Maven为例ANTLR v4的依赖是:

<dependency><groupId>org.antlr</groupId><artifactId>antlr4-runtime</artifactId><version>4.8</version>
</dependency>
String arrayInt = "{1,2,3}";
final ArrayIntLexer arrayIntLexer = new ArrayIntLexer(CharStreams.fromString(arrayInt));
//字符组成单词(token)
final CommonTokenStream commonTokenStream = new CommonTokenStream(arrayIntLexer);
//词法分析:将负责将符号(token)分组成符号类
final ArrayIntParser arrayIntParser = new ArrayIntParser(commonTokenStream);
//根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)
final ArrayIntParser.InitContext selectStatementContext = arrayIntParser.init();
//遍历树节点
ArrayIntBaseVisitor visitor = new ArrayIntBaseVisitor();
visitor.visit(selectStatementContext);

Antlr v4入门教程和实践相关推荐

  1. vim入门教程(实践第一)

    2019独角兽企业重金招聘Python工程师标准>>> vim 是一个具有很多命令的功能非常强大的编辑器.限于篇幅,在本教程当中      就不详细介绍了.本教程的设计目标是讲述一些 ...

  2. 时间序列入门教程,从理论到业务实践,Kaggle kernels Master 整理分享

    一.前言 最近逛了逛Kaggle,发现了一个非常详细的时间序列教程. 里面记载了很多关于时间序列的知识,并且一直在updating中. 可以看到这个教程已经被观看了6w多次. 点赞700+, copy ...

  3. 【D1N910】正则表达式30分钟入门教程 (一)-学习笔记 实践

    目录 一.正则表达式介绍 二.bilibili正则表达式入口 三.正则表达式入门 四.元字符表 五.字符转义 正常操作,正常分析,大家好,我是D1n910 本文学习自 正则表达式30分钟入门教程 ht ...

  4. 【D1N910】正则表达式30分钟入门教程 (二)-学习笔记 实践

    正常操作,正常分析,大家好,我是D1n910. 本文学习自 正则表达式30分钟入门教程 http://deerchao.net/tutorials/regex/regex.htm 书接上文 六.重复 ...

  5. antlr idea 入门_ANTLR入门:构建简单的表达语言

    antlr idea 入门 这是该系列的第一篇文章. 本系列的目的是描述如何创建有用的语言和所有支持工具. 在本文中,我们将开始研究一种非常简单的表达语言. 我们将在语言沙箱中构建它,因此我们将其称为 ...

  6. flex+android+教程,android开发flex4.5入门教程.pdf

    android开发flex4.5入门教程 中国矿业大学教务部 教务通知(2013 )第33 号 关于做好各级"大学生创新训练计划" 项目中期检查和结题验收的通知 各学院: 为加强我 ...

  7. 渐进式Web应用(PWA)入门教程(上)

    最近关于渐进式Web应用有好多讨论,有一些人还在质疑渐进式Web应用是否就是移动端未来. 但在这篇文章中我并不会将渐进式APP和原生的APP进行比较,但有一点是可以肯定的,这两种APP的目标都是使用户 ...

  8. Scala开发入门教程

    出处:http://blog.csdn.net/mapdigit/article/details/21878083 Scala语言和其它语言比如Java相比,算是一个比较复杂的语言,它是一个面向对象和 ...

  9. eBPF Tracing 入门教程与实例

    2019独角兽企业重金招聘Python工程师标准>>> 原文链接 Learn eBPF Tracing: Tutorial and Examples 译者 弃余 在 LPC'18(L ...

最新文章

  1. mysql5.6.42 力资源_MySQL5.6.42解压版安装教程
  2. Matlab 条形图实例
  3. java class类文件结构
  4. mysql用户及权限管理_MySQL 用户及权限管理
  5. 【Python】IDE环境Pycharm运行虚拟环境Django
  6. 老有人问你什么是Docker?把这篇干货文章甩给他!
  7. linux 权限拒绝,linux – 权限被拒绝,虽然文件是chmod 777
  8. tx2 刷机, cudnn安装失败,手动安装
  9. HTM皮质学习算法资料
  10. 基于SSM的订餐管理系统
  11. zabbix3.2短信告警脚本
  12. java 日期 英文月份_java日期月份转英文格式
  13. kmplayer音轨切换(换配音)
  14. 深耕地产 20 年,拿下90%头部客户,“明源云”能为垂直行业 SaaS 带来哪些启发?
  15. 【论文阅读】Coupled Iterative Refinement for 6D Multi-Object Pose Estimation
  16. 医疗管理系统-项目概述和环境搭建
  17. 数据库优化——慢查询MySQL定位优化流程
  18. Hibernate持久化对象生命周期之实战探索
  19. CSIP发布软件自主创新评估系统平台
  20. 亚马逊为什么能够成为创新力最强的公司

热门文章

  1. “error LNK1123
  2. Trimble RealWorks处理点云数据(三)之点云抽稀取样
  3. Trimble MB-Two OEM GNSS板 参考手册(四)
  4. 灰度传感器、、、diy原理。。图
  5. 随便做点图:苹果电磁炉海报
  6. 计算机室在初中英语教学中的应用,信息技术在初中英语教学中的运用
  7. java 动态行转列_行转列的三种实现方式
  8. 随机不重复:从以下学员名单中随机选出4个学员:var arr = [“鹿晗“,“王俊凯“,“蔡徐坤“,“彭于晏“,“周杰伦“,“刘德华“,“赵本山“];注意:不要有重复的学员
  9. 第009天:APP的网络连接
  10. 小程序自定义Tabber,使其图标突出