Search

'SQL파서'에 해당되는 글 1건

  1. 2007.08.17 Lex&Yacc으로 SQL 파서를 만들어 보자

Lex&Yacc으로 SQL 파서를 만들어 보자

Programming/Delphi 2007.08.17 01:04 Posted by 파란크리스마스

정규표현식이나, Lex&Yacc을 델파이만 개발 하신 분이라면 처음 들어 보신 분들도 계실 것이라고 생각됩니다.
저도 6년 넘게 개발하면서 최근에 알게 되었고, 그 활용 범위가 무궁무진 하다는 것도 알게 되었죠.
이 글을 있는 개발자 분들도 이 글을 계기로 Lex&Yacc에 대해서 관심을 가졌으면 합니다.

Lex&Yacc은 컴파일러를 만들기 위한 도구로 GCC나 대부분의 컴파일러가 Lex&Yacc을 사용하고 있습니다.
Lex&Yacc의 활용 범위는 소스를 분석하거나, 소스에서 주석만 제거하거나, 간단한 스크립트 언어를 만들 수도 있습니다.

C언어나 JAVA의 경우 많은 Lex&Yacc 도구가 많이 있지만 Delphi의 경우 2개 정도 있는 것 같고,
제가 사용하고 있는 Delphi Lex&Yacc은 Tuber Pascal로 만들어 진 것을 델파이용으로 수정한 것으로 버전은 1.3을 사용했습니다.

아래의 예제는 데이터베이스에서 SQL을 파싱하는 아주 간단한 Sample을 만들어 보았습니다.

select aa, bb from tab;
select aa, bb, cc from tab1, tab2;

위의 SQL 문장에서 컬럼과 테이블 명을 구하는 Lex&Yacc 소스입니다.
위의 SQL 문장의 컬럼과 테이블 명을 구하는 것을 Lex&Yacc을 사용하지 않고도 쉽게 얻어 낼 수 있겠지만, 굉장히 긴 문장의 SQL문장에서 컬럼, 테이블, 함수, 문자열을 분리하는 것을 어려울 것입니다. 이와 같은 SQL문 처리를 위해서 여러분들이 Lex&Yacc문장을 추가 하시기 바랍니다. (인터넷에 SQL grammar 찾아서 추가하면 될 듯......)

▶ Delphi Lex & Yccc Download

http://www.grendelproject.nl/dyacclex/

▶ Lex 파일

- sqllex.l 파일

%start

%%
 
[F|f][R|r][O|o][M|m] begin return(FROM); end;
[S|s][E|e][L|l][E|e][C|c][T|t] begin return(SELECT); end;

[A-Za-z][A-Za-z0-9_]* begin
yylval.yyString := yytext;
return (NAME);  end;

[ \t\n] ;

. |
\n returnc(yytext[1]);

- sqllex.pas 만들기

C:\Delphi\dyacclex-1.3\test\sql>dlex.exe sqllex.l
Delphi Lex - Copyright (c) 2003,2004 by Michiel Rook
Based on Turbo Pascal Lex 4.1, Copyright (c) 1990-2000 Albert Graef
parse ... DFA construction ... code generation ... DONE
15 lines, 6 rules, 27/1200 p, 29/600 s, 58/1200 t.

▶ Yacc 파일

- sqlparser.y 파일

%{
program sqlpser;
{$APPTYPE CONSOLE}


uses
SysUtils,
dlib,
yacclib,
lexlib;

var x : array [1..26] of Real;

%}

%token NAME
%token FROM SELECT /* illegal token */

%%

query_spec:
SELECT selection table_exp ';'
;

table_exp:
from_clause
;

from_clause:
FROM table_ref_commalist
;

table_ref_commalist:
table_ref
| table_ref_commalist ',' table_ref
;

table_ref:
table
| table range_variable
;

range_variable: NAME
;

table:
NAME { writeln('Table : ', $1); }
| NAME '.' NAME
;

selection:
scalar_exp_commalist
| '*'
;

scalar_exp_commalist:
scalar_exp
| scalar_exp_commalist ',' scalar_exp
;

scalar_exp:
column_ref
;

column_ref:
NAME { writeln('Column : ', $1); }
| NAME '.' NAME /* needs semantics */
| NAME '.' NAME '.' NAME
;

%%

{$I sqllex.pas}

var
lexer : TLexer;
parser : TParser;
i : Integer;

begin
for i := 1 to 26 do
x[i] := 0.0;

lexer := TLexer.Create();
  
parser := TParser.Create();
parser.lexer := lexer;
parser.parse();
end.

- sqlparser.dpr 만들기

C:\Delphi\dyacclex-1.3\test\sql>dyacc.exe sqlparser.y sqlparser.dpr
Delphi Yacc - Copyright (c) 2003,2004 by Michiel Rook
Based on Turbo Pascal Yacc 4.1, Copyright (c) 1990-2000 Albert Graef
parse ... sort ... closures ... first sets ... LR0 set ... lookaheads ...
code generation ... DONE
89 lines, 18/900 rules, 29/1200 s, 41/9600 i, 33/9600 t, 19/1200 r.

▶ 컴파일, 실행

- 컴파일

위의 lex, yacc 절차를 따르셨다면 sqlparser.dpr, sqllex.pas 파일이 생겼을 것입니다.
sqlparser.dpr, sqllex.pas 한 폴더에 두고 델파이에서 sqlparser.dpr을 열어서 컴파일 하고 sqlparser.exe 실행 하면 됩니다.

C:\Delphi\dyacclex-1.3\test\sql>sqlparser
select aa, bb from tab;
Column : aa
Column : bb
Table : tab
신고


 

티스토리 툴바