之前给DBScale写的sql解析器并没有处理token的位置信息,这样在重构sql语句的时候非常的麻烦。
本文将说明如何在可重入的bison和flex中添加token的位置信息,即yylloc.
flex文件修改:
首先需要在flex文件中添加选项:
%bison-locations
开启flex对位置信息的支持。
其次,因为flex或者lex会自动维护行的信息(yylineno), 但不会自动为你维护列的信息, 我们需要自己维护。
参考《flex & bison》这本书第8章中的介绍,我们可以使用 YY_USER_ACTION 这个宏(书中的例子不能直接用,因为那个是单线程模式下的例子)。
flex在匹配到一个token之后,在返回给bison之前,会调用YY_USER_ACTION
在flex文件第一部分中添加 YY_USER_ACTION的定义:
%{
#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;\
yylloc->first_column = sp->column; yylloc->last_column = sp->column+yyleng-1;\
sp->column += yyleng;
%}
上面的sp->column是我添加进去的,用来记录本次sql语句解析过程中当前token匹配位置的。
它的值在本次sql语句匹配过程中被每次token匹配使用和修改。
而sp是yylex_init_extra 初始化时,设置的yylex外部参数。
bison文件修改:
首先是添加选项:
%locations
其次是修改yyerror的函数定义:
int yyerror(YYLTYPE *l, struct param *pp , const char *s, ...);
这里的YYLTYPE是我们重定义的位置信息结构体:
typedef struct location {
int first_line;
int first_column;
int last_line;
int last_column;
} location_value;
#define YYLTYPE location_value
修改后的示例:
test3.l
----------------------------------------------------------------------------
%{
#include "stdio.h"
#include "string.h"
#include "main.h"
#include "test.tab.h"
int linenum;
extern int parse_worker(const char *str, int len);
#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;\
yylloc->first_column = sp->column; yylloc->last_column = sp->column+yyleng-1;\
sp->column += yyleng;
%}
%option noyywrap nodefault yylineno reentrant bison-bridge bison-locations
%option header-file="test.l.h"
%%
%{
scan_param *sp = (scan_param *)yyextra;
%}
title
{showtitle(); strcpy(yylval->title, yytext); return TITLE;}
[/n]
{linenum++; return SPACE;}
[0-9]+
{ yylval->num= atoi(yytext); return NUM;}
[a-zA-Z][a-zA-Z0-9]*
{printf("Var
: %s/n",yytext); strcpy(yylval->body, yytext); return STRING;}
[/+/-/*///%]
{printf("Op
: %s/n",yytext); return OP;}
.
{printf("Unknown : %c/n",yytext[0]); return UNKNOWN;}
%%
showtitle()
{
printf("----- Lex Example -----/n");
}
------------------------------------------------------------------------------------------------------------
test3.y
-------------------------------------------------------------------------------------------------------------
% define api.pure
(这里 %和 define之间没有空格,因为显示的问题所以加上的)
%locations
%parse-param { struct param *pp }
%{
#include
#include
#include
#include "main.h"
#include "test.l.h"
#define YYLEX_PARAM pp->scaninfo
extern int linenum;
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
scan_param *sp;
} PARAM;
%}
%token SPACE LOF TITLE NUM STRING OP UNKNOWN
%%
mail: head UNKNOWN body
| no;
head: TITLE UNKNOWN NUM {strcpy(pp->m->title, $1.title); pp->m->num=$3.num;};
body: STRING {strcpy(pp->m->body, $1.body);};
no : SPACE|UNKNOWN|OP;
%%
int yyerror( YYLTYPE *l, struct param * pp, char *msg)
{
printf("error: %s", msg);
return 0;
}
int parser_do(const char *str, int len, MAIL *m)
{
PARAM mypwc ;
mypwc.m = m;
sp.column = 1;
YY_BUFFER_STATE state;
scan_param sp;
mypwc.sp = &sp;
yylex_init_extra(mypwc.sp, &mypwc.scaninfo);
linenum=0;
state = yy_scan_bytes(str, len, mypwc.scaninfo);
yy_switch_to_buffer(state, mypwc.scaninfo);
yyparse(&mypwc);
yy_delete_buffer(state, mypwc.scaninfo);
yylex_destroy( mypwc.scaninfo );
printf("\n gaotitle: %s, num: %d, body: %s\n", mypwc.m->title, mypwc.m->num, mypwc.m->body);
return 0;
}
----------------------------------------------------------------------------------------------------------------- main.h
------------------------------------------------------------------------------------
typedef struct Mail
{
char title[10];
int num;
char body[50];
} MAIL;
typedef struct scan_param
{
int column;
} scan_param;
typedef struct location {
int first_line;
int first_column;
int last_line;
int last_column;
} location_value;
#define YYSTYPE MAIL
#define YYLTYPE location_value
-----------------------------------------------------------------------------------------
main.c
----------------------------------------------------------------------------------------
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "test.tab.h"
#include "main.h"
int main()
{
char *text = "title 3 hello123";
MAIL mail;
//parse_worker((const char *)text, strlen(text));
parser_do((const char *)text, strlen(text), &mail);
printf("\ntitle:%s num:%d body:%s\n", mail.title, mail.num, mail.body);
return 0;
}
--------------------------------------------------------------------------------------------
转载请注明转自高孝鑫的博客
本文将说明如何在可重入的bison和flex中添加token的位置信息,即yylloc.
flex文件修改:
首先需要在flex文件中添加选项:
%bison-locations
开启flex对位置信息的支持。
其次,因为flex或者lex会自动维护行的信息(yylineno), 但不会自动为你维护列的信息, 我们需要自己维护。
参考《flex & bison》这本书第8章中的介绍,我们可以使用 YY_USER_ACTION 这个宏(书中的例子不能直接用,因为那个是单线程模式下的例子)。
flex在匹配到一个token之后,在返回给bison之前,会调用YY_USER_ACTION
在flex文件第一部分中添加 YY_USER_ACTION的定义:
%{
#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;\
%}
上面的sp->column是我添加进去的,用来记录本次sql语句解析过程中当前token匹配位置的。
它的值在本次sql语句匹配过程中被每次token匹配使用和修改。
而sp是yylex_init_extra 初始化时,设置的yylex外部参数。
bison文件修改:
首先是添加选项:
%locations
其次是修改yyerror的函数定义:
int yyerror(YYLTYPE *l, struct param *pp , const char *s, ...);
这里的YYLTYPE是我们重定义的位置信息结构体:
typedef struct location {
} location_value;
#define YYLTYPE location_value
修改后的示例:
test3.l
----------------------------------------------------------------------------
%{
#include "stdio.h"
#include "string.h"
#include "main.h"
#include "test.tab.h"
int linenum;
extern int parse_worker(const char *str, int len);
#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;\
%}
%option noyywrap nodefault yylineno reentrant bison-bridge bison-locations
%option header-file="test.l.h"
%%
%{
scan_param *sp = (scan_param *)yyextra;
%}
title
[/n]
[0-9]+
[a-zA-Z][a-zA-Z0-9]*
[/+/-/*///%]
.
%%
showtitle()
{
printf("----- Lex Example -----/n");
}
------------------------------------------------------------------------------------------------------------
test3.y
-------------------------------------------------------------------------------------------------------------
% define api.pure
%locations
%parse-param { struct param *pp }
%{
#include
#include
#include
#include "main.h"
#include "test.l.h"
#define YYLEX_PARAM pp->scaninfo
extern int linenum;
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
scan_param *sp;
} PARAM;
%}
%token SPACE LOF TITLE NUM STRING OP UNKNOWN
%%
mail: head UNKNOWN body
head: TITLE UNKNOWN NUM {strcpy(pp->m->title, $1.title); pp->m->num=$3.num;};
body: STRING {strcpy(pp->m->body, $1.body);};
no : SPACE|UNKNOWN|OP;
%%
int yyerror( YYLTYPE *l, struct param * pp, char *msg)
{
}
int parser_do(const char *str, int len, MAIL *m)
{
sp.column = 1;
mypwc.sp = &sp;
}
-----------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
typedef struct Mail
{
} MAIL;
typedef struct scan_param
{
} scan_param;
typedef struct location {
} location_value;
#define YYSTYPE MAIL
#define YYLTYPE location_value
-----------------------------------------------------------------------------------------
main.c
----------------------------------------------------------------------------------------
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "test.tab.h"
#include "main.h"
int main()
{
}
--------------------------------------------------------------------------------------------
转载请注明转自高孝鑫的博客