打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
用Lex和Yacc做一个简单的SQL解释器
前段时间做了一个简单的内存数据库,需要提供点简单的SQL支持,在参考了《Lex与Yacc》和网上的相关资料后,以《Lex与Yacc》中的SQL解释器为基础,做了修改,最后生成了一个简单的SQL解释器。
这个SQL解释器由于本身内存数据库提供的功能限制,提供的SQL也有很多的限制:
1、select不支持按字段取值,一次查询获取所有字段
2、查询条件之间的关系只支持AND
3、UPDATE一次只更新一个字段
4、不支持函数
在SQL解释器中,关键是我们要构建我们的语法结构,也就是最终通过SQL解释器要生成的一个程序能识别的结构。负责的SQL支持对应负责的负责的结构,因为我们支持的SQL简单,所以相对应的结构也就很简单了。
主题程序由3个文件组成,sql_plan.h parser_lex.l parser_yacc.y。其中,sql_plan.h是语法结构的定义,parser_lex.l是词法解释和主程序入口部分,parser_yacc.y是语法解释部分。
#ifndef __SQL_DEFINE__
#define __SQL_DEFINE__
#define NAME_SIZE   24
#define MAX_BUFFER_SIZE  8192
typedef enum
{
SQL_SELECT = 1,
SQL_INSERT,
SQL_UPDATE,
SQL_DELETE,
SQL_COUNT_ALL
}sql_action;
typedef struct{
char field_name[NAME_SIZE];
char field_value[256];
}FieldNameValue;
typedef struct{
int list_len;
FieldNameValue fnv_par[5];
}FieldNameValue_List;
typedef struct{
int    action;
char tab_name[256];
FieldNameValue_List w_fnv_list;
char u_field_name[256];
char u_field_value[256];
int pos;
char buffer[MAX_BUFFER_SIZE];
}SQL_PLAN;
extern SQL_PLAN sql_plan;
#endif
sql_plan.h
parser_lex.l%{
#include "parser_yacc.h"
#include "sql_define.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int lineno = 1;
void yyerror(char *s);
void TrimString(char *str)
{
char *copied, *tail = NULL;
if ( str == NULL )
return;
for( copied = str; *str; str++ )
{
if ( *str != ' ' && *str != '\t' && *str != '\n' &&
*str != '\r' && *str != '\'' && *str != ';')
{
*copied++ = *str;
tail = copied;
}
else
{
if ( tail )
*copied++ = *str;
}
}
if ( tail )
*tail = 0;
else
*copied = 0;
return;
}
char *_xInput;
int _xLen = 0;
int myinput(char *buff,int max)
{
if(!_xLen) return 0;
if(max > _xLen) max = _xLen   ;
memcpy(buff,_xInput,max);
_xInput += max;
_xLen -= max;
return   max;
}
#define YY_INPUT(b, r, m) (r = myinput(b, m))
%}
%%
and        { return AND; }
CHAR(ACTER)?    { return CHARACTER; }
CLOSE        { return CLOSE; }
CREATE        { return CREATE; }
CURRENT        { return CURRENT; }
CURSOR        { return CURSOR; }
count        { return COUNT; }
DECLARE        { return DECLARE; }
delete        { return DELETE; }
DOUBLE        { return DOUBLE; }
FETCH        { return FETCH; }
FLOAT        { return FLOAT; }
FOR        { return FOR; }
from        { return FROM; }
insert        { return INSERT; }
INT(EGER)?    { return INTEGER; }
into        { return INTO; }
NOT        { return NOT; }
NULL        { return NULLX; }
NUMERIC        { return NUMERIC; }
OF        { return OF; }
OPEN        { return OPEN; }
OR        { return OR; }
REAL        { return REAL; }
select        { return SELECT; }
set        { return SET; }
table        { return TABLE; }
update        { return UPDATE; }
values        { return VALUES; }
where        { return WHERE; }
/* punctuation */
"=" { return L_EQ; }
"<>"     |
"<"    |
">"    |
"<="    |
">="        { return COMPARISON; }
[-+*/:(),.;]    { return yytext[0]; }
/* names */
[A-Za-z][A-Za-z0-9_]*    { strcpy(yylval.nameval,yytext); return NAME; }
/* numbers */
-?[0-9]+    { yylval.intval = atoi(yytext); return INTNUM; }
[0-9]+"."[0-9]* { yylval.floatval = atof(yytext); return FLOATNUM; }
[0-9]+[eE][+-]?[0-9]+    |
[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
"."[0-9]*[eE][+-]?[0-9]+    { return APPROXNUM; }
/* strings */
'[^'\n]*'    { TrimString(yytext); strcpy(yylval.strval,yytext); return STRING; }
'[^\'\n]*$    { yyerror("Unterminated string"); }
\n        lineno++;
[ \t\r]+    ;    /* white space */
"--".*$        ;    /* comment */
%%
void yyerror(char *s)
{
printf("%d: %s at %s\n", lineno, s, yytext);
}
int yywrap()    {return 1;}
main(int argc, char **argv)
{
int pos;
int ret;
char *buffer;
char prompt_buffer[MAX_BUFFER_SIZE];
char last_prompt_buffer[MAX_BUFFER_SIZE];
int count;
while(1)
{
printf("mdbsql>>");
fgets(prompt_buffer, sizeof(prompt_buffer), stdin);
_xInput = prompt_buffer;
_xLen = strlen(prompt_buffer);
if (prompt_buffer[0]=='\\')
{
strcpy(prompt_buffer, last_prompt_buffer);
_xLen = strlen(prompt_buffer);
}
if (strncmp(prompt_buffer, "quit", 4)==0 ||
strncmp(prompt_buffer, "exit", 4)==0
)
{
break;
}
memset(&sql_plan, 0, sizeof(sql_plan) );
strcpy(last_prompt_buffer, prompt_buffer);
if(!yyparse())
{
if (sql_plan.action == SQL_SELECT)
{
printf("%d records are retrieved\n", count);
}
else if (sql_plan.action == SQL_DELETE)
{
printf("%d records are deleted\n", ret);
}
else if (sql_plan.action == SQL_UPDATE)
{
printf("%d records are updated\n", ret);
}
else if (sql_plan.action == SQL_INSERT)
{
if (ret>0) printf("1 record is inserted\n");
}
else if (sql_plan.action == SQL_COUNT_ALL)
{
if (ret>0) printf("1 record is retrieved\n");
}
}
else
{
printf("SQL parse failed\n");
}
}
}
parser_yacc.y%{
#include "parser_yacc.h"
#include "sql_define.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int lineno = 1;
void yyerror(char *s);
void TrimString(char *str)
{
char *copied, *tail = NULL;
if ( str == NULL )
return;
for( copied = str; *str; str++ )
{
if ( *str != ' ' && *str != '\t' && *str != '\n' &&
*str != '\r' && *str != '\'' && *str != ';')
{
*copied++ = *str;
tail = copied;
}
else
{
if ( tail )
*copied++ = *str;
}
}
if ( tail )
*tail = 0;
else
*copied = 0;
return;
}
char *_xInput;
int _xLen = 0;
int myinput(char *buff,int max)
{
if(!_xLen) return 0;
if(max > _xLen) max = _xLen   ;
memcpy(buff,_xInput,max);
_xInput += max;
_xLen -= max;
return   max;
}
#define YY_INPUT(b, r, m) (r = myinput(b, m))
%}
%%
and        { return AND; }
CHAR(ACTER)?    { return CHARACTER; }
CLOSE        { return CLOSE; }
CREATE        { return CREATE; }
CURRENT        { return CURRENT; }
CURSOR        { return CURSOR; }
count        { return COUNT; }
DECLARE        { return DECLARE; }
delete        { return DELETE; }
DOUBLE        { return DOUBLE; }
FETCH        { return FETCH; }
FLOAT        { return FLOAT; }
FOR        { return FOR; }
from        { return FROM; }
insert        { return INSERT; }
INT(EGER)?    { return INTEGER; }
into        { return INTO; }
NOT        { return NOT; }
NULL        { return NULLX; }
NUMERIC        { return NUMERIC; }
OF        { return OF; }
OPEN        { return OPEN; }
OR        { return OR; }
REAL        { return REAL; }
select        { return SELECT; }
set        { return SET; }
table        { return TABLE; }
update        { return UPDATE; }
values        { return VALUES; }
where        { return WHERE; }
/* punctuation */
"=" { return L_EQ; }
"<>"     |
"<"    |
">"    |
"<="    |
">="        { return COMPARISON; }
[-+*/:(),.;]    { return yytext[0]; }
/* names */
[A-Za-z][A-Za-z0-9_]*    { strcpy(yylval.nameval,yytext); return NAME; }
/* numbers */
-?[0-9]+    { yylval.intval = atoi(yytext); return INTNUM; }
[0-9]+"."[0-9]* { yylval.floatval = atof(yytext); return FLOATNUM; }
[0-9]+[eE][+-]?[0-9]+    |
[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
"."[0-9]*[eE][+-]?[0-9]+    { return APPROXNUM; }
/* strings */
'[^'\n]*'    { TrimString(yytext); strcpy(yylval.strval,yytext); return STRING; }
'[^\'\n]*$    { yyerror("Unterminated string"); }
\n        lineno++;
[ \t\r]+    ;    /* white space */
"--".*$        ;    /* comment */
%%
void yyerror(char *s)
{
printf("%d: %s at %s\n", lineno, s, yytext);
}
int yywrap()    {return 1;}
main(int argc, char **argv)
{
int pos;
int ret;
char *buffer;
char prompt_buffer[MAX_BUFFER_SIZE];
char last_prompt_buffer[MAX_BUFFER_SIZE];
int count;
while(1)
{
printf("mdbsql>>");
fgets(prompt_buffer, sizeof(prompt_buffer), stdin);
_xInput = prompt_buffer;
_xLen = strlen(prompt_buffer);
if (prompt_buffer[0]=='\\')
{
strcpy(prompt_buffer, last_prompt_buffer);
_xLen = strlen(prompt_buffer);
}
if (strncmp(prompt_buffer, "quit", 4)==0 ||
strncmp(prompt_buffer, "exit", 4)==0
)
{
break;
}
memset(&sql_plan, 0, sizeof(sql_plan) );
strcpy(last_prompt_buffer, prompt_buffer);
if(!yyparse())
{
if (sql_plan.action == SQL_SELECT)
{
printf("%d records are retrieved\n", count);
}
else if (sql_plan.action == SQL_DELETE)
{
printf("%d records are deleted\n", ret);
}
else if (sql_plan.action == SQL_UPDATE)
{
printf("%d records are updated\n", ret);
}
else if (sql_plan.action == SQL_INSERT)
{
if (ret>0) printf("1 record is inserted\n");
}
else if (sql_plan.action == SQL_COUNT_ALL)
{
if (ret>0) printf("1 record is retrieved\n");
}
}
else
{
printf("SQL parse failed\n");
}
}
}
mdbsql:    parser_yacc.o parser_lex.o
gcc -o $@ parser_yacc.o parser_lex.o  -lfl
parser_yacc.c parser_yacc.h:    parser_yacc.y
yacc -vdt parser_yacc.y
mv y.tab.h parser_yacc.h
mv y.tab.c parser_yacc.c
mv y.output parser_yacc.out
parser_lex.o:    parser_yacc.h parser_lex.c
parser_lex.c : parser_lex.l
flex $<
mv lex.yy.c $*.c
Makefile
上述程序在cygwin、redhat as5下测试过
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[原创]小结了一下Parser Generator 2使用中的几个问题 — 编程爱好者论坛http://bbs.pfan.cn
用lex/yacc来解析配置文件
c语言中串比较函数
C语言字符串函数大全
基于ALSA的WAV播放和录音程序
ANTLR: 文法分析利器 (Ⅰ)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服