这篇文章将为大家详细讲解有关C中如何编译小型计算器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
1、打开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.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)
我们接着完善这个计算器程序,让算式能显示出来,修改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:%4d>",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中如何编译小型计算器”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。