您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)C中如何編譯小型計(jì)算器,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
1、打開cygwin,進(jìn)入home目錄,home目錄在WINDOWS系統(tǒng)的cygwin安裝目錄映射為home目錄。
2、首先,在home目錄中新建文件夾,在文件夾中放置如下內(nèi)容的test1.l
/*統(tǒng)計(jì)字?jǐn)?shù)*/ %{ 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); }
然后調(diào)用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聯(lián)合工作
1 、我們開始構(gòu)造一個(gè)計(jì)算器程序。
創(chuàng)建flex代碼
/*計(jì)算器*/ %{ 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、運(yùn)行
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)計(jì)算器的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中包含了記號(hào)編號(hào)的定義和yylval的定義,因此,將其第一部分的相關(guān)定義刪除,并改為:
/計(jì)算器/
%{
#include "test2.tab.h"
%}
然后刪除,其第三部分的main函數(shù)。
最后,進(jìn)行編譯。
bison -d test2.y flex test21.l gcc test2.tab.c lex.yy.c -lfl
可以測(cè)試一下
root@myhaspl:~# ./a.out 12 + 36 * 2 =84 12 / 6 + 2 * 3 =8
(2)擴(kuò)充計(jì)算器
加入對(duì)括號(hào)和注釋的支持,
首先修改flex文件,在第二部分加入更多的詞法規(guī)則(對(duì)于注釋直接忽略):
"(" {return LEFTBRACKET;}
")" {return RIGHTBRACKET;}
"#". /忽略注釋*/
然后,修改bison文件,在第二部分加入更多的語法規(guī)則:
term:NUMBER {$$=$1;}
|ABS term {$$=$2>=0?$2:-$2;}
|LEFTBRACKET exp RIGHTBRACKET {$$=$2;}
;
我們的注釋以“#”表示
測(cè)試結(jié)果
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$
前面都是以鍵盤輸入 的方式進(jìn)行計(jì)算器運(yùn)算,我們下面以文件方式提供給該解釋器進(jìn)行計(jì)算,首先,將flex文件改為(將其中中文去除,然后對(duì)于非法字符的出現(xiàn)進(jìn)行忽略):
%{ #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文件,加入對(duì)文件的讀寫
%{ #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); }
最后 測(cè)試一下
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#
其中兩個(gè)CPT文件內(nèi)容類似 為:
12*66/(10-5)
我們接著完善這個(gè)計(jì)算器程序,讓算式能顯示出來,修改calculator.l
通過加入printf語句,打印詞法分析器解析到的字符。比如 :
..................
[0-9]+ {yylval=atoi(yytext);printf("%d",yylval);return NUMBER;}
\n {return EOL;}
[ \t] /blank/
. /invalid char/
%%
然后編譯執(zhí)行。
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
接下來加上讀取的行號(hào),將結(jié)果的顯示更加人性化
flex文件要改:
\n {printf("<line:%4d>",yylineno);yylineno++;return EOL;}
然后,bison文件也改:
calclist:/**/
|calclist exp EOL{printf ("the result is:%d\n",$2);}
;
最后 ,編譯運(yùn)行測(cè)試一下。
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#
關(guān)于“C中如何編譯小型計(jì)算器”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。