C指针原理(10)-编译原理-小型计算器实现
、打開cygwin,進入home目錄,home目錄在WINDOWS系統的cygwin安裝目錄映射為home目錄。
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聯合工作
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.yflex test21.lgcc test2.tab.c lex.yy.c -lfl可以測試一下root@myhaspl:~# ./a.out12 + 36 * 2=8412 / 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$ makebison -d calculator.yflex calculator.lgcc calculator.tab.c lex.yy.c -lflmyhaspl@myhaspl:~/flex_bison/2$ lsa.out calculator.tab.c calculator.y makefilecalculator.l calculator.tab.h lex.yy.cmyhaspl@myhaspl:~/flex_bison/2$ ./a.out12-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)
我們接著完善這個計算器程序,讓算式能顯示出來,修改calculator.l
我們接著完善這個計算器程序,讓算式能顯示出來,修改calculator.l
通過加入printf語句,打印詞法分析器解析到的字符。比如 :
…
[0-9]+ {yylval=atoi(yytext);printf("%d",yylval);return NUMBER;}
\n {return EOL;}
[ \t] /blank/
. /invalid char/
%%
然后編譯執行。
root@myhaspl:~/test/4# make
bison -d calculator.y
flex calculator.l
gcc calculator.tab.c lex.yy.c -lfl
root@myhaspl:~/test/4# ./a.out
12+66
12+66=78
^C
root@myhaspl:~/test/4# ./a.out mycpt1.cpt mycpt2.cpt
12*66/(10-5)=158
77/(10+1)-15=-8
接下來加上讀取的行號,將結果的顯示更加人性化
flex文件要改:
\n {printf(“line:M”,yylineno);yylineno++;return EOL;}
然后,bison文件也改:
calclist:/**/
|calclist exp EOL{printf (“the result is:%d\n”,$2);}
;
最后 ,編譯運行測試一下。
root@myhaspl:~/test/4# make
bison -d calculator.y
flex calculator.l
gcc calculator.tab.c lex.yy.c -lfl
root@myhaspl:~/test/4# ./a.out mycpt1.cpt mycpt2.cpt
1266/(10-5)<line: 1>the result is:158
12/22-8<line: 2>the result is:-8
77(6-2)<line: 3>the result is:308
77/(10+1)-15<line: 4>the result is:-8
root@myhaspl:~/test/4#
總結
以上是生活随笔為你收集整理的C指针原理(10)-编译原理-小型计算器实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 串口信息记到日志,[linu
- 下一篇: java用户角色权限管理 只显示姓_快递