用flex & bison (lex & yacc)创建可重入(线程安全)的词
?使用flex(lex)和bison(yacc)可以非常方便的创建词法分析和语法分析器,典型的这类程序都是 %% insert????? {?return?CMD_INSERT;?} delete?????{?return?CMD_DELETE;} update????{?return?CMD_UPDATE;} select??? ??{?return?CMD_SELECT;} [?ntr]+??? {?;???????????????????????????????} .??????????{?return?CMD_ERROR;} %% 我自己做了集成,把要解析的命令传给自己的class: #ifndef?_DO_H_ #define?_DO_H_ #include?<iostream> #include?<string> #include?<FlexLexer.h> using?namespace?std; class?myLexer:?public?yyFlexLexer { ????public: ????????//?set?parse?command ????????myLexer(const?char?*sql) ????????{? ????????????snprintf(content,?sizeof(content),?sql); ????????????parseP?=?content; ????????} ???????? ????????//?flex通过调用这个方法取得要解析的字符串的 ????????virtual?int?LexerInput(char*?buf,?int?max_size) ????????{ ????????????if(parseP?==?NULL)??????return?0; ????????????if(*parseP?==?' ')?????return?0; ????????????strncpy(buf,?parseP,?max_size?-?1); ????????????buf[max_size?-?1]?=?' '; ???????????? ????????????int?len?=?strlen(buf); ????????????parseP?+=?len; ????????????return?len; ????????} ????????//错误函数 ????????virtual?void?LexerError(const?char*?msg) ????????{ ????????????cout<<"error:"<<?msg?<<?"?at?line:"?<<?lineno()?<<endl; ????????} ???????? ????????virtual?~myLexer()?{} ???????? ????private: ????????char?content[4096]; ????????char?*parseP; }; #endif ????调用方法: ????const?char?*sql??=?"update?insert?select?delete?update?insert?select?delete"; ????const?char?*sql2?=?"delete?select?insert?update?delete?select?insert?update"; ????myLexer?*myl??=?new?myLexer(sql); ????myLexer?*myl2?=?new?myLexer(sql2); ????int?cmd,?cmd2;? ???? ????while((cmd?=?myl->yylex())?!=?0?&&?(cmd2?=?myl2->yylex())?!=?0) ????{ ????????cout<<?"cmd1?is:"?<<?cmd?<<?"?cmd2?is:"?<<?cmd2?<<?endl; ????} ???? ????delete?myl; ????delete?myl2; ???? ????return?0; } ? ???用2个词法解析器同时进行解析,发现没有问题,说明是可重入的。? ??? (2)?bison的可重入实施 ????官方文档有:http://dinosaur.compilertools.net/bison/bison_6.html#SEC56 ???? ????注意点:?必须加入%pure_parser ????表示创建可重入的语法解析程序。 ???? ????这时候无法使用全局变量共享信息,必须通过参数传递。 #define?YYPARSE_PARAM???parm #define?YYLEX_PARAM?????parm 表示,会传递一个参数给yyparse()和yylex函数,因为默认的yyparse和yylex是不接受参数的。 #define?yyerror(msg)?my_yyerror(msg,?YYPARSE_PARAM)?//把这个参数也传递给yyerror 贴出全部程序: %{ #include?<stdio.h> #include?<stdlib.h> #include?<unistd.h> #include?<sys/types.h> #include?<sys/stat.h> #include?<string> #include?"do.h" using?namespace?std; %} %union { ????int?cmd_type; } %{ #define?YYPARSE_PARAM???parm #define?YYLEX_PARAM?????parm #define?yyerror(msg)?my_yyerror(msg,?YYPARSE_PARAM) int?yylex(YYSTYPE?*lvalp,?void?*parm) { ??myLexer?*l?=?(myLexer?*)parm; ??return?l->yylex(); } int?my_yyerror(char?*s,?void?*parm) { ????myLexer?*l?=?(myLexer?*)parm; ????cout<<"bison?got?errorn"; ????l->LexerError(s); ????return?1; } %} %token?CMD_INSERT %token?CMD_DELETE %token?CMD_UPDATE %token?CMD_SELECT %token?CMD_ERROR %pure_parser %start?sql %% sql: ?????|sql?command; ????? command:?CMD_INSERT???{?cout<<"meet?a?insertn";?} ?????|?CMD_DELETE?????{?cout<<"meet?a?deleten";?} ?????|?CMD_UPDATE?????{?cout<<"meet?a?updaten";?} ?????|?CMD_SELECT?????{?cout<<"meet?a?selectn";?} %% ????调用方法: #include?<string> #include?<FlexLexer.h> #include?"do.h" using?namespace?std; int?main(int?argc,?char?**argv) { ????const?char?*sql??=?"update?insert?select?delete?update?insert?select?delete"; ????const?char?*sql2?=?"delete?select?insert?update?delete?select?insert?update"; ????myLexer?*myl??=?new?myLexer(sql); ???? ????//进行语法解析 ????yyparse((void?*)myl); ???? ????delete?myl; ???? ????return?0; } ???有了可重入和参数传递基础,我们就可以很方便的设计自己的线程安全词法和语法分析程序,所有的信息可以通过传递参数搞定。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |