SQL 语句解析过程详解(附带完整demo)

这篇具有很好参考价值的文章主要介绍了SQL 语句解析过程详解(附带完整demo)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文末有惊喜哦 👇👇👇

本文主要是使用 Flex 和 Bison 工具实现一个简单的 SQL 解析器,最终生成抽象语法树!

下面先分别对 Flex 和 Biosn 原理进行介绍,然后给出 SQL 解析器的完整 Demo!

1.输入SQL语句

2.  Flex词法分析器 

2.1 Flex 原理

1、使用 flex 工具定义正则表达式规则来匹配不同类型的词法单元;例如,可以定义以下规则: 

  • 匹配关键字:SELECT、FROM、WHERE、HAVING等。
  • 匹配标识符:由字母或下划线开头,后跟字母、数字或下划线组成。
  • 匹配运算符:比如=、<、>、+、等。
  • 匹配常量:包括整数、浮点数、字符串等。

2、生成词法分析器代码:根据定义的词法规则,使用Flex工具生成对应的词法分析器代码;

3、输入查询字符串:将要解析的查询字符串作为输入提供给同法分析器;

4、扫描和匹配:词法分析器从输入字符串中逐个读取字符,并尝试将其与定义的词法规则进行匹配;

5、生成词法单元:当词法分析器匹配到一个词法规则时,它会生成相应的词法单元并返回给语法分析器。每个词法单元通常包含两部分信息:

  • 词法单元类型(token type):表示该词法单元的种类,比如关键字、标识符、运算符等;
  • 词法单元值(tokenvalue):表示该词法单元具体的取值;

6、继续扫描:词法分析器会持续从输入字符串中读取字符,并重复步骤4和步骤5,直到整个查询字符串被完全解析为一系列词法单元;

7、返回词法单元序列:当整个查询字符串都被解析后,词法分析器将返回一个包含所有词法单元的序列给语法分析器,供后续的语法分析处理;

2.2 Flex 文件代码结构

Flex文件代码如下:

%option noyywrap
%{
definition
%}

%%
rules
%%
Code

(1)%option 指定 flex 扫描时的一些特性。yywrap 通常在多文件扫描时定义使用。常用的一些选项有:

  • Noyywrap:告诉flex不使用yywrap函数;
  • yylineno:会告诉flex生成一个名为yylineno的整型变量来保存当前的行号;
  • case-insensitive 正则表达式规则大小写无关;

(2)definitio部分为定义部分,包括引入头文件,变量声明,函数声明,注释等,这部分会被原样拷贝到输出的.c文件中。

(3)rules部分定义词法规则,使用正则表达式定义词法,后面{}内则是扫描到对应词法时的动作代码;“|”是一个特殊符号,表示下一个模式应用相同的动作;正则表达式后面不指定动作,则相应的模式会被忽略。

(4)code部分为C语言的代码。yylex为flex的函数,使用yylex开始扫描。

2.3 Flex 文件常用变量

(1)yytext:yytext 是 Flex 中的一个全局字符数组,用于存储当前匹配的词法单元的文本。在词法规则中,当匹配到某个模式时,可以通过 yytext 来获取匹配的文本。

(2)yylength:yylength 是 Flex 中的一个全局整数变量,用于存储当前匹配的词法单元的长度。在词法规则中,可以通过 yylength 来获取匹配的文本的长度。

(3)yylval:yylval 是 Bison 中的一个共用联合体(union),用于在词法分析器和语法分析器之间传递值。它可以存储不同类型的值,根据需要进行定义。在词法规则中,可以通过修改 yylval 的值来传递附加信息给语法分析器。

2.4 Flex 文件具体案例

1、创建一个名为 lexer.l 的文件,其中包含词法规则;

%{
#include <stdio.h>
%}

%%
SELECT                  { printf("Keyword: SELECT\n"); }
FROM                    { printf("Keyword: FROM\n"); }
WHERE                   { printf("Keyword: WHERE\n"); }
AND                     { printf("Keyword: AND\n"); }
OR                      { printf("Keyword: OR\n"); }

