lex 和 yacc 学习…
来源:互联网 发布:淘宝被保护自助开通 编辑:程序博客网 时间:2024/06/03 07:21
笔记1中的实现是线程不可重入的,通过拜读《flex&bison》这本书学习并实践了线程可重入(reentrant)的实现(还是看正经的教科书来的靠谱)。这里记录下。
1. flex的可重入
实例程序如下: test.l
---------------------------------------------------------------------------------
新浪博客的bug吧,
这里一贴代码就出显示的问题, 这段代码可以到我baidu的博客上看
http://hi.baidu.com/gao_dennis/item/e583244ee2d84a16896d103c
------------------------------------------------------------------------------------------------------
关键在于 参数yyscan_t scanner; 它可以理解为可重入parser一次解析的用户空间。它包含了非可重入模式下的全局变量和缓存的本地版本。
我们可以通过yylex_init_extra 给scanner设置传参。通用可以使用yy_scan_bytes来为输入缓存设置。
另外在.l文件中还需要做些修改:
首先 %option reentrant 告知flex这是要生成一个可重入版本的解析器;
然后 %option extra-type="struct pwc *" 告知flex解析器传参的类型。
最后 struct pwc *pp = yyextra; 取这个传参为本次解析的本地变量。 注意这句话的位置,它位于规则块中:
%%
%{
struct pwc *pp = yyextra;
%}
title {showtitle(); strcpy(pp->title, yytext);}
[/n] {linenum++;}
[0-9]+ { pp->num= atoi(yytext);}
[a-zA-Z][a-zA-Z0-9]*{printf("Var : %s/n",yytext); strcpy(pp->body, yytext); }
[/+/-//%] {printf("Op : %s/n",yytext); return OP;}
. {printf("Unknown : %c/n",yytext[0]); return UNKNOWN;}
%%
2. bison的可重入
bison的可重入要简单很多,主要是添上:
% define api.pure
%parse-param { struct pureparse *pp }
其中% defineapi.pure的作用是告知bison这是个可重入的程序,而%parse-param告知用户传参的类型,例如:
yyparse(&mypwc); 其中“&mypwc”的类型就是由 %parse-param来告知。
此外,可重入bison与非可重入版本调用yylex的方式也不一样。在非可重入版本中bison与yylex通过全局变量yylval来交互信息。在可重入bison中yylval将被作为参数传递给yylex
token = yylex(YYSTYPE *yylvalp);
注,如果有使用yyloc的话 token = yylex(YYSTYPE *yylvalp,YYLTYPE *yylocp);
3. bison + flex
示例代码:
test2.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);
%}
%option noyywrap nodefault yylineno reentrant bison-bridge
%option header-file="test.l.h"
%%
%{
struct param *pp = yyextra;
%}
title {showtitle(); strcpy(yylval->title, yytext); returnTITLE;}
[/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");
}
------------------------------------------------------------------------------------------------------------
区别在于
a. 添加了选项 %option bison-bridge,用来生成和可重入版本bison调用方式相适应的yylex函数
int yylex(YYSTYPE * yylval_param ,yyscan_t yyscanner);
b. 也生成了一个头文件 test.l.h, 这个文件不能被包含在该.l文件中
c. yylval的类型变成了指针 (bison中的$n的类型由宏YYSTYPE来决定,而bison调用yylex时的传参是YYSTYPE *,且新的yylex函数的第一个参数的类型也是YYSTYPE * )
然后是test.y
--------------------------------------------------------------------------------------------------------
% defineapi.pure (这里 %和 define之间没有空格,因为显示的问题所以加上的)
%parse-param { struct param *pp }
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "test.l.h"
#define YYLEX_PARAM pp->scaninfo
extern int linenum;
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
} 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(struct param * pp, char *msg)
{
printf("error: %s", msg);
return 0;
}
int parser_do(const char *str, int len, MAIL *m)
{
PARAM mypwc = {NULL,NULL};
mypwc.m = m;
YY_BUFFER_STATE state;
yylex_init_extra(&mypwc,&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;
}
-----------------------------------------------------------------------------------------------------------------
这里需要注意的是
#define YYLEX_PARAM pp->scaninfo
这个是指定bison调用 yylex时所传递的yyscan_t对象,这也是flex可重入的关键。
在这个例子中,我们把yyscan_t对象作为bison传入参数的一个属性, 由结构体
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
} PARAM;
定义。
另外这里我们引用了flex生成的头文件test.l.h 主要是因为定义的结构体PARAM用到了yyscan_t。
然后是实例的剩余部分
main.h
------------------------------------------------------------------------------------
typedef struct Mail
{
char title[10];
int num;
char body[50];
} MAIL;
#define YYSTYPE MAIL
-----------------------------------------------------------------------------------------
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;
}
--------------------------------------------------------------------------------------------
编译命令同上一篇博客
转载请注明出自高孝鑫的博客
1. flex的可重入
实例程序如下: test.l
---------------------------------------------------------------------------------
新浪博客的bug吧,
这里一贴代码就出显示的问题, 这段代码可以到我baidu的博客上看
http://hi.baidu.com/gao_dennis/item/e583244ee2d84a16896d103c
------------------------------------------------------------------------------------------------------
关键在于 参数yyscan_t scanner; 它可以理解为可重入parser一次解析的用户空间。它包含了非可重入模式下的全局变量和缓存的本地版本。
我们可以通过yylex_init_extra 给scanner设置传参。通用可以使用yy_scan_bytes来为输入缓存设置。
另外在.l文件中还需要做些修改:
首先 %option reentrant
然后 %option extra-type="struct pwc *" 告知flex解析器传参的类型。
最后 struct pwc *pp = yyextra; 取这个传参为本次解析的本地变量。 注意这句话的位置,它位于规则块中:
%%
%{
struct pwc *pp = yyextra;
%}
title
[/n]
[0-9]+
[a-zA-Z][a-zA-Z0-9]*{printf("Var
[/+/-//%]
.
%%
2. bison的可重入
bison的可重入要简单很多,主要是添上:
% define api.pure
%parse-param { struct pureparse *pp }
其中% defineapi.pure的作用是告知bison这是个可重入的程序,而%parse-param告知用户传参的类型,例如:
yyparse(&mypwc);
此外,可重入bison与非可重入版本调用yylex的方式也不一样。在非可重入版本中bison与yylex通过全局变量yylval来交互信息。在可重入bison中yylval将被作为参数传递给yylex
token = yylex(YYSTYPE *yylvalp);
注,如果有使用yyloc的话
3. bison + flex
示例代码:
test2.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);
%}
%option noyywrap nodefault yylineno reentrant bison-bridge
%option header-file="test.l.h"
%%
%{
struct param *pp = yyextra;
%}
title
[/n]
[0-9]+
[a-zA-Z][a-zA-Z0-9]*
[/+/-/*///%]
.
%%
showtitle()
{
printf("----- Lex Example -----/n");
}
------------------------------------------------------------------------------------------------------------
区别在于
然后是test.y
--------------------------------------------------------------------------------------------------------
% defineapi.pure
%parse-param { struct param *pp }
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "test.l.h"
#define YYLEX_PARAM pp->scaninfo
extern int linenum;
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
} 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(struct param * pp, char *msg)
{
}
int parser_do(const char *str, int len, MAIL *m)
{
}
-----------------------------------------------------------------------------------------------------------------
这里需要注意的是
#define YYLEX_PARAM pp->scaninfo
这个是指定bison调用 yylex时所传递的yyscan_t对象,这也是flex可重入的关键。
在这个例子中,我们把yyscan_t对象作为bison传入参数的一个属性, 由结构体
typedef struct param{
yyscan_t scaninfo;
MAIL *m;
} PARAM;
定义。
另外这里我们引用了flex生成的头文件test.l.h 主要是因为定义的结构体PARAM用到了yyscan_t。
然后是实例的剩余部分
main.h
------------------------------------------------------------------------------------
typedef struct Mail
{
} MAIL;
#define YYSTYPE MAIL
-----------------------------------------------------------------------------------------
main.c
----------------------------------------------------------------------------------------
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "test.tab.h"
#include "main.h"
int main()
{
}
--------------------------------------------------------------------------------------------
编译命令同上一篇博客
转载请注明出自高孝鑫的博客
0 0
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- lex 和 yacc 学习笔记1
- IOS 开发 loadView 和 viewDidLoad…
- C# StreamReader 和 StreamWriter …
- set unused column column_name 和…
- 兴趣学习: 信息熵 ---- 《数学…
- dive into python 第 5 章 对象和…
- 总结: 全排列 和 全部子集 (深搜…
- 集线器 交换机 路由器 网桥 …
- 使用BBED修改SCN …
- Java学习笔记18 ArrayList 和Linke…
- spring security 和spring mvc学习
- Hive安装 …
- android o…
- android …
- 通过cat 数据文件来合并 myisam表
- Innodb Architecture an…
- 黑马程序员——OC基础@property语法详解
- 关于图处理的数据库 和 工具
- lex 和 yacc 学习笔记1
- lex 和 yacc 学习…
- mysql命令行工具的编辑技巧
- git 推送分支
- Mysql 学习小记1
- mysql实际使用过程中碰到的一些有…
- 关于mysql query cache和memcached…
- windows下编译bison + f…
- 用cmake 编译 bison和flex
- 如何查看mysql的某个安全漏洞在哪…