文章目录
- SQL 词法/语法分析
- 一、技术实现方案
- 1. Lex + Yacc
- 2. ANTLR
- 3. ANTLR 的 IDE ——ANTLRWorks2
- 4. jsqlparser - 基于javacc实现的解析器JSqlParser
- 4. Javacc/AST
SQL 词法/语法分析
一、技术实现方案
1. Lex + Yacc
- Lex:词法分析 - flex
- Yacc:语法分析 - bison
- 搭载语言:C语言
- 弊端:移植性不够,需要和以自动机为原理的YACC/LEX生成的一大堆整数表打交道。
相当于从零开始造轮子,遂短时间不建议实验。
不过也建议花十分钟简单看一下,在整个领域,他们实在太经典了,后面轻量级的 ANTLR 里面都有他们的思想。
2. ANTLR
-
参考资料:
-
ANTLR 总览:
工作总流程:词法分析,而后进行语法分析,语义分析,构建sql的AST- 词法分析器(Lexer):
词法分析器的工作是分析量化那些本来毫无意义的字符流,将他们翻译成离散的字符组(也就是一个一个的Token),包括关键字,标识符,符号(symbols)和操作符 供语法分析器使用。 - 语法分析器(Parser):
编译器又称为Syntactical analyser。在分析字符流的时候,Lexer不关心所生成的单个Token的语法意义及其与上下文之间的关系,而这就是Parser的工作。语法分析器将收到的Tokens组织起来,并转换成为目标语言语法定义所允许的序列。
无论是Lexer还是Parser都是一种识别器,Lexer是字符序列识别器而Parser是Token序列识别器。他们在本质上是类似的东西,而只是在分工上有所不同而已。 - 树分析器 (tree parser):
树分析器可以用于对语法分析生成的抽象语法树进行遍历,并能执行一些相关的操作。 - ANTLR:
ANTLR将上述结合起来,它允许我们定义识别字符流的词法规则 和 用于解释Token流的语法分析规则。
然后,ANTLR将根据用户提供的语法文件自动生成相应的词法/语法分析器。
用户可以利用他们将输入的文本进行编译,并转换成其他形式(如AST—Abstract Syntax Tree,抽象的语法树)。
- 词法分析器(Lexer):
-
ANTLR环境安装:
-
ANTLR安装:
windows上安装配置 ANTLR:建议使用 ANTLR-4.8版本
https://www.cnblogs.com/wynjauu/articles/9872822.html
ANTLR的4.4和其他版本不一致,会有以下的问题,解决方案如下。
找不到或无法加载主类 org.antlr.v4.gui.TestRig:https://blog.csdn.net/weixin_43171083/article/details/90510771 -
idea 中配置 ANTLR:
https://blog.csdn.net/qq_21383435/article/details/80814618
-
-
ANTLR 语法结构:
- 参考资料:
antlr4 实战 idea:https://blog.csdn.net/qq_39158142/article/details/86437919
简洁如下:
antlrv4"> //声明语法头,类似于java类的定义 grammar Name; //选项,如语言选项,输出选项,回溯选项,记忆选项等等 options {...} import ... ; // 符号(Token)名大写开头 // 解析规则(Parser rule)名小写开头,后面可以跟字母、数字、下划线 tokens {...} channels {...} // lexer only @actionName {...} // rule - 这是核心,表示规则,以 “:” 开始, “;” 结束, 多规则以 "|" 分隔。 rule1 // parser and lexer rules, possibly intermingled ... ruleN
- 参考资料:
-
ANTLR 使用流程:
ANTLR 官方demo:https://github.com/antlr/grammars-v4 。
官方仓库中提供了 ANTLR 多个方向的 ANTLR,关于 SQL 的 词法/语法解析,该仓库中也有提供。
ANTLR使用过程如下- 编写文法文件(g4后缀)
- 使用g4文法文件通过antlr工具生成lexer词法解析器、parser语法解析器、visitor和listener的runtime target文件(支持多种语言)
- 直接使用输出的runtime target文件模块进行开发工作
-
ANTLR 实战:
参考我的另一篇博客:ANTLR 实战 SQL 词法/语法分析
https://blog.csdn.net/pentiumCM/article/details/106077486
3. ANTLR 的 IDE ——ANTLRWorks2
-
参考资料:https://blog.csdn.net/u014454538/article/details/86351781
javaccJSqlParser_86">4. jsqlparser - 基于javacc实现的解析器JSqlParser
- 调用 Java 的 jar 包(相当于直接使用别人封装好的,自己拿过来使用即可)
- 搭载语言:java
- 参考资料:
- JSqlParser——SQL语法解释器:SQL解析样例:https://blog.csdn.net/Gigaplant/article/details/80452892
JSQLParser 来分析复杂SQL:https://www.jianshu.com/p/f57bc22b5b32
JSqlParser系列之二代码结构:https://www.cnblogs.com/liuwt0911/p/4420472.html
jsqlparser解析SQL工具类:https://blog.csdn.net/qq_26458903/article/details/89923522
- JSqlParser——SQL语法解释器:SQL解析样例:https://blog.csdn.net/Gigaplant/article/details/80452892
- 使用方式:
- maven 的 pom.xml 中添加如下的依赖:
<!-- jsqlparser解析SQL工具类--> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>1.4</version> </dependency>
- jsqlparser 语法demo:
java">package indi.pentiumcm.utils; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.parser.CCJSqlParser; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.parser.ParseException; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectBody; import net.sf.jsqlparser.util.AddAliasesVisitor; import net.sf.jsqlparser.util.SelectUtils; import net.sf.jsqlparser.util.TablesNamesFinder; import java.util.List; /** * @projName: JavaSkillStack * @packgeName: indi.pentiumcm.utils * @className: jsqlparserUtils * @author: pentiumCM * @email: 842679178@qq.com * @date: 2020/5/11 22:22 * @describe: jsqlparser工具类 */ public class jsqlparserUtils { public static void main(String[] args) throws JSQLParserException, ParseException { //1、简单的语句解析 // 1.1 单个语句 String sql = "SELECT * FROM TABLE1"; //方法1 Statement statement = CCJSqlParserUtil.parse(sql); //方法2 CCJSqlParser ccjSqlParser = new CCJSqlParser(sql); Statement statement2 = ccjSqlParser.Statement(); // 1.2 多个语句 String sqls = "SELECT * FROM TABLE1;SELECT * FROM TABLE2"; //方法1 Statements statements = CCJSqlParserUtil.parseStatements(sqls); //方法2 CCJSqlParser ccjSqlParser2 = new CCJSqlParser(sqls); // Statements statements3 = ccjSqlParser.Statements(); List<Statement> statementList = statements.getStatements(); // 2、简单的表达式解析 //表达式 Expression expression = CCJSqlParserUtil.parseExpression("a+b*c"); //条件表达式 Expression expression2 = CCJSqlParserUtil.parseCondExpression("A='123'"); // 3、从SQL中提取表名 String sql3 = "SELECT * FROM TABLE1"; Statement statement3 = CCJSqlParserUtil.parse(sql); TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); List<String> tableList = tablesNamesFinder.getTableList(statement); // 4、将别名应用于所有表达式 Select select = (Select) CCJSqlParserUtil.parse("SELECT A,B,C FROM TABLE1");//此处的运行时类是Select SelectBody selectBody = select.getSelectBody(); AddAliasesVisitor addAliasesVisitor = new AddAliasesVisitor(); addAliasesVisitor.setPrefix("B");//设置前缀(如不进行设置默认为“A”) selectBody.accept(addAliasesVisitor); System.out.println(selectBody.toString());//SELECT A AS B1, B AS B2, C AS B3 FROM TABLE1 // 5、向SELECT添加一列或表达式 Select select5 = (Select) CCJSqlParserUtil.parse("SELECT A FROM TABLE1"); SelectUtils.addExpression(select, new Column("B")); System.out.println(select);//SELECT A, B FROM TABLE1 } }
- maven 的 pom.xml 中添加如下的依赖:
4. Javacc/AST
- Javacc/AST简介:
JavaCC 是一个代码生成器,可以根据输入的语言定义输出一个词法分析器和解析器,JavaCC 输出的代码是合法的可编译Java代码.
解析器和词法分析器本身就是一个冗长而复杂的组件,手工编写一个这样的程序需要仔细考虑各条件的相互作用,总的来说,通过javacc完成一些字符串的分析,还是比较方便,现在普遍使用AST了。