[0-9]+                  { printf("Number: %s\n", yytext); }

[A-Za-z_][A-Za-z0-9_]*  { printf("Identifier: %s\n", yytext); }
[=><]+                  { printf("Operator: %s\n", yytext); }
[ \t\n]                 ; // Skip whitespace

.                       { printf("Unknown: %s\n",yytext); }
 
%%

int main() {    
    yylex();   
    return 0;
}

2、使用 flex 命令编译 lexer.l 文件,生成词法分析器代码 

(1)执行下列语句生成词法分析器代码

flex lexer.l

(2)词法分析器生成结果

lex.yy.c

(3)编译生成的词法分析器代码,生成可执行文件

gcc -o lexer lex.yy.c -lfl

(4)运行可执行文件并输入一些算术表达式进行测试

./lexer

输入:SELECT * FROM table;

(5)执行结果如下

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

说明:

  • -ll: 这是旧版本的Flex生成器(例如Flex 2.5.4)的链接选项。它指示链接器将使用名为 libl.a 或 libl.so 的库文件。在以前的版本中,Flex生成的词法分析器的默认名称是 lex.yy.c,而库文件的名称以 "l" 开头,因此使用 -ll 是一种传统的方式。
  • -lg: 这是新版本的Flex生成器(例如Flex 2.5.35)的链接选项。类似于旧版本的 -ll,它指示链接器使用名为 libg.a 或 libg.so 的库文件。这种新方式是为了避免与其他工具和库发生命名冲突。
  • -lfl: 这是一个与Flex生成的词法分析器库相关的选项。-lfl 表示链接器将使用名为 libfl.a 或 libfl.so 的库文件。这个库包含了Flex所需的运行时支持函数。

注意:

        如果 flex 词法分析器对 .l 进行编译时报错:

        /opt/h/devtoolset-11/root/usr/ibexec/gcex86.64-redhat-linux/11/ld: cannot find -lfn

解决方案:

        该错误表明链接器无法找到名为 -if 的库文件。这通常是因为在您的系统上缺少libfl库,或者库文件的路径未正确配置。要解决这个问题,您可以尝试以下步骤:

1、确认库是否已安装:首先,请确保您的系统上已安装了libfl库。您可以尝试使用包管理器来安装它。在基于Red Hat的系统中,您可能需要执行类似于以下的命令:

yum install flex-devel

2、检查库文件路径:如果库已安装,但链接器仍然找不到它,可能是因为库文件的路径未正确配置。您可以尝试手动指定库文件的路径。例如,假设libfl库文件位于/usr/lib64目录下,您可以使用以下方式链接:

gcc -o my program lex.yy.c -L/usr/lib64 -1f1

3、更新库文件缓存:如果您最近安装了libfl库,但链接器仍然找不到它,您可能需要更新库文件缓存。运行以下命令以更新库文件缓存:

sudo ldconfig

 3.  Bison语法分析器

        Bison(GNU Bison)是一个用于生成语法分析器的工具,它基于Yacc(Yet Another Compiler Compiler)工具的扩展版本。Bison接受一个上下文无关文法作为输入,并生成一个LALR(1)(Look-Ahead LR(1))语法分析器。

3.1 Bison原理

(1)定义文法:使用Bison的语法来定义上下文无关文法。这个文法描述了待分析的语言的语法规则。

(2)生成解析器代码:运行Bison工具,将定义的文法作为输入。Bison会根据文法生成一个解析器的C源代码文件。

(3)编译解析器:使用C编译器将生成的C源代码文件编译成可执行的解析器。

(4)运行解析器:将待分析的输入传递给生成的解析器,解析器会按照定义的文法进行分析。

(5)语法分析:解析器使用LALR(1)算法进行语法分析。它通过读取输入符号流并使用状态转换表来推导出输入的符号序列是否符合文法规则。

