antlr实现解析sql语法树-检测sql是否与数据库字段匹配
xsobi 2024-12-06 20:28 23 浏览
前言
- 你有没有想过 idea 是如何做到sql 关键字语法高亮的?毫无疑问需要识别出sql 的关键字。
antlr
- antlr 就是这么一个工具,他能够解析sql ,下面我们通过他来实现表名的获取
安装
antlr-tools
- 首先我们下载上面的antlr 工具 , 然后再通过工具分析每种sql 的语法,每种sql的语法需要我们额外准备,你可以自己将sql 的语法编写好,这里我就直接使用官方提供的语法了。
sql语法
bash复制代码 git clone https://github.com/antlr/grammars-v4.git
- 在开始sql解析之前,我们先将焦点移到antlr , antlr 是一个语法解析器工具,sql只是其中一个解析,所以我们先开始一段简单的语法解析吧。
安装文档
windows安装
- 上方文档我们移动到windows章节,首先antlr需要java环境,然后将上方我们下载antlr-4.11.1-complete.jar配置到环境变量中。官网也提到了配置环境变量可以在终端中临时配置也可以在系统环境变量中永久配置。
临时配置环境变量
- 在终端中执行 SET CLASSPATH=.;C:\Javalib\antlr-4.11.1-complete.jar;%CLASSPATH% 即可在终端中临时设置了变量。
永久配置环境变量
- 这样配置只要是新打开的终端都是可以获取到CLASSPATH 这个环境变量的。
小结
- 这里需要注意的是,在配置CLASSPATH这个环境变量时必须配置 . , 如果不配置在执行到grun命令时会报错Can't load Hello as lexer or parser。
antlr4&&grun
- 因为antrl4基于java包,每次运行要从java调用,为了方便使用写一个批处理文件(.bat文件)放在antlr-4.11.1-complete.jar同一文件夹下,自己命名,我命名为antlr4.bat
- 为了能够访问我们的自定义脚本,这里我们需要将antlr-4.11.1-complete.jar所在目录配置成环境变量。我这里是E:/study/antlr/antlr-4.11.1-complete.jar
- 然后我们就可以在E:\study\antlr的目录下新建一个脚本antlr4.bat , 内容如下
ini复制代码 doskey antlr4=java org.antlr.v4.Tool $*
doskey grun=java org.antlr.v4.gui.TestRig $*
- 这样我们可以执行antlr4.bat命令后就可以在终端执行antlr4&&grun命令了。官网也介绍到我们可以分别为antlr4和grun创建脚本
antlr4.bat
erlang复制代码 java org.antlr.v4.Tool %*
grun.bat
ini复制代码 @ECHO OFF
SET TEST_CURRENT_DIR=%CLASSPATH:.;=%
if "%TEST_CURRENT_DIR%" == "%CLASSPATH%" ( SET CLASSPATH=.;%CLASSPATH% )
@ECHO ON
java org.antlr.v4.gui.TestRig %*
测试
- 到了这里我们的antlr4已经安装完成了,那么我们该如何进行语法测试呢?
ini复制代码 grammar Hello; // 1、定义文法的名字
s : 'hello' ID ; // 3、匹配关键字hello和标志符
ID : [a-z]+ ; // 标志符由小写字母组成
WS : [ \t\r\n]+ -> skip ; // 4、跳过空格、制表符、回车符和换行符
- 下面针对语法进行相关解释:
- 定义了 grammar 的名字,名字需要与文件名对应
- s定义的语法,会使用到下方定义的正则表达式词法
- 定义了空白字符,后面的 skip 是一个特殊的标记,标记空白字符会被忽略。
ini复制代码 grammar Hello;
r : 'hello' ID ;
ID : [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;
打开终端
- 针对新打开的终端我们执行antlr4 就会执行我们配置的E:\study\antlr\antlr4.bat 脚本。执行完成之后就可以执行内部命令了。
- 通过antlr4 Hello.g4进行语法翻译
- 会生成一些Java类,这些类就是我们用来解析相关文本的工具类。为了能够执行这些Java 我们先 javac编译一下
复制代码 javac Hello*.java
grun解析
- 下面我们通过grun进行demo解析
复制代码 grun Hello r -tree
- 如下命令就会进行等待我们输入文本。Hello.g4的语法就是 hello [a-z]+ 这个正则,也就是所有的hello开头的文本,中间一个空格后面跟着由小写字母组成的字符的整个文本就会被解析出来。
(注意:^D在 Unix 上表示 control-D 并表示“输入结束”;^Z在 Windows 上使用。)
Linux安装
- windows是大多数人使用的系统,但是Linux才是最终的服务环境,加之我本身就是Linux作为开发环境,所以Linux安装对于我而言很重要。
- 因为antlr本事就是jar ,得以与java的跨平台所以这里资源两个系统是可以通用的。
- linux上配置环境变量更方便,我们只需要在~/.bashrc或者~/.zshrc中配置即可
bash复制代码 export CLASSPATH=".:/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH"
- 在终端中给命令创建别名
ini复制代码 alias antlr4='java -Xmx500M -cp "/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
alias grun='java -Xmx500M -cp "/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
- 或者我们也可以按照windows方式的命令,其实最终都是执行相同的类
ini复制代码 alias antlr4='java org.antlr.v4.Tool '
alias grun='java org.antlr.v4.gui.TestRig'
- export和alias可以同时配置在~/.zshrc中。
可视化
- TestRig充当一款调试工具,官网建议我们将它重命名为grun
- 直接输入grun可以看到其支持的参数。
参数 | 功能 |
-tokens | 打印出词法符号流 |
-tree | LISP格式打印分析树,啥叫LISP? |
-gui | 可视化打印分析树 |
-ps fiels.ps | 以PostScript格式生成可视化语法分析树 |
-trace | 打印规则的名字以及进入和离开该规则时的语法符号 |
- 不管是linux还是windows我们都可以通过 -gui的方式进行可视化
自定义解析
- 从4.11开始,antlr大约支持10种语言进行语法解析,上面案列中我使用的是Java 语言的解析工具,只需要javac编译一次即可,或者直接将相关的Java代码拷贝到项目中进行调用。下面我们看看如何生成Python语言的解析代码吧。
python
复制代码 pip3 install antlr4-python3-runtime
- 因为是测试python的语法生成,这里就不配置快捷命令了,所以这里使用全命令java -jar ../antlr-4.11.1-complete.jar -Dlanguage=Python3 Hello.g4
ini复制代码 import sys
from antlr4 import *
from HelloLexer import HelloLexer
from HelloParser import HelloParser
def main(argv):
input = FileStream(argv[1])
lexer = HelloLexer(input)
stream = CommonTokenStream(lexer)
parser = HelloParser(stream)
tree = parser.r()
print(tree.toStringTree(recog=parser))
if __name__ == '__main__':
main(sys.argv)
- 上述代码就是我们对antlr生成的解析代码的使用,这样我们可以进行自定义的处理。
解析Mysql
xml复制代码 <dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.11.1</version>
</dependency>
- 版本需要保持一致。
- 上一章节中我们通过一个简单的Hello.g4语法进行Java、python等语言的解析代码的生成。上章节也提到antlr是一个语法解析工具,并不仅仅是解析sql , 理论上他能解析所有的语法,比如你自己有一套语法如何让antlr解析呢?你只需要按照antlr的规则用antlr的语言表达出你自己的语法,目前比较规范的就是https://github.com/antlr/grammars-v4.git这个仓库提供的语法解析树了,本次对mysql解析也是使用这个仓库下提供的g4 文件。
- 这个仓库给我们提供了MySqlLexer.g4和MySqlParser.g4两个文件,前者是Mysql的关键词,后者就是Mysql的语法配置。examples是作者给我们提供的Mysql相关的sql 。 我们可以用来测试用。
- 为了方便测试,这里我们将这两个g4文件拷贝到其他目录下执行生成Java解析代码
复制代码 antlr4 MySqlParser.g4 MySqlLexer.g4
- 两个文件没有先后顺序区别,但是要注意的是不能缺少。笔者就是一开始认为只需要MysqlParser.g4一再在报错。MySqlParser.g4:2595:37: cannot create implicit token for string literal in non-combined grammar: '|'。
- 执行完上述命令后,我们就可以看到我们的Java代码了.
- 这样的代码是没有包名的,好在antlr在生成代码时支持指定包名。antlr4 MySqlParser.g4 MySqlLexer.g4 -package com.github.zxhtom.mysql
作者:zxhtom
链接:https://juejin.cn/post/7246177710728282169
相关推荐
- C/C++编程笔记:C++中的函数重载(c++如何实现函数重载)
-
函数重载是C++中的一项功能,其中两个或多个函数可以具有相同的名称,但可以具有不同的参数。当函数名称因不同的作业而被重载时,称为函数重载。在函数重载中,“函数”的名称应相同,而参数则应不同。函数重载...
- C/C++编程笔记:C++中的运算符重载
-
在C++中,我们可以使运算符为用户定义的类工作。这意味着C++能够为运算符提供数据类型的特殊含义,这种能力称为运算符重载。例如,我们可以在String之类的类中重载运算符'+',以...
- 变频器如何区分重载和轻载?我们应该如何进行选择?
-
在选择变频器的过程中,重载和轻载是两个非常重要的参数。它是我们选择变频器的先决条件。1、那什么是轻型负载,轻型负载有哪些特征?轻载典型特征就是能拖动同等功率的负载,但是它的输出转距较小。像我们经常用到...
- 面试官:Java的重写和重载有什么区别?
-
先来看一段重写的代码吧。class LaoWang{ public void write() { &...
- Idea项目的创建和模块的导入Java中方法的三种调用方式和方法重载
-
一:如何创建工程和模块File-->New-->Project...EemptProject-->Next输入Finish-->Ok-->NewWindow关闭刚创建...
- C# - 构造方法重载与调用,析构方法(*) 068
-
构造方法重载普通方法构成重载的规则:方法名称一样,对应位置参数的类型或个数不同可以构成方法重载而构造方法的构成规则与此一样注意事项:如果方法的访问修饰符是private(还有其他的访问修饰符之后再说)...
- Java方法的重载与重写详解(java方法重载的规则是哪些)
-
1.方法的重载1.1.基本介绍在同一个类中,允许多个重名方法的存在,但要求形参列表不一致。比如:System.out.println(11)//输出整数System.out.println(...
- Go如何优雅的解决方法的重载(golang 优雅重启)
-
1、问题你是否曾经见过这样的代码funcHandler(){//...}funcHandler(timeOuttime.Duration){//..}fu...
- 你知道Java方法重载的本质吗?(java的方法重载是什么意思)
-
背景考大家一道题目,下面的类执行结果是什么???publicclassDispatcherClient{publicstaticvoidmain(String[]args)...
- Java方法重载&栈的了解(java方法重载有什么用)
-
函数的重载1.函数重载重载:在同一个类中,允许存在一个以上的同名函数,只要他们的参数个数或者参数类型不同即可。看一下示例:实例中函数名都为add,但是参数表(圆括号中的参数类型+形参)中的参数类型或者...
- 初学java常见问题:Java方法的重载是咋回事?
-
前言小千在之前给大家讲解构造方法的时候说过,在一个类中,可以定义多个构造方法,这叫做方法的重载!但是关于方法重载,具有有哪些要求和细节?很多小白还并不清楚,所以在今天的这篇文章中,小千给大家详细说说方...
- C#基础之方法重载(c# 重载运算符)
-
在具有相同名称但具有不同参数列表的类中定义多个方法时。此方法参数在参数的数量、类型和顺序上必须不同。这称为方法重载。方法重载是多态性的一种形式。C#中的方法重载方法重载的语法:以下是在C#中使用方...
- 观察者模式-Java实现(观察者模式实例)
-
介绍观察者模式的使用场景非常广泛,小到代码层面的解耦,达到架构层面的系统解耦,再或者到一些产品的设计思路,都有这种模式的影子。现在我们常说的基于事件驱动的架构,其实也是观察者模式的一种最佳实践。当我们...
- 如何使用Go实现观察者模式(观察者模式的使用场景)
-
#从今天起记录我的2023##头条创作挑战赛#观察者模式是一种设计模式,它允许对象之间的松散耦合,因为这些对象不需要知道彼此的细节信息,只需要知道如何通知其他对象,以便它们可以做出相应的响应。在g...
- JAVA实现观察者模式,其实真的很简单
-
#头条创作挑战赛#概述观察者模式,又叫发布/订阅模式(Publish-Subscribe)。定义对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于他的对象都会收到通知并且执行对应的...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- characterencodingfilter (33)
- getmonth (34)
- label换行 (33)
- android studio 3 0 (34)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- xmlhttp (35)
- mysql更改密码 (34)
- 权限777 (33)
- htmlposition (33)
- 学校网站模板 (34)
- textarea换行 (34)
- 轮播 (34)
- asp net三层架构 (38)
- bash (34)