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编译

猜你喜欢

转载自igaozh.iteye.com/blog/1695633