(6)语法错误处理:如果输入的符号序列不符合文法规则,解析器会检测到语法错误。此时,Bison会调用yyerror函数进行错误处理,你可以自定义yyerror函数来处理错误。

(7)语义动作:在解析过程中,可以在文法规则中指定语义动作。语义动作是在解析过程中执行的代码片段,用于构建抽象语法树、执行语义动作等。

(8)生成抽象语法树:通过语义动作,解析器可以构建抽象语法树(AST),表示输入符合文法规则的结构。

(9)后续处理:一旦解析器完成语法分析并生成了抽象语法树,你可以根据需要进行进一步的语义分析、代码生成等后续处理。

3.2 Bison文件代码结构

  Bison文件代码如下:

%{
// C 代码和头文件的声明
#include <stdio.h>
// 在这里可以定义全局变量和函数等
%}
// Bison 的选项部分
%option verbose   		// 控制 Bison 解析器的详细输出

// Bison 的声明部分    
%token NAME       	    // 定义终结符或标记的名称
%token NUMBER

%left ‘+’ ‘-‘           // 定义运算符的优先级和结合性
%left ‘*’ ‘/’

%{
// 在这里可以编写更多的 C 代码
%}// Bison 的规则部分

%%
// 语法规则的定义
expression : expression '+' expression           
            | expression '-' expression           
            | expression '*' expression           
            | expression '/' expression           
            | '(' expression ')'           
            | NUMBER           ;
// 更多的语法规则...
%%

// C 代码部分(选项中的 %{ ... %} 和规则部分中的 %% 之间的部分)
// 在这里可以编写与语法规则相关的 C 代码
int main() {    
    yyparse();  // 调用 Bison 生成的解析函数    
    return 0;
}

  bison文件的书写格式与flex文件的书写格式基本一致,只是规则的定义语法不同。

3.3 Bison文件常用特殊符号

(1)“文法”

        “文法”是一组规则,用于描述编程语言或语言的语法结构。这些规则定义了语言的句法(syntax),即哪些组合是有效的、合法的语句和表达式,以及它们如何组合在一起。文法规则使用产生式(productions)的形式来表示,其中包含终结符(terminals)和非终结符(non-terminals)的组合。

        文法规则在 Bison 文件中是使用 BNF(巴科斯-诺尔范式)或 EBNF(扩展巴科斯-诺尔范式)的形式表示的。BNF 是一种形式化的表示方法,用于定义上下文无关文法(Context-Free Grammar),这些文法用于指定编程语言的语法规则。

expression : expression '+' term
          		| expression '-' term
           		| term;

(2) %start

        %start 指令用于指定文法的起始非终结符。起始非终结符是语法分析的入口点,也就是从哪个语法规则开始构建解析树或语法分析树。

%start program

%%

statements : statement

                   | statements statement;

statement : assignment

                   | if_statement

                   | while_statement

                   | /* ... other statement types ... */ ;

        %start program 指定了起始非终结符为 program。这意味着语法分析将从 program 规则开始,逐步展开其他非终结符,最终构建解析树。在实际语法规则中,起始非终结符的选择取决于您想要分析的语言的语法结构。

(3)$

        在语法规则中,$ 用于引用当前产生式的右侧的符号或值。例如,在产生式的右侧,$1 表示该产生式右侧的第一个元素(终结符或非终结符),$2表示第二个元素,依此类推。这些引用用于将产生式右侧的值传递给产生式左侧。注意:生产式的起始下标为1。

(4)$$

        在语法规则中,$$ 用于引用当前产生式的结果。当 Bison 解析器完成一个产生式的分析并计算出其结果时,该结果会被赋值给 $$。这通常用于构建解析树的节点或为更高层次的语法规则提供结果。

(5)|

        | 用于表示多个产生式之间的选择。它在上下文无关文法中用于定义非终结符的不同产生式形式。每个产生式通过竖线分隔,表示它们是该非终结符的可能形式之一。

3.4 bison文件具体案例

1、创建一个名为parser.l的文件,其中包含词法规则;

