본문 바로가기

Programming/LEX & YACC

SQL parser ( 간단한 몇 가지 구문을 토큰으로 나누고 stack 에 넣어 출력 )

테스트용으로 한번 만들어 본것
파서에서는 각 문법을 인식했을 때마다 씨언어로 동작을 작성할 수 있다.
평소에 코딩이 할 일이 있을 때 lex yacc이 필요하면 이런식으로 활용 할 수 있다.


/**************************************
* 렉스 select.l
**************************************/


%{
#include "y.tab.h"
int lineno = 1;
%}

%%

CREATE  { return CREATE; }
TABLE   { return TABLE; }
VIEW    { return VIEW;  }
SELECT { return SELECT; }
FROM { return FROM; }
WHERE  { return WHERE; }
AND  { return AND; }
OR { return OR;  }
NOT { return NOT; }
COUNT { return FUNC; }
SUM { return FUNC; }
MAX { return FUNC; }
MIN { return FUNC; }
AVG { return FUNC; }
INTEGER { return INTEGER; }
CHARACTER { return CHARACTER; }
DOUBLE  { return DOUBLE; }
NULLX { return NULLX; }
UNIQUE  { return UNIQUE; }
REFERENCES { return REFERENCES; }
PRIMARY { return PRIMARY; }
FOREIGN { return FOREIGN; }
KEY { return KEY; }
VIEW { return VIEW; } 
AS { return AS; }
UPDATE { return UPDATE; }
SET { return SET; }
GROUP { return GROUP; }
BY { return BY; }

"=" |
"<>" |
"<" |
">" |
"<=" |
">="  { return COMPARE; }

[-+*/:(),.;]    { return yytext[0]; }
[a-zA-Z][_a-zA-Z0-9]* { yylval.sval = strdup(yytext); return NAME; }

[0-9]+ { yylval.dval = atof(yytext); return NUMBER; }

'[^'\n]*' { yylval.sval = strdup(yytext); return STRING; }

\n { lineno++; }
[ \t] ;

%%

yyerror(char *s)
{
 printf(" line %d: %s at'%s':\n",lineno,s,yytext);
}

main(int argc , char **argv)
{
 if( argc > 1 )
 {
  FILE *fp = fopen(argv[1] , "r" );
  if(!fp)
  {
   printf("FILE OPEN ERROR !\n");
   exit(1);
  }
  yyin = fp;
 }
 if( !yyparse() )
  printf(" SQL parse worked \n");
 
 else
  printf(" SQL parse failed \n");

}

/**************************************
* 야크 select.y
**************************************/
%{
#include "sym_table.h"
%}

%union {
 double dval;
 char *sval;
}

%token <sval> NAME
%token <sval> STRING
%token <dval> NUMBER

%left OR
%left AND
%left NOT
%left COMPARE
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS

%token SELECT WHERE FROM FUNC CREATE TABLE VIEW UNIQUE AS UPDATE SET GROUP
%token NULLX INTEGER CHARACTER DOUBLE PRIMARY FOREIGN REFERENCES KEY BY

%%


sql_list :
   sql ';'  {
   input_stack("sql"); 
   input_stack("sql_list"); sql_end(); }
 | sql_list sql ';'
  ;

sql :   create_schema
 | manipulative_stat { input_stack("manipulative_stat"); }

 ;

create_schema :
   create_table { input_stack("create_schema"); }
 | create_view
        ; 

 /* create_table */
create_table :
   CREATE TABLE table_name '(' table_element_list ')'
 ;
table_element_list :
   table_element
        | table_element_list ',' table_element
        ;
table_name :
   NAME  {
    input_stack($1);  
       input_stack("NAME");
  }
  | NAME '.' NAME
 ;
table_element :
     variable
        | key
  ;
variable : NAME data_type
        |  NAME data_type data_opt
 ;

data_type : CHARACTER
 |   CHARACTER '(' NUMBER ')'
 |   INTEGER  
 |   INTEGER '(' NUMBER ')'
  |   DOUBLE
 |   DOUBLE '(' NUMBER ')' 
 ;
data_opt :  NOT NULLX
 |   NOT NULLX UNIQUE
 |   NOT NULLX PRIMARY KEY
 ;
key :      PRIMARY KEY '(' NAME ')'
 |   FOREIGN KEY '(' NAME ')' REFERENCES NAME
 |   UNIQUE '(' NAME ')'
 ; 
 /* create_view */
create_view :
     CREATE VIEW NAME '(' name ')'AS manipulative_stat
  |   UPDATE NAME SET NAME COMPARE update_cond where

update_cond :
     NAME '+' cond
 |   NAME '-' cond
 |   NAME '*' cond
  |   NAME '/' cond
 |   NUMBER

 /* query list */

manipulative_stat :
   select_stat   { input_stack("select_stat"); }
   ;

select_stat :
   SELECT name select_cond {
   input_stack("select_cond");
   input_stack("name");
   input_stack("SELECT");
   }  
   ;
select_cond :
   from
   where
   group_by  {
    input_stack("group_by");
    input_stack("where"); 
    input_stack("from");
      }   


   ; 
from :    FROM name  {   input_stack("name");
   input_stack("FROM");  }
   ;

where :    {  input_stack("empty string"); }
   |  
   WHERE condition {  input_stack("condition");
        input_stack("WHERE");
     }
   ;
group_by : {   input_stack("empty string"); }
   |
   GROUP BY name 
   ;

condition : comparision conj condition
     | comparision {  input_stack("comparision"); }
     ;

comparision: NAME COMPARE cond  {  input_stack($1);
       input_stack("cond");
       input_stack("COMPARE");
       input_stack("NAME"); }
   ;

cond :    NAME   {  
   input_stack($1);
    input_stack("NAME"); }
     |    NUMBER {    
   input_stack("NUMBER"); }
     |    STRING { 
   input_stack($1);
   input_stack("STRING"); }
     ;

name :
   table_name { input_stack("table_name"); }
     |    name ',' table_name
     ;

conj :    AND
     |   OR
     |    NOT
     ;
  
%%

sql_end()

  show_stack();
 printf("\n parsing complete \n");
 exit(1);
}

'Programming > LEX & YACC' 카테고리의 다른 글

LEX 와 YACC 의 동작 원리  (0) 2009.08.14
간단한 렉스 프로그램 ( Flex & C++ )  (0) 2009.08.13
YACC 문법 구조  (0) 2009.08.13
LEX 의 정규 표현식  (0) 2009.08.13
LEX 의 구조  (1) 2009.08.12