C指針原理教程之編譯原理-小型計(jì)算器實(shí)現(xiàn)
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文件,在第二部分加入更多的語(yǔ)法規(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ì)算器程序,讓算式能顯示出來(lái),修改calculator.l
通過(guò)加入printf語(yǔ)句,打印詞法分析器解析到的字符。比如 :
..................
[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
接下來(lái)加上讀取的行號(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#
欄 目:C語(yǔ)言
下一篇:C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單翻譯功能
本文標(biāo)題:C指針原理教程之編譯原理-小型計(jì)算器實(shí)現(xiàn)
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/474.html
您可能感興趣的文章
- 01-10深入理解數(shù)組指針與指針數(shù)組的區(qū)別
- 01-10基于C++輸出指針自增(++)運(yùn)算的示例分析
- 01-10解析sizeof, strlen, 指針以及數(shù)組作為函數(shù)參數(shù)的應(yīng)用
- 01-10探討C++中數(shù)組名與指針的用法比較分析
- 01-10深入理解雙指針的兩種用法
- 01-10libxml教程(圖文詳解)
- 01-10C語(yǔ)言數(shù)組指針的小例子
- 01-10基于SVN源碼服務(wù)器搭建(詳細(xì)教程分析)
- 01-10解析如何用指針實(shí)現(xiàn)整型數(shù)據(jù)的加法
- 01-10深入const int *p與int * const p的區(qū)別詳解(常量指針與指向常量的指


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置


