C语言指针原理教程:编译原理-小型计算器代码实现

2019-02-0814:33:30编程语言入门到精通Comments2,798 views字数 4640阅读模式
如何使用C语言编写一个小型计算器的实例代码,有需要的小伙伴可以参考下

1、打开cygwin,进入home目录,home目录在WINDOWS系统的cygwin安装目录映射为home目录。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

2、首先,在home目录中新建文件夹,在文件夹中放置如下内容的test1.l文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

/*统计字数*/

%{

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生成词法分析器文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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源码,可分析词法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

Administrator@2012-20121224HD /home/flexlinux

$ ls

lex.yy.c test1.l

二、flex和bison联合工作文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

1 、我们开始构造一个计算器程序。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

创建flex代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

/*计算器*/

%{

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、编译文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

Administrator@2012-20121224HD /home/flexlinux

$ flex test2.l

Administrator@2012-20121224HD /home/flexlinux

$ gcc lex.yy.c -lfl

3、运行文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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程序文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%{
#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文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

test2.tab.h中包含了记号编号的定义和yylval的定义,因此,将其第一部分的相关定义删除,并改为:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

/计算器/文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

#include "test2.tab.h"文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

然后删除,其第三部分的main函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

最后,进行编译。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

bison -d test2.y

flex test21.l

gcc test2.tab.c lex.yy.c -lfl

可以测试一下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

root@myhaspl:~# ./a.out

12 + 36 * 2

=84

12 / 6 + 2 * 3

=8

(2)扩充计算器文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

加入对括号和注释的支持,文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

首先修改flex文件,在第二部分加入更多的词法规则(对于注释直接忽略):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

"("   {return LEFTBRACKET;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

")"   {return RIGHTBRACKET;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

"#". /忽略注释*/文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

然后,修改bison文件,在第二部分加入更多的语法规则:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

term:NUMBER {$$=$1;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

|ABS term {$$=$2>=0?$2:-$2;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

|LEFTBRACKET exp RIGHTBRACKET {$$=$2;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

我们的注释以“#”表示文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

测试结果文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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文件改为(将其中中文去除,然后对于非法字符的出现进行忽略):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%{
#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文件,加入对文件的读写文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%{
#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);
}

最后 测试一下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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文件内容类似 为:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

12*66/(10-5)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

我们接着完善这个计算器程序,让算式能显示出来,修改calculator.l文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

通过加入printf语句,打印词法分析器解析到的字符。比如 :文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

..................文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

[0-9]+ {yylval=atoi(yytext);printf("%d",yylval);return NUMBER;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

\n  {return EOL;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

[ \t] /blank/文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

. /invalid char/文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

%%文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

然后编译执行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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

接下来加上读取的行号,将结果的显示更加人性化文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

flex文件要改:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

\n  {printf("<line:%4d>",yylineno);yylineno++;return EOL;}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

然后,bison文件也改:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

calclist:/**/
|calclist exp EOL{printf ("the result is:%d\n",$2);}
;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

最后 ,编译运行测试一下。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html

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#
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/9466.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/ymba/9466.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定