%{
#include <stdio.h>
#include <stdlib.h>
%}

//定义终结符
%token SELECT INSERT UPDATE DELETE FROM WHERE 
%token INTO VALUES SET
%token ID INT STRING

%%

//定义规则
	
statement: SELECT columns FROM table WHERE condition ';'
         	| INSERT INTO table '(' columns ')' VALUES '(' values ')' ';'
         	| UPDATE table SET assignments WHERE condition ';'
         	| DELETE FROM table WHERE condition ';'
         	;

columns: ID
       	| columns ',' ID
       	;

table: ID
     	;

assignments: ID '=' value
           	| assignments ',' ID '=' value
           	;

values: value
      	| values ',' value
      	;

value: INT
     	| STRING
     	;

condition: ID '=' value
         	;

%%

int main() {
    	yyparse();
    	return 0;
}

int yyerror(const char *s) {
    	printf("Error: %s\n", s);
    	return 0;
}

2、使用 bison 命令编译 lexer.l 文件

bison -d parser.y

        这将生成 parser.tab.c 和 parser.tab.h 两个文件。接下来,你可以将这些文件与你的编译器项目一起编译,并链接到你的代码中。

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

4.  SQL 解析器完整 Demo 演示

4.1 查询语句
SELECT cloumn FROM table WHERE id=2;

查询语句语法分析结果如下所示: 

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

 4.2 插入语句
INSERT INTO table VALUES(1);

插入语句语法分析结果如下所示:  

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

 4.3 更新语句
UPDATE table SET name='LIST';

更新语句语法分析结果如下所示:   

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

 4.4 删除语句
DELETE FROM table WHERE phone LIKE '%9';

删除语句语法分析结果如下所示:    

SQL 语句解析过程详解(附带完整demo),CentOS,Linux 操作系统,centos,mysql,linux,数据库,adb

5. SQL解析器代码 

5.1 SQL解析器主函数
#include <stdio.h>
#include <stdlib.h>

extern FILE* yyin;
extern int yyparse();

int main() {
    yyin = fopen("input.sql", "r"); // 打开待解析的 SQL 文件

    if (yyin == NULL) {
        fprintf(stderr, "Failed to open input file.\n");
        return 1;
    }

    //yypase()函数是bison自动生成的函数,是语法分析的入口函数,会自动调用flex中的yylex()函数
    /*  返回值为 0:表示语法分析成功完成。
        返回值为非零:表示语法分析过程中发生了错误。*/
    if (yyparse() != 0) {
        fprintf(stderr, "Parsing failed.\n");
        return 1;
    }

    fclose(yyin);
    return 0;
}
5.2 SQL解析器完整代码

完整代码:https://download.csdn.net/download/weixin_47156401/88265367?spm=1001.2014.3001.5503

说明:资源里面附带测试案例,非常适合初学者学习! 

如果想了解抽象语法树的生成编译原理中对应解析器部分,见下面链接:

https://mp.csdn.net/mp_blog/creation/editor/132252320文章来源地址https://www.toymoban.com/news/detail-688211.html

到了这里,关于SQL 语句解析过程详解(附带完整demo)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • zabbix缺乏create.sql.gz语句包怎么处理?附带详细处理方法和讲解

    下载作者整理来的官方源码包里找来的sql语句包,并导入 这个报错的问题,归根结底就是因为安装的数据库和yum源的mysql数据库的yum源不一致导致的 解决方法: 1.查看自己的数据库版本 2.打开系统的yum源文件 3.根据你的mysql数据库版本打开不同的yum配置 ps:例如你是5.7版本你就

    2024年01月19日
    浏览(29)
  • 【SQL Server】数据库开发指南(七)MS-SQL存储过程全面解析:种类、优点和创建方法详解

    本系列博文还在更新中,收录在专栏:#MS-SQL Server 专栏中。 本系列文章列表如下: 【SQL Server】 Linux 运维下对 SQL Server 进行安装、升级、回滚、卸载操作 【SQL Server】数据库开发指南(一)数据库设计的核心概念和基本步骤 【SQL Server】数据库开发指南(二)MSSQL数据库开发对

    2024年02月07日
    浏览(50)
  • 使用SQL语句创建存储过程

    本篇文章是记录学校学习 SQL server 中知识,可用于复习资料. 定义: 存储过程 是为了完成特定功能的SQL语句集合,存储在数据库中,用户通过指定 存储过程 的名称并给出参数来执行。 优点: 1、方便修改。   因为 存储过程 是存储在数据库中的,如果需要涉及到修改SQL语句

    2024年02月08日
    浏览(27)
  • MySQL—一条查询SQL语句的完整执行流程

    表结构和数据如下: 我们分析的sql语句如下: 大体来说,MySQL可以分为Server层和存储引擎层两部分: Server层 包括:连接器、查询缓存、分析器、优化器、执行器等 涵盖MySQL的大多数核心服务功能 所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在

    2024年04月28日
    浏览(47)
  • 4.2.1 SQL语句、索引、视图、存储过程

    怎么执行一条select语句 1.连接器 接收连接-》管理连接-》校验用户信息 2.查询缓存 kv存储,命中直接返回,否则继续执行 8.0已经删除 3.分析器 词法句法分析生成语法树 4.优化器 指定执行计划,选择查询成本最小的计划 5.执行器 根据执行计划,从存储引擎获取数据,并返回客

    2024年02月06日
    浏览(33)
  • MySQL内部机制:SQL语句的执行过程浅析

    目录 1. 连接与认证 2. 解析与优化 3. 查询缓存 4. 打开表和读取数据 5. 执行 6. 返回结果 7. 日志记录 8. 关闭连接 当我们在MySQL中执行一个SQL语句时,背后发生了一系列的操作和步骤。下面是一个简化的概述,描述了SQL语句在MySQL中的执行过程或原理: 客户端(如应用程序或命

    2024年03月12日
    浏览(40)
  • WPF入门实例 WPF完整例子 WPF DEMO WPF学习完整例子 WPF实战例子 WPF sql实例应用 WPF资料源码

    WPF 和 WinForms 都是用于创建 Windows 桌面应用程序的开发框架,它们有一些相似之处,但也有很多不同之处。 在开发速度方面,这取决于具体情况。如果您熟悉 WinForms 开发并且正在开发简单的界面应用程序,则可能会比使用 WPF 更快速地完成任务。然而,在设计和实现复杂的用

    2024年02月06日
    浏览(35)
  • sql语句练习50题(含解析)

    通过score表自连接后,过滤出每位学生 “01”课程分数和 “02”课程分数的一条记录,最后将01”课程分数大于 “02”课程分数记录筛选出来 与第1题思路一样 此题比较简单,使用分组即可。需要注意下在mysql中使用group by后,select后出现的字段要么是 分组的字段 要么是 聚集函

    2023年04月08日
    浏览(23)
  • 执行SQL语句&存储过程的真正【神器】,不用ORM的全选它,比dapper好

    支持.Net Core(2.0及以上)与.Net Framework(4.0及以上)(注意:升级了,可以覆盖到早期的.Net Framework4.0了,而且修复了数据库字段为Null时报错的问题,无敌了!!) 此工具在IDataAccess接口中提供。 已被.Net圈内多家大厂采用! IDataAccess所在的命名空间是:DeveloperSharp.Framework.QueryEngine(

    2024年02月08日
    浏览(24)
  • SQL 50 题(MySQL 版,包括建库建表、插入数据等完整过程,适合复习 SQL 知识点)

    ① 本文整理了经典的 50 道 SQL 题目,文本分为 建库建表 、 插入数据 以及 SQL 50 题 这三个部分。 ② 这些题目许多博主也整理过,但本人不太了解这些题目具体的出处。第一次了解这些题目是本科期间老师出的题目。如果有网友知道这些题目的最原始出处,可以在评论评论区

    2024年02月07日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包