Antlr的使用
概念
ANTLR(ANother Tool for Language Recognition)是一个强大的解析器生成工具,用于读取、处理、执行或翻译结构化文本或二进制文件。ANTLR通过定义文法(grammar)来识别、构建和访问语言中的元素。
ANTLR为包括Java、C++、C#在内的多种语言提供了一个通过语法描述来自动构造自定义语言的识别器(recognizer)、编译器(parser)和解释器(translator)的框架。ANTLR使用Adaptive LL(*) 语法分析技术进行语法分析,支持词法分析、语法分析、语义分析以及代码生成等功能。
Antlr 提供了大量的官方Grammar示例,包含了各种场景语言,如SQL、Javascript等。
核心功能
1)自动生成语法分析器:ANTLR可以根据用户定义的语法规则自动生成相应的词法分析器和语法分析器,无需手动编写复杂的语法分析代码;
词法分析器(Lexer):负责将输入文本分割成一个个的标记(Token)。词法分析器不关心所生成的单个Token的语法意义及其与上下文之间的关系;
语法分析器(Parser):使用词法分析器生成的标记来构建语法树。语法分析器关注Token之间的语法关系和上下文信息;
2)语法树构造:ANTLR能够将输入文本转换为语法树(AST,Abstract Syntax Tree),使文本的结构更加清晰易懂;
3)语法错误提示:ANTLR在解析过程中能够发现语法错误,并提供详细的错误提示,帮助用户快速定位和修复问题;
4)自定义语言支持:ANTLR支持自定义语言的识别、解析和翻译,为开发者提供了极大的灵活性;
工作流程
1)定义语法规则:使用ANTLR的语法规范描述语言(通常为.g4文件)定义目标语言的语法规则;
2)生成解析器:使用ANTLR工具,根据语法规则文件,自动生成词法分析器和语法分析器的源码;
3)编译解析器:将自动生成的词法分析器和语法分析器的源代码拷贝到应用项目中,编译成可执行文件或库;
3)使用解析器:在应用程序中调用自动生成的解析器,对输入的文本进行解析,并根据生成的语法树进行其他处理;
ANTLR准备
本篇以IDEA中使用 Antlr 4.x 为例。
4.1 Antlr插件安装
在使用之前,要先安装Antlr插件。安装步骤如下:
打开 File - Settings - Plugins 菜单中,如图:
选择插件市场,搜索antlr。
如果搜索不了,可以修改代理,如图:
在弹出的界面中,选择自动代理,并在url中输入:
https://plugins.jetbrains.com/
如果以上配置还是搜索不了,可以直接在浏览器中访问JetBrains Marketplace,在界面中搜索antlr,并选择安装。如图:
4.2 插件使用
Antlr 插件安装之后,idea 开发工具中才能支持 .g4 文件的创建。
4.2.1 Generate ANTLR Recognizer
在 g4 文件中右击,选择 “Generate ANTLR Recognizer”,在项目的根目录,自动创建一个 gen 目录,自动生成词法分析器和语法分析器的源码。
如 Hello.g4 文件,自动的文件如下:
4.2.2 ANTLR Preview
在 Idea 中打开 “ANTLR Preview”,如下:
选择任意 g4 文件,在左侧输入框中输入满足条件的信息,右侧可以预览生成的解析树。
Hello 示例
5.1 示例
Antlr 支持正则表达式集合表示法。以下示例为使用 hello 开头的短语。
1)创建 Hello.g4 文件,文件内容如下:
grammar Hello; // 定义名字
@header {package com.jingai.antlr; } // java 的packages : 'hello' ID | EOF ; // 匹配关键字hello和标志符
ID: [a-z]+ ; // 标识符由小写字母组成
WS: [ \t\r\n]+ -> skip ; // 跳过空格、制表符、回车符和换行符
a)文件以 grammar 开头,名称跟着文件名 Hello;
b)@header 可以用于指定自动生成的词法分析器等 java 文件的报名;
c)在本例中,s 为解析树的root节点,如上面 4.2.2 所示;
d)ID 节点匹配任意长度的小写字母;
+:匹配一次或多次;*:匹配零次或多次;?:匹配零次或一次;
e)-> skip 用于指定跳过的信息;
f)EOF 结束标识;
2)使用 ANTLR Preview,可以预留生成的解析树,如 4.2.2 所示;
3)使用 Generate ANTLR Recognizer,自动生成词法分析器和语法分析器的源码,如 4.2.1 所示;
4)在项目中创建一个包,名称为 g4 文件中通过 @header 指定。将自动生成的 java 文件拷贝到包中;
5)自定义Visitor,代码如下:
package com.jingai.anltr.hello;import org.antlr.v4.runtime.tree.ParseTree;import java.util.List;public class EvalVisitor extends HelloBaseVisitor<String> {@Overridepublic String visitS(HelloParser.SContext ctx) {List<ParseTree> children = ctx.children;StringBuffer sb = new StringBuffer();for (ParseTree t : children) {System.out.println("visit child : " + t.getText());sb.append(t.getText()).append(" ");}return sb.toString();}}
在 Antlr 中,可以通过实现监听器(Listener)或访问者(Visitor)接口来遍历语法树。在自动生成的代码中,除了词法分析器和语法分析器以外,还生成了对应的 Listener 和 Visitor 接口以及基础的默认实现类。
5)编写测试用例,代码如下:
package com.jingai.anltr.hello;import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;public class HelloTest {public static void main(String[] args) {// 创建词法分析器 hello world 字符串HelloLexer lexer = new HelloLexer(CharStreams.fromString("hello world"));// 获取tokenCommonTokenStream tokens = new CommonTokenStream(lexer);// 解析tokenHelloParser parser = new HelloParser(tokens);// 获取根rootHelloParser.SContext tree = parser.s();EvalVisitor visitor = new EvalVisitor();System.out.println(visitor.visit(tree));}
}
执行以上的测试用例,打印的信息为:
5.2 解析
在上面的自定义Visitor中,在for循环中添加断点,执行信息如下:
1)visitS() 方法访问根节点 s,该根节点存在两个子节点,分别为 hello 和 world;
2)子节点的类型为TerminalNodeImpl,包含 symbol 和 parent 信息。其中symbol为当前节点的信息、parent为父节点信息;
a)symbol 为 CommonToken 类型,打印的信息为:[@1,6:10='world',<2>,1:6] ;
b)CommonToken 的 toString() 源码中,返回的代码如下:
return "[@" + this.getTokenIndex() + "," + // 索引,从0开始this.start + ":" + this.stop + // 开始和结束位置"='" + txt + "', // 对应文本<" + typeString + ">" + // 类型channelStr + "," + // 频道信息,在 g4 文件中可以通过 channel() 指定this.line + ":" + // 所在的行,从1开始this.getCharPositionInLine() + "]"; // 所在行的开始位置,从0开始
c)结合以上分析,[@1,6:10='world',<2>,1:6] 表示如下:
@1表示为第1个,即第2个;
6:10表示文本在第6个字符到第10个字符之间;
<2>表示类型为2。可以在自动生成的代码中查看;如:
1:6表示在第1行,从第6个字符开始;
算式计算示例
以下通过计算表达式的解析,计算表达式的值为例。
1)创建Calcultor.g4文件,代码如下:
grammar Calculator;@header {package com.jingai.antlr.calculator; } // java 的packageexpr: INT # int| expr op=('*'|'/') expr # mulDiv| expr op=('+'|'-') expr # addSub| '(' expr ')' # brackets| EOF # e;INT : [0-9]+ ;MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;WS: [ \t\r\n]+ -> skip ; // 跳过空格、制表符、回车符和换行符
a)| 表示或的关系,即 expr 是由 INT 或者乘除表达式或者加减表达式或者括号表达式组成;
b)在每一项后面使用 # 加字母,在自动生成的Visitor或Listener中,会自动生成对应的visit或enter方法。如 # mulDiv,在CalcultorVisiter中,自动生成 visitMulDiv()方法;
二义性处理
所谓的二义性是指解析的信息同时匹配多种语法结构。如上面算式表达式,如果要解析的是
5 + 2 * 3,那么 5 + 2 匹配了加法表达式,2 * 3 匹配了乘法表达式,此时就存在二义性。
在 Antlr 中,通过使输入字符串和语法中第一个指定的规则匹配来解决词法二义性。
如上面的 5 + 2 * 3,因为在语法定义中,乘除是放在加减前面,所以会匹配先匹配乘法。解析树为:
如果在语法中修改乘除和加减的位置,同一个表达式,解析树为:
2)通过 Generate ANTLR Recognizer 自动生成源码,并拷贝到项目;
3)编写Visiter类,进行算式运算,代码如下:
package com.jingai.anltr.calculator;public class MyCalculatorVisitor extends CalculatorBaseVisitor<Integer> {/*** 加减运算*/@Overridepublic Integer visitAddSub(CalculatorParser.AddSubContext ctx) {// 获取加减运算左右的数字Integer left = visit(ctx.expr(0));Integer right = visit(ctx.expr(1));// 根据计算类型,执行相应计算,并返回计算结果if(ctx.op.getType() == CalculatorParser.ADD) {return left + right;}return left - right;}/*** 乘除运算*/@Overridepublic Integer visitMulDiv(CalculatorParser.MulDivContext ctx) {// 获取乘除运算左右的数字Integer left = visit(ctx.expr(0));Integer right = visit(ctx.expr(1));if(ctx.op.getType() == CalculatorParser.MUL) {return left * right;}return left / right;}@Overridepublic Integer visitInt(CalculatorParser.IntContext ctx) {return Integer.parseInt(ctx.INT().getText());}@Overridepublic Integer visitBrackets(CalculatorParser.BracketsContext ctx) {return visit(ctx.expr());}
}
4)编写测试用例,代码如下:
package com.jingai.anltr.calculator;import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;public class CalculatorTest {public static void main(String[] args) {CalculatorLexer lexer = new CalculatorLexer(CharStreams.fromString("12-(3*3)+8-4/2"));CommonTokenStream tokens = new CommonTokenStream(lexer);CalculatorParser parser = new CalculatorParser(tokens);CalculatorParser.ExprContext tree = parser.expr();MyCalculatorVisitor visitor = new MyCalculatorVisitor();System.out.println(visitor.visit(tree));}
}
执行结果如下:
其他语法
1)通过@parser::members{},添加 java 代码,该代码会自动添加到Parser解析器中;
2)使用locals,定义局部变量,添加 java 代码,对应代码会自动添加到Parser解析器对应的标签解析中;
3)默认情况下,Antlr 从左到右结合运算符进行解析,对于特殊情况,需要从右到左的,可以使用assoc手动指定,示例如下:
expr : expr '^'<assoc=right> expr // 运算符是右结合的| INT;
4)支持语义谓词添加,示例如下:
// 示例一
group : INT sequence[$INT.int]; // INT为int类型sequence[int n] locals [int i = 1;] // 在自动生成的Parser类的sequence()方法中,会添加 int n 的参数: ({$i <= $n}? INT {$i++;})* ;INT : [0-9]+ ;// 示例二
predicates: expression predicate[$expression.ctx]? // expression的ctx为ParserRuleContext类型;predicate[ParserRuleContext value] : // 在自动生成的Parser类的predicate()方法中,会添加ParserRuleContext value的参数expression: STR;
小结
本篇分析到这里,以下做一个小结:
1)Antlr 用于按照编写的语法规则,解析文本字符串。语法支持正则表达式规则;
先将文本按词进行分解,而后通过语法进行匹配分析。
2)通过 ANTLR Preview,可以预留解析树;
3)通过 Generate ANTLR Recognizer,可以自动生成词法分析器和语法分析器;
在语法中,可以按照特定格式添加对应语言的代码,代码将自动添加在Parser语法分析器中。(也可在自动生成后的Parser语法分析器代码中进行修改,该种方式不太规范)
4)通过继承自动生成的Visiter或Listener,可以对解析后的信息进行提取即相应处理;
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。
参考:
《ANTLR 4简明教程》 - 书栈网 · BookStack
GitHub - antlr/grammars-v4: Grammars written for ANTLR v4; expectation that the grammars are free of actions.
相关文章:
Antlr的使用
概念 ANTLR(ANother Tool for Language Recognition)是一个强大的解析器生成工具,用于读取、处理、执行或翻译结构化文本或二进制文件。ANTLR通过定义文法(grammar)来识别、构建和访问语言中的元素。 ANTLR为包括Jav…...
HealChat心理大语言模型 丨OPENAIGC开发者大赛高校组AI创作力奖
在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者,希望能带给…...
PyQt5整合爬虫制作图片爬取器-幽络源
前言 本篇教程适合对Python爬虫和Python软件制作感兴趣的小伙伴阅读,看完本篇教程,你将能更深入了解PyQt5与实际功能的整合方式。 1.设计界面 首先在pycharm中创建一个新目录,这里我建立的目录名为爬图片,然后按如图打开Qt设计…...
DC00023基于jsp+MySQL新生报到管理系统
1、项目功能演示 DC00023基于jsp新生报到管理系统java webMySQL新生管理系统 2、项目功能描述 基于jspMySQL新生报到管理系统项目分为学生、辅导员、财务处和系统管理员四个角色。 2.1 学生功能 1、系统登录 2、校园新闻、报到流程、学校简介、在线留言、校园风光、入校须知…...
AdaptIoT——制造业中使用因果关系的自我标签系统
0.概述 论文地址:https://arxiv.org/abs/2404.05976 在许多制造应用中,机器学习(ML)已被证明可以提高生产率。针对制造业应用提出了一些软件和工业物联网(IIoT)系统,以接收这些 ML 应用。最近&…...
代码随想录算法训练营Day15
654.最大二叉树 力扣题目链接:. - 力扣(LeetCode) 前序递归、循环不变量 class Solution {public TreeNode constructMaximumBinaryTree(int[] nums) {return findmax(nums,0,nums.length);}public TreeNode findmax(int[] nums,int lefti…...
Thinkphp/Laravel旅游景区预约系统的设计与实现
目录 技术栈和环境说明具体实现截图设计思路关键技术课题的重点和难点:框架介绍数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 技术栈和环境说明 采用PHP语言开发,开发环境为phpstudy 开发工具notepad并使用MYSQL数据库…...
SpringCloud学习记录|day1
学习材料 2024最新SpringCloud微服务开发与实战,java黑马商城项目微服务实战开发(涵盖MybatisPlus、Docker、MQ、ES、Redis高级等) 学redis讲到微服务就停了,nginx也是。 所以嘛,我终于来到微服务了。 复习MyBatisP…...
Elasticsearch讲解
1.Elasticsearch基本知识 1.基本认识和安装 Elasticsearch是由elastic公司开发的一套搜索引擎技术,它是elastic技术栈中的一部分。完整的技术栈包括: Elasticsearch:用于数据存储、计算和搜索 Logstash/Beats:用于数据收集 Kib…...
Linux嵌入式有发展吗,以及对uboot,kernel,rootfs的领悟
工作多年后,对uboot,kernel,rootfs的领悟,总结 上大学时,51单片机,正点原子的stm32,linux arm开发。对uboot,kernel,rootfs的理解云里雾里,感觉自己很懂了 其…...
基于Springboot+Vue的公寓管理系统(含源码+数据库)
1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 该系统…...
多功能声学气膜馆:承载梦想与希望的舞台—轻空间
在9月29日上午,苏州大学应用技术学院的2024级新生开学典礼暨开学第一课在轻空间建造的多功能声学气膜馆内盛大举行。这一盛典不仅见证了2849名新生的入学,也展示了气膜馆的独特魅力与优越功能。 卓越的声学表现 声学气膜馆采用高性能材料,确保…...
【线程】线程池
线程池通过一个线程安全的阻塞任务队列加上一个或一个以上的线程实现,线程池中的线程可以从阻塞队列中获取任务进行任务处理,当线程都处于繁忙状态时可以将任务加入阻塞队列中,等到其它的线程空闲后进行处理。 线程池作用: 1.降…...
输出 / 目录下所有目录文件的大小并排序
使用 du -sh /* 输出 / 目录下所有的目录总大小,看下效果: [rootlocalhost ~]# du -sh /* 0 /bin 110M /boot 0 /dev 32M /etc 12K /home 0 /lib 0 /lib64 0 /media 0 /mnt 0 /opt du: cannot access ‘/proc/2731/task/2731/fd/4’: No such file or …...
【hot100-java】【编辑距离】
多维dp篇 class Solution {public int minDistance(String word1, String word2) {char [] sword1.toCharArray();char [] tword2.toCharArray();int ns.length;int mt.length;int [][] fnew int[n1][m1];for (int j1;j<m;j){f[0][j]j;}for(int i0;i<n;i){f[i1][0]i1;for…...
随手记:牛回速归
上周-国庆前:牛回速归 国庆:小心被套住 国庆后:一片迷茫 总结:要是上周到国庆前的基本都能捞到,后面情况不好说 后续持续更新...
UI设计师面试整理-设计过程和方法论
在UI设计师面试中,清晰地阐述你的设计过程和方法论是至关重要的。这不仅可以展示你的专业技能和设计思维,也能让面试官看到你是如何解决实际设计问题的。以下是一个全面的UI设计过程和常用方法论的概述,你可以根据你的经验进行相应调整。 1. 设计过程 a. 研究与发现阶段(Re…...
ACM 纳新每日一题 4329: 三进制
首先我们要学习的是数制转化 这里我找了一篇博客https://blog.csdn.net/weixin_53564801/article/details/123665194 一定要注意0需要单独特判一下,这个点尤其重要 然后关于这道题可以使用递归来实现,如下: 递归的代码比较简洁,但…...
WebGIS包括哪些技术栈?怎么学习?
WebGIS,其实是利用Web开发技术结合地理信息系统(GIS)的产物,它是一种通过Internet实现GIS交互操作和服务的最佳途径。 WebGIS通过图形化界面直观地呈现地理信息和特定数据,具有可扩展性和跨平台性。 它提供交互性&am…...
无人机之集群控制及应用
一、无人机集群控制 无人机集群控制是指通过先进的通信、导航和控制算法,实现多架无人机之间的协同、协调和高效的任务执行。其关键技术包括: 通信技术:实现无人机之间的实时数据传输和共享,确保集群控制的准确性和稳定性。 路径…...
AV1 Bitstream Decoding Process Specification--[9]:语法结构语义-5
原文地址:https://aomediacodec.github.io/av1-spec/av1-spec.pdf 没有梯子的下载地址:AV1 Bitstream & Decoding Process Specification摘要:这份文档定义了开放媒体联盟(Alliance for Open Media)AV1视频编解码…...
APISIX 联动雷池 WAF 实现 Web 安全防护
Apache APISIX 是一个动态、实时、高性能的云原生 API 网关,提供了负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。 雷池是由长亭科技开发的 WAF 系统,提供对 HTTP 请求的安全请求,提供完整的 API 管理和…...
音频剪辑还能在线做?以前的我真是OUT了,效果秒杀专业软件
以前,剪辑音频都得靠那些专业的音频师,用很贵的设备和复杂的软件才行。不过,现在有了互联网和云计算,在线音频剪辑变得简单多了。只要你有台能上网的电脑或者手机,就能轻松做出很棒的音频。这个变化让更多人都能玩音频…...
Library介绍(三)
环境描述 工作条件 一般lib文件里面包含了芯片的工作条件即operation conditions,其指定了工艺(process)、温度(temperature)和电压(voltage),见图1。 其中,process代表了…...
VMware搭建DVWA靶场
目录 1.安装phpstudy 2.搭建DVWA 本次搭建基于VMware16的win7系统 1.安装phpstudy 下载windows版本:小皮面板-好用、安全、稳定的Linux服务器面板! 安装后先开启mysql再开启apache,遇到mysql启动不了的情况,最后重装了phpstud…...
使用 Llama-index 实现的 Agentic RAG-Router Query Engine
前言 你是否也厌倦了我在博文中经常提到的老式 RAG(Retrieval Augmented Generation | 检索增强生成) 系统?反正我是对此感到厌倦了。但我们可以做一些有趣的事情,让它更上一层楼。接下来就跟我一起将 agents 概念引入传统的 RAG 工作流,重新…...
一行命令将Cmder添加到系统右键菜单中----配置环境
第一步,去官网下载一个简版的文件 ** 第二步,将下载的文件解压后如图,找到Cmder.exe右键以管理员身份运行 第三步,在窗口输入cmder /register all然后回车 第四步,OK!不管在哪里都可以使用了,直接右键即可...
【系统架构设计师】专题:基于构件的软件工程考点
更多内容请见: 备考系统架构设计师-核心总结目录 文章目录 一、构件概述二、构件模型三、CBSE的特征四、CBSE的过程五、构件组装一、构件概述 基于构件的软件工程(Component-Based Software Engineering,CBSE) 是一种基于分布对象技术、 强调通过可复用构件设计与构造软件系…...
目前最好用的爬虫软件是那个?
作为一名数据工程师,三天两头要采集数据,用过十几种爬虫软件,也用过Python爬虫库,还是建议新手使用现成的软件比较方便。 这里推荐3款不错的自动化爬虫工具,八爪鱼、亮数据、Web Scraper 1. 八爪鱼爬虫 八爪鱼爬虫是一…...
运营计划管理——电商运营(案例分享)
运营计划,作为运营管理的重要组成部分,通过科学规划与有效执行,对确保企业目标实现起着至关重要的作用。 运营计划是指通过制定、执行、监控和调整运营计划,以确保企业资源得到合理配置,业务活动有序进行,最…...
苏州招聘网站建设/杭州百度推广开户
题解在下已经写过一次了,所以就不再写了,下面只有代码 题解下载(1):http://pan.baidu.com/s/1hsAUjMs 题解下载(2):http://pan.baidu.com/s/1mhC7EYk A 卿学姐与公主 代码 #include <iostream> #include <cstdio> #include <a…...
制作网站工具/网站一般怎么推广
719. 找出第 k 小的距离对 给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值。 示例 1: 输入: nums [1,3,1] k 1 输出:0 解释: 所有数对如下: (1,3) ->…...
设计装修网站大全/管理人员课程培训
最近一直没有项目做,于是我也不能这样闲着,我得开始学习新的技术,并且巩固以前自学的技术。以下就是我写的一个简单的java存取款代码,很简单,可能还有更简单的方法,目的是为了熟悉java的基本使用。package …...
网站开发用什么图片格式最好/建站流程
一、主键自增 1.设置数据库中,主键自增 2.设置VS中Model1.edmx 二、级联删除 使用Data Annotations: 如果我们要到一对主从表增加级联删除,则要在主表中的引用属性上增加Required关键字,如: public class Destination{…...
网站建设实战教程/2022年十大网络流行语发布
在正文之前,我想问大家一个问题:问:亲,你有基础吗?答: 有啊,你说前端吗? 不就是HTML,JS,CSS 吗? so easy~问: oh-my-zsh... 好吧,那问题来了,挖掘机技术哪家强... 开玩笑。 现在才是问题的正内…...
吴中公司网站建设找哪家/各大免费推广网站
3.9 闲聊数据类型 字符串: 单引号 双引号 三引号 数值: 整数 浮点 布尔 复数类型3.9.1 整型(整数) Python3的整型和长整型无缝结合 不再区分 长度取决于内存 优点-利于大数计算3.9.2 浮点型(小数) 科学记数法 E记法 也可以是e 源码…...