使用flex和bison实现的sql引擎解析
由于老师要求,最近在做oceanbase存储过程的实现,在oceanbase 0.4以前是不支持存储过程的。实现的主要步骤主要包括 1、语法解析 2、词法解析 3、具体执行语法树的步骤 现在先来说说语法解析吧,在这一块主要是使用的flex( 词法分析器生成工具) 和bison(语
由于老师要求,最近在做oceanbase存储过程的实现,在oceanbase 0.4以前是不支持存储过程的。实现的主要步骤主要包括
1、语法解析
2、词法解析
3、具体执行语法树的步骤
现在先来说说语法解析吧,在这一块主要是使用的flex( 词法分析器生成工具) 和bison(语法分析器生成器) 这两个是对用户输入的存储过程语句进行解析的
来具体说说该怎么实现对sql语句的分析吧
1、首先建立一个lex的文件
%option noyywrap nodefault yylineno case-insensitive %{ #include "prosql.tab.hpp" #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <malloc.h> //YYSTYPE yylval; int oldstate; extern "C" int yylex(); //extern "C" int yyparse(); extern "C" void yyerror(const char *s, ...); extern char globalInputText[10000]; extern int readInputForLexer( char *buffer, int *numBytesRead, int maxBytesToRead ); #undef YY_INPUT #define YY_INPUT(b,r,s) readInputForLexer(b,&r,s) %} %x COMMENT %% CREATE { return CREATE; } PROCEDURE { return PROCEDURE; } SQL { return SQL; } DECLARE { return DECLARE; } SET { return SET; } BEGIN { return BEGINT; } END { return END; } INT { return INT; } VARCHAR { return VARCHAR; } DATE { return DATE; } TIME { return TIME; } DOUBLE { return DOUBLE; } IF { return IF; } THEN { return THEN; } ELSE { return ELSE; } ENDIF { return ENDIF; } FOR { return FOR; } WHEN { return WHEN; } WHILE { return WHILE; } [0-9]+ { yylval.strval = strdup(yytext);/*printf("number=%s\n",yylval.strval);*/ return INTNUM; }/*number*/ [0-9]+"."[0-9]* | "."[0-9]+ | [0-9]+E[-+]?[0-9]+ | [0-9]+"."[0-9]*E[-+]?[0-9]+ | "."[0-9]*E[-+]?[0-9]+ { yylval.strval = strdup(yytext);/*printf("float=%s\n",yylval.strval);*/ return APPROXNUM; }/*double*/ TRUE { yylval.strval = "1";/*printf("bool=%s\n",yylval.strval);*/ return BOOL; }/*bool*/ FALSE { yylval.strval = "0";/*printf("bool=%s\n",yylval.strval);*/ return BOOL; }/*bool*/ '(\\.|''|[^'\n])*' | \"(\\.|\"\"|[^"\n])*\" { char *temp = strdup(yytext); yylval.strval = strdup(yytext); //GetCorrectString(yylval.strval, temp); /*printf("string=%s\n",yylval.strval);*/ return STRING; }/*string*/ '(\\.|[^'\n])*$ { yyerror("Unterminated string %s", yytext); } \"(\\.|[^"\n])*$ { yyerror("Unterminated string %s", yytext); } X'[0-9A-F]+' | 0X[0-9A-F]+ { yylval.strval = strdup(yytext); return STRING; } 0B[01]+ | B'[01]+' { yylval.strval = strdup(yytext); return STRING; } [-+&~|^/%*(),.;!] { return yytext[0]; } "&&" { return ANDOP; } "||" { return OR; } "<" { yylval.subtok = 1; return COMPARISON; } ">" { yylval.subtok = 2; return COMPARISON; } "!=" | "<>" { yylval.subtok = 3; return COMPARISON; } "=" { yylval.subtok = 4; return COMPARISON; } "<=" { yylval.subtok = 5; return COMPARISON; } ">=" { yylval.subtok = 6; return COMPARISON; } "<=>" { yylval.subtok = 12; return COMPARISON; } "<<" { yylval.subtok = 1; return SHIFT; } ">>" { yylval.subtok = 2; return SHIFT; } [A-Za-z][A-Za-z0-9_]* { yylval.strval = strdup(yytext); /*printf("name 1=%s\n",yylval.strval);*/ return NAME; } `[^`/\\.\n]+` { yylval.strval = strdup(yytext+1); /*printf("name 2=%s\n",yylval.strval);*/ yylval.strval[yyleng-2] = 0; return NAME; } `[^`\n]*$ { yyerror("unterminated quoted name %s", yytext); } @[0-9a-z_.$]+ | @\"[^"\n]+\" | @`[^`\n]+` | @'[^'\n]+' { yylval.strval = strdup(yytext+1); return USERVAR; } @\"[^"\n]*$ { yyerror("unterminated quoted user variable %s", yytext); } @`[^`\n]*$ { yyerror("unterminated quoted user variable %s", yytext); } @'[^'\n]*$ { yyerror("unterminated quoted user variable %s", yytext); } ":=" { return ASSIGN; } #.* ; "--"[ \t].* ; "/*" { oldstate = YY_START; BEGIN COMMENT; } <COMMENT>"*/" { BEGIN oldstate; } <COMMENT>.|\n ; <COMMENT><<EOF>> { yyerror("unclosed comment"); } [ \t\n] /* white space */ . { yyerror("mystery character '%c'", *yytext); } %% 这一部分呢就是对 每个我们自定义的满足正则的识别
接下来是对词的语法识别
%{ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <stdio.h> #include <malloc.h> char * parsetreeroot=NULL; extern "C" int yylex(); extern "C" int yyparse(); extern "C" void yyerror(const char *s, ...); char globalInputText[10000]; int globalReadOffset; int readInputForLexer( char *buffer, int *numBytesRead, int maxBytesToRead ); char * mystrcat(char *s1,char *s2) { char *p1=(char *)malloc(strlen(s1)+strlen(s2)+1); strcpy(p1,s1); strcat(p1,s2); return p1; } %} %locations %union { int intval; double floatval; char *strval; int subtok; } %token <strval> NAME %token <strval> STRING %token <strval> INTNUM %token <strval> BOOL %token <strval> APPROXNUM %token <strval> USERVAR %type <strval> stmt_root create_stmt para_list definition data_type pro_block pro_parameters declare_list set_list %type <strval> assign_var pro_body pro_stmt_list sql_stmt expr %right ASSIGN %left OR %left XOR %left ANDOP %left NOT '!' %left BETWEEN %left <subtok> COMPARISON /* = <> < > <= >= <=> */ %left '|' %left '&' %left <subtok> SHIFT /* << >> */ %left '+' '-' %left '*' '/' '%' MOD %left '^' %token CREATE %token PROCEDURE %token PRONAME %token DECLARE %token SET %token BEGINT %token END %token SQL %token INT %token VARCHAR %token DATE %token TIME %token DOUBLE %token IF %token NOT %token EXISTS %token THEN %token ELSE %token ENDIF %token FOR %token WHEN %token WHILE %start stmt_root %% stmt_root: create_stmt pro_block { $$=mystrcat($1,$2); parsetreeroot=$$;} ; create_stmt: CREATE PROCEDURE NAME '(' para_list ')' { char *temp=mystrcat("create procedure ",$3); temp=mystrcat(temp,"("); temp=mystrcat(temp,$5); $$=mystrcat(temp,")(create)\n"); } ; /* opt_if_not_exists: { $$ = 0; } | IF NOT EXISTS { $$ = 1; } ; */ para_list: definition { $$=$1; } |definition ',' para_list { char *temp=mystrcat($1,","); $$=mystrcat(temp,$3); } ; definition: USERVAR data_type { char *temp=mystrcat($1," "); $$=mystrcat(temp,$2); } ; data_type: DATE {$$="date"; } | TIME {$$="time"; } | VARCHAR '(' INTNUM ')' {$$="varchar"; } | INT {$$="int"; } | DOUBLE {$$="double"; } ; pro_block: BEGINT pro_parameters pro_body END { char *temp=mystrcat("begin\n",$2); temp=mystrcat(temp,""); temp=mystrcat(temp,$3); $$=mystrcat(temp,"end"); //printf("pro_body %s\n",$3); } ; pro_parameters: declare_list ';' { $$=mystrcat($1,";(declare)\n");} |pro_parameters declare_list ';' { char *temp=mystrcat($1,$2); $$=mystrcat(temp,";(declare)\n"); } |pro_parameters set_list ';' { char *temp=mystrcat($1,$2); $$=mystrcat(temp,";(set)\n"); } ; declare_list: |DECLARE definition { $$=mystrcat("declare ",$2); } |declare_list ',' definition { char *temp=mystrcat($1,","); $$=mystrcat(temp,$3); } ; set_list: |SET assign_var { $$=mystrcat("set ",$2); } | set_list ',' assign_var { char *temp=mystrcat($1,","); $$=mystrcat(temp,$3); } ; assign_var : USERVAR COMPARISON expr { char *temp=mystrcat($1,"="); $$=mystrcat(temp,$3); } ; expr: NAME { $$=$1;} | STRING { $$=$1;} | INTNUM { $$=$1;} | APPROXNUM { $$=$1;} | BOOL { $$=$1;} ; pro_body : pro_stmt_list { $$=$1; } ; pro_stmt_list: sql_stmt {$$=$1; } |pro_stmt_list sql_stmt { $$=mystrcat($1,$2); } ; sql_stmt: |SQL NAME ';' { $$=mystrcat($2,";(sql)\n");} ; %% /* int main(int argc, char* argv[]) { yyparse(); }*/ int readInputForLexer( char *buffer, int *numBytesRead, int maxBytesToRead ) { int numBytesToRead = maxBytesToRead; int bytesRemaining = strlen(globalInputText)-globalReadOffset; int i; if ( numBytesToRead > bytesRemaining ) { numBytesToRead = bytesRemaining; } for ( i = 0; i < numBytesToRead; i++ ) { buffer[i] = globalInputText[globalReadOffset+i]; } *numBytesRead = numBytesToRead; globalReadOffset += numBytesToRead; return 0; } void yyerror(const char *s, ...) { fprintf(stderr, "error: %s\n", s); } void zzerror(const char *s, ...) { extern int yylineno; va_list ap; va_start(ap, s); fprintf(stderr, "%d: error: ", yylineno); vfprintf(stderr, s, ap); fprintf(stderr, "\n"); } int yywrap(void) { return 1; } char* getsql() { return parsetreeroot; } 这部分就是对上一个识别出来的词 进行顺序上的确定,构成一个完整的语法
这些需要在linux环境下进行调试
bison -d 文件名
flex 文件名

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

HQL和SQL在Hibernate框架中进行比较:HQL(1.面向对象语法,2.数据库无关的查询,3.类型安全),而SQL直接操作数据库(1.与数据库无关的标准,2.可执行复杂查询和数据操作)。

网易邮箱,作为中国网民广泛使用的一种电子邮箱,一直以来以其稳定、高效的服务赢得了用户的信赖。而网易邮箱大师,则是专为手机用户打造的邮箱软件,它极大地简化了邮件的收发流程,让我们的邮件处理变得更加便捷。那么网易邮箱大师该如何使用,具体又有哪些功能呢,下文中本站小编将为大家带来详细的内容介绍,希望能帮助到大家!首先,您可以在手机应用商店搜索并下载网易邮箱大师应用。在应用宝或百度手机助手中搜索“网易邮箱大师”,然后按照提示进行安装即可。下载安装完成后,我们打开网易邮箱账号并进行登录,登录界面如下图所示

在如今云存储已经成为我们日常生活和工作中不可或缺的一部分。百度网盘作为国内领先的云存储服务之一,凭借其强大的存储功能、高效的传输速度以及便捷的操作体验,赢得了广大用户的青睐。而且无论你是想要备份重要文件、分享资料,还是在线观看视频、听取音乐,百度网盘都能满足你的需求。但是很多用户们可能对百度网盘app的具体使用方法还不了解,那么这篇教程就将为大家详细介绍百度网盘app如何使用,还有疑惑的用户们就快来跟着本文详细了解一下吧!百度云网盘怎么用:一、安装首先,下载并安装百度云软件时,请选择自定义安装选

华为手机如何实现双微信登录?随着社交媒体的兴起,微信已经成为人们日常生活中不可或缺的沟通工具之一。然而,许多人可能会遇到一个问题:在同一部手机上同时登录多个微信账号。对于华为手机用户来说,实现双微信登录并不困难,本文将介绍华为手机如何实现双微信登录的方法。首先,华为手机自带的EMUI系统提供了一个很便利的功能——应用双开。通过应用双开功能,用户可以在手机上同

MetaMask(中文也叫小狐狸钱包)是一款免费的、广受好评的加密钱包软件。目前,BTCC已支持绑定MetaMask钱包,绑定后可使用MetaMask钱包进行快速登入,储值、买币等,且首次绑定还可获得20USDT体验金。在BTCCMetaMask钱包教学中,我们将详细介绍如何注册和使用MetaMask,以及如何在BTCC绑定并使用小狐狸钱包。MetaMask钱包是什么?MetaMask小狐狸钱包拥有超过3,000万用户,是当今最受欢迎的加密货币钱包之一。它可免费使用,可作为扩充功能安装在网络

编程语言PHP是一种用于Web开发的强大工具,能够支持多种不同的编程逻辑和算法。其中,实现斐波那契数列是一个常见且经典的编程问题。在这篇文章中,将介绍如何使用PHP编程语言来实现斐波那契数列的方法,并附上具体的代码示例。斐波那契数列是一个数学上的序列,其定义如下:数列的第一个和第二个元素为1,从第三个元素开始,每个元素的值等于前两个元素的和。数列的前几个元

小米汽车软件提供远程车控功能,让用户可以通过手机或电脑远程控制车辆,例如开关车辆的门窗、启动引擎、控制车辆的空调和音响等,下文就是这个软件的使用及内容,一起了解下吧。小米汽车app功能及使用方法大全1、小米汽车app在3月25日上线苹果AppStore,现在安卓手机的应用商店中也可以下载了;购车:了解小米汽车核心亮点和技术参数,可预约试驾、配置订购您的小米汽车,支持在线处理提车待办事项。3、社区:了解小米汽车品牌资讯,交流用车体验,分享精彩车生活;4、车控:手机就是遥控器,远程控制,实时安防,轻

如何在华为手机上实现微信分身功能随着社交软件的普及和人们对隐私安全的日益重视,微信分身功能逐渐成为人们关注的焦点。微信分身功能可以帮助用户在同一台手机上同时登录多个微信账号,方便管理和使用。在华为手机上实现微信分身功能并不困难,只需要按照以下步骤操作即可。第一步:确保手机系统版本和微信版本符合要求首先,确保你的华为手机系统版本已更新到最新版本,以及微信App
