windows下的lex与yacc工具(转)
Parser Generator作为当前最好用的Windows环境LEX/YACC工具而被广泛应用。
之所以推荐它是因为它生成的c文件可以在vc++下通过编译。
下载地址?http://www.bumblebeesoftware.com/downloads.htm?
下载之后,解压缩,然后安装。
打开集成开发环境,选择项目“Project”菜单,在下拉菜单中选“LibBuilder”,弹出LibBuilder对话框
选择“属性”按钮弹出“compiler properties”对话框:
对于Microsoft Visual Studio6.0即VC6.0的设置
Compiler Bin Directory:?? C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\BIN
Compiler Bin Directory(2):?? C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\COMMON\MSDEV98\BIN
Compiler Include Directory: C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\INCLUDE
Compiler Include Directory(2): C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\MFC\INCLUDE
Compiler Library Directory: C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\LIB
Compiler Library Directory(2): C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\MFC\LIB
点ok。返回LibBuilder。
点Build就可以编译vc++使用的lex与yacc的lib库。生成库文件在软件安装目录下的D:\Parser Generator 2\Cpp\Lib\msvc32目录下。
单独yacc文件的编译。
以下是一个单独的yacc文件,实现一个简单的计算器功能。
%{
/************************************************************
www.linmu100.com
************************************************************/
#include <ctype.h>
#include <stdio.h>
#define YYSTYPE double /* double type for YACC stack */
%}
%token NUMBER
%%
lines??? : lines expr '\n'??? ??? ??? { printf("%g\n", $2); }
??? ??? | lines '\n'
??? ??? | /* e */
??? ??? | error '\n'??? ??? ??? ??? { yyerror("reenter last line:"); yyerrok(); }
??? ??? ;
expr??? : expr '+' term??? ??? ??? ??? { $$ = $1 + $3; }
??? ??? | expr '-' term??? ??? ??? ??? { $$ = $1 - $3; }
??? ??? | term
??? ??? ;
term??? : term '*' factor??? ??? ??? { $$ = $1 * $3; }
??? ??? | term '/' factor??? ??? ??? { $$ = $1 / $3; }
??? ??? | factor
??? ??? ;
factor??? : '(' expr ')'??? ??? ??? ??? { $$ = $2; }
??? ??? | '(' expr error??? ??? ??? { $$ = $2; yyerror("missing ')'"); yyerrok(); }
??? ??? | '-' factor??? ??? ??? ??? { $$ = -$2; }
??? ??? | NUMBER
??? ??? ;
%%
int main(void)
{
??? return yyparse();
}
int yylex(void)
{
??? int c;
??? while ((c = getchar()) == ' ');
??? if (c == '.' || isdigit(c)) {
??? ??? ungetc(c, stdin);
??? ??? scanf("%lf", &yylval);
??? ??? return NUMBER;
??? }
??? return c;
}
我们用Parser Generator的Project --> Parser Wizard创建一个工程,如下图所示,注意红圈部分的设置:
?
这时,我们可以看到Parser Generator帮我们自动生成了一个myparser.y文件,语法规则就可以在这里加了。
现在我们把开头展示的yacc源码完全覆盖myparser.y文件,然后编译,成功后会生成三个文件:myparser.c,myparser.h,myparser.v
好,现在我们要做的就是用vc来编译myparser.c,myparser.h这两个文件了。
打开Microsoft Visual C++ 6.0,新建一个工程。
然后将Parser Generator生成的两个文件myparser.c,myparser.h导入工程。(这里就不多说了^-^)
现在要设置环境变量了,首先要导入Parser Generator的库文件和源文件。在工具->选项里要设置这些环境变量。
设置完这些文件后,还要在工程->设置里添加yl.lib库:
好,一切设置完毕,开始编译,编译通过后,就会生成yacc_vc.exe文件。
假设有文件demo.txt,此文件和yacc_vc.exe在同一个目录,其内容如下:
1+3*5
3*4-23
7- 9 *30 - 999
在此目录的命令行下运行如下命令:yacc_vc.exe <demo.txt,即可得到计算结果:
单独lex文件的编译。
以下是一个单独的lex文件,实现一个简单的计算单词个数功能。
%{
/************************************************************
www.linmu100.com
************************************************************/
int wc = 0;??? ??? /* word count */
%}
%%
[a-zA-Z]+??? { wc++; }
\n|.??? ??? { /* gobble up */ }
%%
int main(void)
{
??? int n = yylex();
??? return n;
}
int yywrap(void)
{
??? printf("word count: %d\n", wc);
??? return 1;
}
我们用Parser Generator新建一个工程:
?
下一步默认完成即可。这时,Parser Generator帮我们自动生成了一个mylexer.l文件,词法规则可以在这里加。
同样的,我们用上面展示的lex文件内容完全覆盖mylexer.l文件,编译后同样生成三个文件,然后用VC编译其中的myparser.c,myparser.h这两个文件。
VC的设置方法和上面编译单独yacc文件时的步骤完全一样,最终会生成一个可以计算文件单词数目的.exe文件。
yacc 和 lex整合文件的编译。
以下分别是yacc文件和lex文件的内容,这两个文件共同实现了自定义的一个简单语法规则。
yacc文件内容:
%{
/*
www.linmu100.com
*/
#include <stdio.h>
#include <string.h>
void yyerror(const char *str)
{
??? fprintf(stderr,"error: %s\n",str);
}
int yywrap()
{
??? return 1;
}
main()
{
??? yyparse();
}
char *heater="xl's test";
%}
%token TOKHEATER TOKHEAT TOKTARGET TOKTEMPERATURE
%union?
{
??? int number;
??? char *string;
}
%token <number> STATE
%token <number> NUMBER
%token <string> WORD
%%
commands:
??? | commands command
??? ;
command:
??? heat_switch | target_set | heater_select
??? ;
heat_switch:
??? TOKHEAT STATE?
??? {
??? ??? if($2)
??? ??? ??? printf("\tHeater '%s' turned on\n", heater);
??? ??? else
??? ??? ??? printf("\tHeat '%s' turned off\n", heater);
??? }
??? ;
target_set:
??? TOKTARGET TOKTEMPERATURE NUMBER
??? {
??? ??? printf("\tHeater '%s' temperature set to %d\n",heater, $3);
??? }
??? ;
heater_select:
??? TOKHEATER WORD
??? {
??? ??? printf("\tSelected heater '%s'\n",$2);
??? ??? heater=$2;
??? }
??? ;
lex文件内容:
%{
/*
www.linmu100.com
*/
#include <stdio.h>
#include <string.h>
#include "myparser.h"?? ?? ?? ?? ?? ?? //注意,这里的头文件要和Parser Generator生成的头文件名一样。
extern char *yytext;
%}
%%
[0-9]+????????????????? {yylval.number=atoi(yytext); return NUMBER;}
heater??? ??? ??? return TOKHEATER;
heat??????????????????? return TOKHEAT;
on|off????????????????? {yylval.number=!strcmp(yytext,"on"); return STATE;}
target????????????????? return TOKTARGET;
temperature???????????? return TOKTEMPERATURE;
[a-z0-9]+??? ??? {yylval.string=strdup(yytext);return WORD;}
\n????????????????????? /* ignore end of line */;
[ \t]+????????????????? /* ignore whitespace */;
%%
现在用Parser Generator创建新的工程:
?
?
其余的步骤和上面编译yacc时的步骤相同,最终可以生成both_y_l.exe文件,放一个demo.txt和both_y_l.exe在同一个目录下,demo.txt内容如下:
heat on
target temperature 99
heater asdfsieiwef99adsf
然后在此目录的命令行下执行both_y_l.exe <demo.txt得到:
?
以上即为Parser Generator的使用以及如何用VC编译。