继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

C指针原理(10)-编译原理-小型计算器实现

holdtom
关注TA
已关注
手记 1703
粉丝 240
获赞 991


、打开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联合工作

本博客所有内容是原创,如果转载请注明来源

http://blog.csdn.net/myhaspl/

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)

©著作权归作者所有:来自51CTO博客作者myhaspl的原创作品,如需转载,请注明出处,否则将追究法律责任


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP