`
tower
  • 浏览: 244823 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用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是语法解释部分。

sql_plan.h
#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



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");
        }       
    }
}


Makefile
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




上述程序在cygwin、redhat as5下测试过

分享到:
评论
2 楼 tower 2009-01-06  
只是一个很简单的样例而已。要看完整的,实际上书上的例子也比较详细了
1 楼 yananay 2009-01-06  
不晓得sql语法的BNF?如果有现成的BNF,我想解释器会更完善一些。

相关推荐

    Lex和Yacc简明教程

    通过实践编写简单的词法分析器和语法分析器,你可以逐步掌握如何使用Lex和Yacc构建自己的编译器或解析器。 总的来说,掌握Lex和Yacc是提升编程技能和理解编译原理的重要步骤。它们提供了强大的工具,帮助开发者高效...

    lex_yacc_example

    总结起来,lex和yacc是构建编译器和解释器的重要工具,它们将复杂的文法规则和词法分析工作自动化,使得开发者能够专注于更高层次的逻辑实现。通过对"lex_yacc_example"的学习和实践,我们可以更好地理解和掌握这两...

    用yacc和lex实现SQL解释器

    在计算机科学领域,SQL(Structured Query Language,结构化查询语言)是...以上知识点概述了使用yacc和lex实现SQL解释器的理论基础和实现步骤,这些知识点对于深入理解编译原理和数据库管理系统的开发具有重要的意义。

    我的sql解释器0.1

    《我的SQL解释器0.1》是一个不错的起点,对于想要深入了解数据库和SQL语言的人来说,这是一个很好的实践项目。尽管目前功能有限,但随着不断迭代和改进,有望成为一个功能丰富的自定义SQL工具。对于初学者,可以从这...

    lex yacc for windows

    《在Windows下使用Flex与Bison:解析与...它们不仅适用于编译器的开发,还可以应用于配置文件解析、SQL查询解析、编程语言解释器等领域。理解并熟练掌握这两款工具的使用,对于深入学习编译原理和软件工程至关重要。

    Python Lex-Yacc.zip

    PLY是Python的一个实现,用于词法分析(Lex)和语法分析(Yacc)的工具,它允许开发者编写自己的解析器来处理特定的语言或数据格式。在计算机科学中,词法分析和语法分析是编译器和解释器设计中的关键步骤,它们分别...

    Simple-RDBMS:使用Lex和Yacc工具实现了SQL查询解析器,并构建了用于数据存储和操作的基本文件系统

    本文将深入探讨一个名为“Simple-RDBMS”的项目,该项目通过使用经典的词法分析工具Lex和语法分析工具Yacc,实现了一个简单的SQL查询解析器,并构建了一个基础的文件系统,以支持数据的存储和操作。 一、理解SQL...

    windows下的flex和yacc

    1. **MinGW/MSYS**:这是一个模拟Unix环境的工具集,提供了一个命令行界面,可以运行许多Unix工具,包括Flex和Yacc。首先,你需要下载并安装MinGW和MSYS,然后通过包管理器`pacman`安装flex和bison。 2. **Cygwin**...

    lexyaccmingw

    同时还包含了一个MinGW的GNU的C++编译器环境:)可以直接使用:) &lt;br&gt;这个包包含的文件列表: &lt;br&gt;MinGW GNU的C/C++编译程序(windows版本) bison.exe GNU的yacc程序 bison.hairy GNU的yacc程序...

    flex and yacc

    在学习编译原理时,`flex` 和 `yacc` 提供了一个很好的实践平台,让开发者能够深入理解词法分析和语法分析的过程。通过编写 `.l` 和 `.y` 文件,学生可以实现自己的编译器或解释器,从而更好地理解编程语言的内部...

    Yacc.rar_yacc_英文

    这个工具主要用于将词法分析器(通常由lex或flex生成)产生的词法单元流转换为语法分析树,是构建编译器和解释器的重要组成部分。在本“Yacc英文教程”中,我们将深入探讨Yacc的工作原理、语法定义、以及如何使用它...

    yacc-dev.7z

    在使用YACC时,开发者需要编写一个名为`.y`的文件,里面包含了文法规则和动作代码。文法规则由非终结符、终结符、优先级和结合性等组成,而动作代码则定义了当解析器遇到特定符号序列时应执行的操作。YACC会读取这个...

    yacc从入门到精通

    2. **解释器实现**:对于不需生成目标代码的解释器,yacc同样适用。 3. **配置文件解析**:许多配置文件格式可以通过yacc进行解析。 4. **DSL(领域特定语言)**:构建特定领域的解析器,如SQL查询解析。 **五、...

    sql简单语法分析(ply).zip_ply_ply python_python ply_reviewl71_sheetqpo

    在Python编程环境中,`ply`是一个著名的词法分析和语法分析工具,用于构建解析器。...在这个项目中,用户可以利用`ply`理解并执行简单的SQL查询,这对于学习SQL语法和解析原理,或者构建自己的SQL解释器都非常有帮助。

    SQL语言解析器的实现1

    此外,作者还提到了从PostgreSQL的SQL解析器中学习经验,以及Lex和Yacc的其他应用场景,比如编译器设计、脚本语言解释器等。 总之,为BerkeleyDB添加SQL支持是一个复杂的过程,涉及到数据库系统设计、解析理论和...

    parser generator

    描述提到的是一个适用于Windows操作系统的集成开发环境(IDE),该环境集成了lex和yacc工具。lex,也称为flex,是用于生成词法分析器的工具,它能够识别程序源代码中的基本符号或标记。而yacc,或者在某些实现中被...

    flex和bison官方手册

    Flex接受一个包含正则表达式和动作的输入文件(通常命名为lex.yy.c),然后生成C代码,该代码可以读取输入流并识别这些模式。 Bison,原名Yacc(Yet Another Compiler-Compiler),是一个语法分析器生成器。它根据...

    flex & bison 中文版

    其中,flex是一种快速词法分析器生成器,而bison则是一个语法分析器生成器,它们能够帮助用户创建出适用于各种文本数据处理任务的编译器和解释器。《flex与bison》这本书籍即是深入讲解如何使用这两个工具的经典参考...

    flex and bison

    Flex(以前称为lex)是一个词法分析器生成器,而Bison(以前称为yacc)是一个语法分析器生成器。它们共同帮助开发者将高级语言的语法规则转化为可执行代码。 **Flex** Flex是一个广泛使用的开源工具,用于创建词法...

    Windows下的flex和bison

    在Windows环境下使用它们可以为开发者提供强大的语法解析支持,尤其是在开发编译器、解释器或者语言处理工具时。下面将详细介绍这两个工具以及在Windows下如何使用它们。 `flex`(Fast Lexical Analyzer Generator...

Global site tag (gtag.js) - Google Analytics