C指針原理(10)-編譯原理-小型計算器實現
2、首先,在home目錄中新建文件夾,在文件夾中放置如下內容的test1.l
/*統計字數*/ %{ int?chars=0; int?words=0; int?lines=0; %} %% [a-zA-Z]+??{words++;chars+=strlen(yytext);} \n??{chars++;lines++;} .???{chars++;} %% main(int?argc,char**argv) { ???yylex(); ???printf("%d%d%d\n",lines,words,chars); }
然後調用flex生成詞法分析器
Administrator@2012-20121224HD?/home/flexlinux
$?cd?/home
Administrator@2012-20121224HD?/home
$?cd?flexlinux
Administrator@2012-20121224HD?/home/flexlinux
$?flex?test1.l
Administrator@2012-20121224HD?/home/flexlinux
$
可以看到目錄中的lex.yy.c就是剛生成的C源碼,可分析詞法。
Administrator@2012-20121224HD?/home/flexlinux
$?ls
lex.yy.c??test1.l
二、flex和bison聯合工作
本博客所有內容是原創,如果轉載請註明來源
http://blog.csdn.net/myhaspl/
1?、我們開始構造一個計算器程序。
創建flex代碼
/*計算器*/ %{ enum?yytokentype{ ?????NUMBER=258, ?ADD=259, ?SUB=260, ?MUL=261, ?DIV=262, ?ABS=263, ?EOL=264 }; int?yylval; %} %% "+"???{return?ADD;} "-"???{return?SUB;} "*"???{return?MUL;} "/"???{return?DIV;} "|"???{return?ABS;} [0-9]+?{yylval=atoi(yytext);return?NUMBER;} \n??{return?EOL;} [?\t]?{/*空白忽略*/} .?{printf("非法字符?%c\n",*yytext);} %% main(int?argc,char**argv) { ???int?tok; ???while(tok=yylex()){ ??????printf("%d",tok); ??if?(tok==NUMBER)?printf("=%d\n",yylval); ??else?printf("\n"); ???} }
2、編譯
Administrator@2012-20121224HD?/home/flexlinux
$?flex?test2.l
Administrator@2012-20121224HD?/home/flexlinux
$?gcc?lex.yy.c?-lfl
3、運行
Administrator@2012-20121224HD?/home/flexlinux
$?./a
-?12?66
260
258=12
258=66
264
Administrator@2012-20121224HD?/home/flexlinux
$?./a
/?56?2?+?|32
262
258=56
258=2
259
263
258=32
264
Administrator@2012-20121224HD?/home/flexlinux
$
(2)計算器的BISON程序
%{
#include <stdio.h>
%}
%token NUMBER
%token ADD SUB MUL DIV ABS
%token EOL
%%
calclist:/**/
|calclist exp EOL{printf ("=%d\n",$2);}
;
exp:factor {$$ = $1;}
|exp ADD factor{$$=$1+$3;}
|exp SUB factor{$$=$1-$3;}
;
factor:term {$$=$1;}
|factor MUL term{$$=$1*$3;}
|factor DIV term{$$=$1/$3;}
;
term:NUMBER {$$=$1;}
|ABS term {$$=$2>=0?$2:-$2;}
;
%%
main(int argc,char **argv){
yyparse();
}
yyerror(char *s)
{
fprintf(stderr,"error:%s\n",s);
}
$ bison -d test2.y
t$ ls
test2.tab.c? test2.tab.h? test2.y? test2.y~
然後,修改剛才的flex文件,將其命名為test21.l
test2.tab.h中包含了記號編號的定義和yylval的定義,因此,將其第一部分的相關定義刪除,並改為:
/計算器/
%{
??#include?"test2.tab.h"
%}
然後刪除,其第三部分的main函數。
最後,進行編譯。
bison?-d?test2.y
flex?test21.l
gcc?test2.tab.c?lex.yy.c?-lfl
可以測試一下
root@myhaspl:~#?./a.out
12?+?36?*?2
=84
12?/?6?+?2?*?3
=8
(2)擴充計算器
加入對括號和註釋的支持,
首先修改flex文件,在第二部分加入更多的詞法規則(對於註釋直接忽略):
"("???{return?LEFTBRACKET;}
")"???{return?RIGHTBRACKET;}
"#".?/忽略註釋*/
然後,修改bison文件,在第二部分加入更多的語法規則:
term:NUMBER?{$$=$1;}
??|ABS?term?{$$=$2>=0?$2:-$2;}
??|LEFTBRACKET?exp?RIGHTBRACKET?{$$=$2;}
??;
我們的註釋以“#”表示
測試結果
myhaspl@myhaspl:~/flex_bison/2$?make
bison?-d?calculator.y
flex?calculator.l
gcc?calculator.tab.c??lex.yy.c?-lfl
myhaspl@myhaspl:~/flex_bison/2$?ls
a.out?????????calculator.tab.c??calculator.y??makefile
calculator.l??calculator.tab.h??lex.yy.c
myhaspl@myhaspl:~/flex_bison/2$?./a.out
12-36*10/(1+2+3)#compute
=-48
^C
myhaspl@myhaspl:~/flex_bison/2$?
前面都是以鍵盤輸入 的方式進行計算器運算,我們下面以文件方式提供給該解釋器進行計算,首先,將flex文件改為(將其中中文去除,然後對於非法字符的出現進行忽略):
%{
#include "calculator.tab.h"
%}
%%
"+" ? {return ADD;}
"-" ? {return SUB;}
"" ? {return MUL;}
"/" ? {return DIV;}
"|" ? {return ABS;}
"(" ? {return LEFTBRACKET;}
")" ? {return RIGHTBRACKET;}
"#". /comment/
[0-9]+ {yylval=atoi(yytext);return NUMBER;}
\n ?{return EOL;}
[ \t] /blank/
. /invalid char/
%
接著,改bison文件,加入對文件的讀寫
%{
#include <stdio.h>
%}
%token NUMBER
%token ADD SUB MUL DIV ABS LEFTBRACKET RIGHTBRACKET
%token EOL?
%%
calclist:/**/
? |calclist exp EOL{printf ("=%d\n",$2);}
? ;
??
exp:factor {$$ = $1;}
? |exp ADD factor{$$=$1+$3;}
? |exp SUB factor{$$=$1-$3;}
? ;
?
?
factor:term {$$=$1;}
? |factor MUL term{$$=$1*$3;}
? |factor DIV term{$$=$1/$3;}
? ;
term:NUMBER {$$=$1;}
? |ABS term {$$=$2>=0?$2:-$2;}
? |LEFTBRACKET exp RIGHTBRACKET {$$=$2;}
? ;
%%
main(int argc,char **argv){
int i;
if (argc<2){
? ?yyparse();
}
else{
? ?for(i=1;i<argc;i++)
? ? ? ?{
? ? ? ?FILE *f=fopen(argv[i],"r");
? ? ? ?if (!f){
? ? ? ? ? perror(argv[i]);
? ? ? ? ? return (1);
? ? ? ?}
? ? ? yyrestart(f);
? ? ? yyparse();
? ? ? fclose(f);
? ?}
}
}
yyerror(char *s)
{
? fprintf(stderr,"error:%s\n",s);
}
最後 測試一下
root@myhaspl:~/test/3# make
bison -d calculator.y
flex calculator.l
gcc calculator.tab.c ?lex.yy.c -lfl
root@myhaspl:~/test/3# ./a.out mycpt1.cpt mycpt2.cpt
=158
=-8
root@myhaspl:~/test/3#?
其中兩個CPT文件內容類似 為:
12*66/(10-5)
C指針原理(10)-編譯原理-小型計算器實現