![clip_image001[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image001%5B7%5D_thumb.jpg)
關于yacc 和 lex 和在下面鏈接的文章里已經有所介紹了
/html/linuxshijie/20070909/80.html
鏈接中的文章還介紹了在linux下如何使用yacc和lex工具,下面主要是介紹yacc和lex在windows下的用法。
yacc和lex在windows已經移植成功,其中常用的一個工具就是Parser Generator。這個工具使用yacc和lex能夠生成Visual C++,Borland C++,Other C/C++以及相關Java代碼。下面介紹一下這個工具是如何生成代碼并使用Visual C++編譯的。
注:關于Parser Generator的使用和配置,其實在Parser Generator Help中已經有很詳細的介紹,感興趣的朋友可以去那里查到更多有用的信息。
首先要去http://www.bumblebeesoftware.com/downloads.htm下載Parser Generator。
安裝完畢后,我們可以在它的安裝目錄下找到一些例子以及編譯程序所需的庫文件和源文件,這些文件在編譯是很重要。
單獨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創建一個工程,如下圖所示,注意紅圈部分的設置:
![clip_image002[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image002%5B7%5D_thumb.jpg)
然后設置文件,模板:
![clip_image003[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image003%5B7%5D_thumb.jpg)
其余按默認完成即可:
![clip_image004[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image004%5B7%5D_thumb.jpg)
這時,我們可以看到Parser Generator幫我們自動生成了一個myparser.y文件,語法規則就可以在這里加了。
![clip_image005[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image005%5B7%5D_thumb.jpg)
現在我們把開頭展示的yacc源碼完全覆蓋myparser.y文件,然后編譯,成功后會生成三個文件:myparser.c,myparser.h,myparser.v
好,現在我們要做的就是用vc來編譯myparser.c,myparser.h這兩個文件了。
打開Microsoft Visual C++ 6.0,新建一個工程。
![clip_image006[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image006%5B7%5D_thumb.jpg)
然后將Parser Generator生成的兩個文件myparser.c,myparser.h導入工程。(這里就不多說了^-^)
現在要設置環境變量了,首先要導入Parser Generator的庫文件和源文件。在工具->選項里要設置這些環境變量。
![clip_image007[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image007%5B7%5D_thumb.jpg)
![clip_image008[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image008%5B7%5D_thumb.jpg)
![clip_image009[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image009%5B7%5D_thumb.jpg)
設置完這些文件后,還要在工程->設置里添加yl.lib庫:
![clip_image010[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image010%5B7%5D_thumb.jpg)
好,一切設置完畢,開始編譯,編譯通過后,就會生成yacc_vc.exe文件。
假設有文件demo.txt,此文件和yacc_vc.exe在同一個目錄,其內容如下:
1+3*5
3*4-23
7- 9 *30 - 999
在此目錄的命令行下運行如下命令:yacc_vc.exe <demo.txt,即可得到計算結果:
![clip_image011[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image011%5B7%5D_thumb.jpg)
單獨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新建一個工程:
![clip_image012[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image012%5B7%5D_thumb.jpg)
![clip_image013[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image013%5B7%5D_thumb.jpg)
下一步默認完成即可。這時,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創建新的工程:
![clip_image014[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image014%5B7%5D_thumb.jpg)
![clip_image015[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image015%5B7%5D_thumb.jpg)
![clip_image016[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image016%5B7%5D_thumb.jpg)
其余的步驟和上面編譯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得到:
![clip_image017[7]](http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/yacclexwindowsParserGenerator_FB8B/clip_image017%5B7%5D_thumb.jpg)
以上即為Parser Generator的使用以及如何用VC編譯。
/
/*-----Lex & Yacc ----www.linmu100.com ----*/
/
/*-----linux工具,Lex & Yacc,windows下操作----*/
/
/*-----linux配置,UNIX,開源軟件,linux技術,makefile----*/
/
/*----------------------@xiaolin--------------------*/