使用golang+antlr4构建一个自己的语言解析器

news2025/2/4 21:43:58

Goland 中Antlr4插件

在goland中安装Antlr4插件,用于识别输入的字符在在语法文件中生成的语法树的样子,大概就是如下的摸样

下载步骤:
1.点击文件中的设置选项
 

image


2.在插件目录下输入Antlr4搜索插件
 

image


3.点击安装即可

编写自己的语言语法文件

编写语法之前,我们首先要构思一下自己的DSL都有什么关键字,这是个重要的步骤,就像我们学习java或者Golang一样,首先知道这个语法里面都有那些关键字。
我定义的DSL中有四则运算,有比较运算,还有逻辑运算,变量可以有数字、字符串、时间格式

关键字

四则运算

作用符号
乘法*
除法/
加法+
减法-

比较运算

作用符号
等于=
不等于<>
大于>
大于等于>=
小于<
小于等于<=

逻辑运算

作用符号
&&
||
如果if
否则else

变量

作用符号
数字('0' | [1-9] ('_'? [0-9])*)
文本[\p{Nd}]
字符串LETTER (LETTER
日期([0-9]{4}/[0-1]{0,1}[0-9]/[0-3]{0,1}[0-9])

常量辅助符号

作用符号
.
逗号,
左括号(
右括号)
分号;
多行注释'/*' .*? '*/'

上述就是我们的Token列表,可以创建一个文法文件单独写Token,文法文件申明:lexer grammar Lexer;

编写语法

编写语法之前,我们需要构思一下,我们的DSL可以支持那些语法操作,例如四则运算可以支持字符串运算吗?日期支持四则运算吗?我们可以从基础开始编写,例如我们把变量使用算则模式编写成一个语法规则,

simpleStmt:NUMBER|TEXT|STRING|DATE

我的DSL中支持任何数据的四则运算,那么我就可以使用simpleStmt和四则运算符号组成四则运算

expression:
simpleStmt #SimpleExpression
|expression op = (MUL|DIV) expression #MulDiv
|expression op = (ADD|SUB) expression #AddSub
;

这时候我们就定义了支持四则运算的语法规则,我们来试一下语法定义的对不对。
 

image


发现我们输入的加法运算和乘法运算都可以被解析,说明我们的语法定义正确。接下来我们添加比较运算

我定义的DLS支持所有数据做比较运算,那么我直接在上面的expression中添加比较运算就可以了,这里需要注意的是比较运算如果希望有优先级,需要先定义优先级高的比较符号,我这里没有优先级操作,所以都是平级的。

添加比较运算符号

expression:
simpleStmt #SimpleExpression
|expression op = (MUL|DIV) expression #MulDiv
|expression op = (ADD|SUB) expression #AddSub
|expression op = (EQ|NE|LT|LE|GT|GE) expression #Compare
;

验证一下比较运算语法定义的是否正确。
 

image


发现没有错误,正确解析出树就代表语法定义的正确。接下来大家可以自己构思一下剩下的语法规则,或者添加自己的语法规则了。大概思路就是先想一个语法希望是什么样,然后编写语法规则,然后输入希望的格式验证语法规则。

编写Listener

还是老样子,编写号语法文件,我们执行Antlr4生成运行时语言为Go的命令:
java -jar 'C:\Program Files\Java\antlr\antlr-4.12.0-complete.jar' -Dlanguage=Go -no-visitor -package parser *.g4
编写监听器类

type CalcListener struct{
	*parser.BaseCalcListener //继承Listener基类
	*antlr.DefaultErrorListener //继承错误基类
}

//发生错误时,处理错误
func (l *CalcLister) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {

}

//退出MulDiv语法时
func (l *CalcLister) ExitMulDiv(c *parser.MulDivContext) {

}
//退出AddSub语法时
func (l *CalcLister) ExitAddSub(c *parser.AddSubContext) {

}
//退出数字语法时
func (l *CalcLister) ExitNumber(c *parser.NumberContext) {

}

这里细心的小伙伴已经发现,在语法文件中使用“#”指定的节点名称在监听器中回生成一个节点方法,在Antlr4中,“#”号代表手动指定语法规则名称,需要注意的是,不要跟Token和规则名称重复。

遍历语法树

image


Antlr4遍历语法树时,使用DFS方式遍历树

监听模式和访问模式

Antlr4提供了两种遍历语法树的方式,监听模式和访问模式,默认是监听模式,如果希望使用访问模式的话,需要修改命令:
java -jar 'C:\Program Files\Java\antlr\antlr-4.12.0-complete.jar' -Dlanguage=Go -visitor -package parser *.g4
这样会生成访问者模式和监听者模式

calc_base_listener.go //监听者模式基类文件
calc_base_visitor.go //访问者模式基类文件

访问者模式:先遍历父节点,然后遍历子节点
监听者模式:Enter先进入父节点,Exit最后退出父节点
个人建议还是使用监听者模式,在Enter控制子节点访问,Exit做父节点子树执行逻辑。访问者模式控制能力更强,监听者模式需要遍历整个树。

至此,使用golang+Antlr4就可以定义一个属于自己的语法规则的解析器了,如果有哪里不同的可以给小编留言,我们共同学习!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761759.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DDD落地实践复盘 - 记理论培训事件风暴

DDD毕竟是一个指导方法&#xff0c;想落地扎根还是需要很多尝试的&#xff0c;笔者整理了一下在部门内践行推广之初的复盘小结&#xff0c;这可能是多数团队在推广DDD时都会遇到的问题&#xff0c;希望能对大家有所帮助。 DDD在部门进行两次尝试&#xff0c;一次是PPT培训&…

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 三)

页面和自定义组件生命周期 在开始之前&#xff0c;先明确自定义组件和页面的关系&#xff1a; 自定义组件&#xff1a;Component装饰的UI单元&#xff0c;可以组合多个系统组件实现UI的复用。页面&#xff1a;即应用的UI页面。可以由一个或者多个自定义组件组成&#xff0c;E…

springMVC(四)—— 简化配置之不用再写@Repository类

这种简化配置的方法在下面这篇博客中已经用到了&#xff0c;但是因为太重要了&#xff0c;所以把他单独拿出来讲。 springMVC&#xff08;三&#xff09;—— 整合SSM框架_玛丽莲茼蒿的博客-CSDN博客IDEAtomcat 8。https://blog.csdn.net/qq_44886213/article/details/1316570…

【六袆 - Java】Kafka的由来,Kafka创始人,Kafka企业级应用开发;Kafka是一种分布式流处理平台和消息队列系统;

kafka是一门什么技术&#xff1f; Kafka是一种分布式流处理平台和消息队列系统&#xff0c;用于解决高吞吐量、低延迟的数据处理和消息传递问题。它最初由LinkedIn开发&#xff0c;旨在应对LinkedIn在大规模社交网络中处理实时数据流的需求。 它的由来 Kafka的历史可以追溯到…

git学习笔记 |常用命令

文章目录 Git学习笔记是什么&#xff1f;Git的工作机制Git和代码托管中心 Git的常用命令设置签名本地库初始化 git init添加到暂存区 git add将暂存区的文件提交到本地库 git commit查看历史版本 git log/git reflog版本穿梭 git reset Git的分支分支命令合并分支时代码冲突删除…

GBT51277-2018矿山立井冻结法施工及质量验收标准

为规范矿山立井冻结法施工及质量验收保障施T安全确保施工质量,制订本标准。 本标准适用于冰点高于一2C地下水流速小于5m/d、地温低于35C、冲积层厚度小于700m、冻结深度小于950m的立井井筒冻结法施T及质量验收。 立井冻结法施T工程承包合同和技术文件对施工质量要求不应低于本…

Android 自定义按键添加流程

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、驱动通过GPIO连接的按键二、Framework 层添加按键响应方法三、参考文献 一、驱动通过GPIO连接的按键 此类按键采用GPIO来连接&#xff0c;通过监测…

变压器试验介质损耗

试验目的 介质损耗因数 tanδ (% ) 是判断变压器绝缘状态的一种较有效的手段, 主要用来检 查变压器整体受潮、 油质劣化及严重的局部缺陷等, 但不一定能发现变压器局部受潮 等集中性局部缺陷。 试验设备 异频介质损耗测试仪 厂家&#xff1a; 湖北众拓高试 试验接线 (1) 介…

MacBook M1 VulnHub靶机搭建(arm Mac搭建x86 ova镜像)

个人博客: xzajyjs.cn 自从换了M1系的arm Mac后&#xff0c;原本的Vulnhub上的几乎所有靶场按照之前的方法都无法正常搭建了&#xff08;VirtualBox&#xff09;&#xff0c;在外网论坛上找了一遍&#xff0c;有一个相对麻烦一些的替代方法&#xff0c;但效果还是不错的&#x…

MFC演示双缓冲绘图算法

VC6新建一个单文档工程&#xff1b; 先添加一个小球类&#xff1b; 头文件和cpp文件如下&#xff1b; #if !defined(AFX_SPHERE_H__835B2B85_5B12_4409_AEC0_9C5062625DDE__INCLUDED_) #define AFX_SPHERE_H__835B2B85_5B12_4409_AEC0_9C5062625DDE__INCLUDED_#if _MSC_VER &…

MySQL-DQL-基本查询

数据库操作DQL语句 DQL DQL英文全称Data Query Language&#xff08;数据查询语言&#xff09;&#xff0c;用来查询数据库表中的记录关键词&#xff1a;SELECT语法 基本查询条件查询&#xff08;where&#xff09;分组查询&#xff08;group by&#xff09;排序查询&#xff0…

智能办公解决方案——电子标签

智能电子办公标签概要&#xff1a; 电子会议桌牌它外形美观大方&#xff0c;完全取代了传统塑料、纸质或铜制桌牌&#xff0c;是会议桌面显示设备的一大创新&#xff0c;与传统桌牌相比&#xff0c;具有信息化程度高、可反复使用的特点&#xff0c;是现代信息化会议的理想工具…

小物体检测、分割论文

文章目录 2023CaraNet: Context Axial Reverse Attention Network for Segmentation of Small Medical Objects 2023 CaraNet: Context Axial Reverse Attention Network for Segmentation of Small Medical Objects 摘要&#xff1a; 目的&#xff1a;准确、可靠地分割医学图…

Ubuntu 考虑采用新的 “统一默认安装 (unified default install)”

导读Ubuntu安装程序中的 “最小化安装” (Minimal installation) 是该发行版多年来最受欢迎的功能之一。 当用户选择 Ubuntu 的 “最小化安装” 选项时&#xff0c;可以在安装更少的预装应用程序情况下&#xff0c;获得完整、功能齐全的 Ubuntu 系统。 但这个功能可能要被砍掉…

【CSDN新星计划】初阶牛C/C++赛道——顺序程序设计(C语句②)

目录 3.2 最基本的语句——赋值语句 3.2 最基本的语句——赋值语句 在C程序中最常用的语句是:赋值语句和输入输出语句。其中最基本的是赋值语句程序中的计算功能大部分是由赋值语句实现的,几乎每一个有实用价值的程序都包括赋值语句。有的程序中的大部分语句都是赋值语句。先介…

进程间通信之命名管道

进程间通信之命名管道 命名管道1.命名管道概念2.创建一个命名管道2.1用命名管道实现通信2.2用命名管道实现server&client通信 命名管道 1.命名管道概念 管道应用的一个限制就是只能在具有共同祖先&#xff08;具有亲缘关系&#xff09;的进程间通信&#xff0c;这种通信可…

高并发的哲学原理(十)-- 理论无限容量:站在地球表面

前面两篇文章每一篇都花了我五十个小时以上&#xff0c;写的我是欲仙欲死&#xff0c;本文我们来务点虚&#xff0c;上上价值。 我们将从微服务架构讲起&#xff0c;一步一步追根溯源&#xff0c;找寻“分布式数据库”在另一个维度的投影&#xff0c;探寻基建、应用、服务、组织…

Java:运算符、位运算 的运算规则与用法详解

目录 运算符Math数学函数与常量类型转换强制类型转换自增和自减运算符关系运算符三元运算符 位运算& 与| 或^ 异或~ 按位取反<< >> 左移 右移运算符优先级 运算符 Math数学函数与常量 import java.lang.Math.*; public class Test{public static void main(S…

java项目之智能仓储系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的智能仓储系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&…

十八、网页端在移动端的像素

一、简介 -1. 在不同的屏幕&#xff0c;单位像素的大小是不同的&#xff0c;像素越小&#xff0c;屏幕越清晰。 手机端的像素就是宽度和高度&#xff0c;如iphone6 4.7寸 750 x 1334。 -2. 手机的像素点 远远小于 计算机的像素点。 问题&#xff1a;一个宽度为900px的网页在i…