Goland 中Antlr4插件

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

下载步骤:

1.点击文件中的设置选项



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



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
;

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



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

我定义的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
;

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



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

编写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和规则名称重复。

遍历语法树



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就可以定义一个属于自己的语法规则的解析器了,如果有哪里不同的可以给小编留言,我们共同学习!!!

使用golang+antlr4构建一个自己的语言解析器(完结篇)的更多相关文章

  1. 自己动手写一个编译器Tiny语言解析器实现

    然后,上一篇文章简介Tiny词法分析,实现语言.本文将介绍Tiny的语法分析器的实现. 1 Tiny语言的语法 下图是Tiny在BNF中的文法. 文法的定义能够看出.INNY语言有以下特点: 1 程序 ...

  2. atitit.java解析sql语言解析器解释器的实现

    atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...

  3. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  4. 一个简单的json解析器

    实现一个简单地json解析器. 两部分组成,词法分析.语法分析 词法分析 package com.mahuan.json; import java.util.LinkedList; import ja ...

  5. 用c#自己实现一个简单的JSON解析器

    一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...

  6. VS Extension+NVelocity系列(一)——构建一个简单的NVelocity解析环境

    一.前言 本节我们将实际实现一个简单的NVelocity解析环境,以便为以后的实例做一些基本工作,虽然NVelocity如何使用已经属于老掉牙的话题,但我只能专门挑出来一章来做铺垫.人生就是这样无奈啊 ...

  7. 用c#写一个json的万能解析器

    CommonJsonModel .cs /// <summary> /// 万能JSON解析器 /// </summary> public class CommonJsonMo ...

  8. Cocos2dx游戏开发系列笔记13:一个横版拳击游戏Demo完结篇

    懒骨头(http://blog.csdn.net/iamlazybone QQ:124774397 ) 写下这些东西的同时 旁边放了两部电影 周星驰的<还魂夜> 甄子丹的<特殊身份& ...

  9. kotlin 写的一个简单 sql 查询解析器

    package com.dx.efuwu.core import org.apache.commons.lang.StringUtils import java.sql.PreparedStateme ...

  10. 从零构建一个简单的 Python Web框架

    为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...

随机推荐

  1. md5信息摘要算法实现(python 和 go版本)

    纯手写实现的md5信息摘要算法 github地址如下 https://github.com/kittysmith5/dgst/blob/main/md5 python3版本代码 #!/usr/bin/ ...

  2. 面向对象1(Java)

    什么是面向对象 面向对象编程(oop) 面向对象编程的本质是:以类的方式组织代码,以对象的组织(封装)数据 抽象 三大特征:封装.继承.多态 从认识论角度考虑是先有对象后有类.对象是具体的事物.类是抽 ...

  3. 通过VS Code轻松连接树莓派

    如果您正在使用树莓派作为开发平台,那么通过远程连接VS Code到树莓派是非常方便的一种方法.这样,您可以在Windows或macOS等计算机上开发和测试代码,而不必在树莓派上进行. 以下是通过VS ...

  4. 结对作业——考研咨询APP

    结对作业--考研资讯系统   102陈同学105潘同学108苏同学 (排版:Markdown) 一.需求分析(NABCD模型) 1. N(Need 需求): 1)想知道每个专业考研可以考哪个专业2)想 ...

  5. vue移动端登录与登录保持

    成品效果 首先进入首页点击右下角个人中心,若状态为登录中则进入个人中心页面,否则进入登录页 实现步骤 首先完成静态的登录页与个人中心页面 登录页 <template> <div cl ...

  6. js中函数(方法)注释

    原文链接:https://blog.csdn.net/tianxintiandisheng/article/details/103764074 实例 /** * @function 处理表格的行 * ...

  7. ubuntu14搭建内网gitlab服务器

    平台 宿主机系统版本:Ubuntu 14.04.5 LTS gitlab软件版本:11.10.8-ee 验证web浏览器版本:Mozilla Firefox 68.3.0esr 安装firefox浏览 ...

  8. nodejs批量重命名

    const fs = require("fs"); // directory path let config = {   affix: null,   src: null, }; ...

  9. ADB 命令 使用

    基本用法 命令语法 为命令指定目标设备 启动/停止 查看 adb 版本 以 root 权限运行 adbd 指定 adb server 的网络端口 设备连接管理 查询已连接设备/模拟器 USB 连接 无 ...

  10. 关于php pconnect长连接如何刷新连接的讨论

    由于每个pconnect所建立的连接信息和单个进程绑定.线上偶发了redis在某一台机器php-fpm上连接正常而无法进行任何操作的问题. 先说结论 查看redis拓展官方文档 close方法 有一句 ...