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

、打开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生成词法分析器

Ad[email protected]?/home/flexlinux

$?cd?/home

[email protected]?/home

$?cd?flexlinux

[email protected]?/home/flexlinux

$?flex?test1.l

[email protected]?/home/flexlinux

$

可以看到目录中的lex.yy.c就是刚生成的C源码,可分析词法。

[email protected]?/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、编译

[email protected]?/home/flexlinux

$?flex?test2.l

[email protected]?/home/flexlinux

$?gcc?lex.yy.c?-lfl

3、运行

[email protected]?/home/flexlinux

$?./a

-?12?66

260

258=12

258=66

264

[email protected]?/home/flexlinux

$?./a

/?56?2?+?|32

262

258=56

258=2

259

263

258=32

264

[email protected]?/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

可以测试一下

[email protected]:~#?./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;}

??;

我们的注释以“#”表示

测试结果

[email protected]:~/flex_bison/2$?make

bison?-d?calculator.y

flex?calculator.l

gcc?calculator.tab.c??lex.yy.c?-lfl

[email protected]:~/flex_bison/2$?ls

a.out?????????calculator.tab.c??calculator.y??makefile

calculator.l??calculator.tab.h??lex.yy.c

[email protected]:~/flex_bison/2$?./a.out

12-36*10/(1+2+3)#compute

=-48

^C

[email protected]:~/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);
}

最后 测试一下

[email protected]:~/test/3# make
bison -d calculator.y
flex calculator.l
gcc calculator.tab.c ?lex.yy.c -lfl
[email protected]:~/test/3# ./a.out mycpt1.cpt mycpt2.cpt
=158
=-8
[email protected]:~/test/3#?

其中两个CPT文件内容类似 为:

12*66/(10-5)

原文地址:http://blog.51cto.com/13959448/2324501

时间: 2024-08-29 09:56:39

C指针原理(10)-编译原理-小型计算器实现的相关文章

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

我们接着完善这个计算器程序,让算式能显示出来,修改calculator.l 我们接着完善这个计算器程序,让算式能显示出来,修改calculator.l 通过加入printf语句,打印词法分析器解析到的字符.比如 : .................. [0-9]+?{yylval=atoi(yytext);printf("%d",yylval);return?NUMBER;} \n??{return?EOL;} [?\t]?/blank/ .?/invalid?char/ %% 然后

0909对编译原理的初了解

1.编译原理学什么? "编译原理":研究设计和构造编译程序原理和方法以及主要实现技术.其中蕴含着计算机科学中解决问题的思路.形式化问题和解决问题的方法.通过本课程的学习,使学生掌握编译理论和方法方面的基本知识,同时也获得设计.实现.分析和移植编译程序方面的初步能力. 编译原理(第3版)共10章,内容包括语言及文法的基本知识.词法分析.语法分析.语义分析及中间代码生成.符号表组织.运行时的存储组织与分配.代码优化及目标代码生成等.此外编译原理是一门实践性较强的课程,要联系实际,多看实验参

浅谈编译原理

什么是编译原理? 编译原理顾名思义,编译就是将源语言(高级程序语言)翻译成等价的目标语言(机器语言即计算机可以识别的语言即0和1或汇编语言)的过程.原理就是研究这一过程的思想方法.理论和技术.从本质上来讲编译是一个算法问题,但由于它的问题相当复杂,导致设计解决这个问题的算法也十分复杂.这里的算法和我们学习的数据结构和算法中的算法有些不同,后者讲述的是基础算法,是解决我们生活中遇到的问题,而编译中的算法则是在人与计算机交流时需要解决的“沟通”问题的算法,比较专注解决一种的算法.编译的过程包括:源程

编译原理 词法分析

原文地址:编译原理 词法分析 编译原理 词法分析 词法分析的主要任务是从左至右逐个字符地对源程序进行扫描,产生一个个单词序列,用于语法分析. 1.正则表达式 对给定的字符集∑={c1,c2,...,cn},归纳定义: 1.空串ε是正则表达式 2.对于任意c∈∑,c是正则表达式 3.如果M和N是正则表达式,则下列表达式也是正则表达式 (1)选择 M|N={M,N} (2)连接 MN={mn|m∈M,n∈N} (3)闭包 M*={ε,M,MM,MMM,...} 2.正则表达式的扩展 (1)[c1-c

0909走进编译原理

1.编译原理学什么? 编译原理这一学科,主要学习的是编译器方面的原理与技术,我们能从中学会各种算法与代码的原理,明白计算机是如何“听懂人话”,我们的代码是如何经过编译器转换成机器语言,这样不仅能实现自己去编写简单的小编译器,也能通过此学科去接触已有各编译器的思想,认识到编程方面更多要注意的问题以及解决的方向,站在本质的角度看代码,从而更能成就计算机专业人员的计算机逻辑思维. 2.为什么要学编译原理? 说到编译原理,人们喜欢把这门学科比作人体解剖和造轮子,是计算机中和代码作斗争的一门学科.据本人理

0909对编译原理的理解

1.编译原理学什么? 编译原理旨在让人们学习编译程序构造的一般原理和基本方法.内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成,而且这门课程关注的是编译器方面的产生原理和技术问题.回归到本质上,学习编译原理其实也就是学习一个相对复杂的算法. 2.为什么学编译原理? 编译原理这门课程实际蕴含着计算机学科中解决问题的思路.形式化问题和解决问题的方法,这些思路和方法除了对应用软件和系统软件的设计与开发有一定的启发和指导作用外,在提倡学科的交叉不断创新

0909 初遇编译原理

编译原理学什么?      编译原理是一门研究设计和构造编译程序原理和方法的课程,是计算机各专业的一门重要专业基础课.编译原理主要学习的是编译程序结构及各部分功能.文法和语言         的基本概念和表示.词法分析.语法分析.属性文法与语法制导翻译技术.符号表.运算时存储空间的组织.代码优化与目标代码生成.并行编译技术概述等. 为什么学编译原理?      编译原理这门课程实际蕴含蕴含着计算机学科中解决问题的思路.形式化问题和解决问题的方法,这些思路和方法除了对应用软件和系统软件的设计与开发

软考-程序设计语言基础(编译原理)

首先声明一下,本系列软考的文章是针对软件设计师(中级)的. 在软件设计师考试中,关于程序设计语言这一章节,前面的知识很基础,像一些控制结构和数据类型的知识我想大家都非常熟练就没有总结在图里. 本章节的重点内容在于编译原理,编译原理指的是编译器是将汇编或高级计算机语言翻译为二进制机器语言代码的计算机程序.内容主要包括文法.正规式.有限自动机.语法推导树. 好了,不多说,还是老规矩用图来介绍. 重点看一下编译原理,展开前三项看看. 文法,是描述语法结构的形式规则: 正规式是描述程序语言单词的表达式,

编译原理 141

什么是编译原理? 编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法.也是将程序语言进行翻译,生成可供用户直接执行的二进制代码,即可执行文件.这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的 必修课程,编译原理及技术从本质上来讲就是一个算法问题. 学习编译原理有什么好处? 这门课是一门真正与代码做斗争的课程,对于一个有至于追求技术的人是不容错过的课程,而且编译原理可以说是一个计算机科学的缩影.可以用语法分析