C指针原理(10)-编译原理-小型计算器实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);}
??{chars++;lines++;}
.???{chars++;}
%%
main(int?argc,char**argv)
{
???yylex();
???printf("%d%d%d
",lines,words,chars);
}
然后调用flex生成词法分析器
[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;}
??{return?EOL;}
[? ]?{/*空白忽略*/}
.?{printf("非法字符?%c
",*yytext);}
%%
main(int?argc,char**argv)
{
???int?tok;
???while(tok=yylex()){
??????printf("%d",tok);
??if?(tok==NUMBER)?printf("=%d
",yylval);
??else?printf("
");
???}
}
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
",$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
",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;}
?{return EOL;}
[ ] /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
",$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
",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)
以上是关于C指针原理(10)-编译原理-小型计算器实现的主要内容,如果未能解决你的问题,请参考以下文章
编译原理构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 7.)(笔记)解释器 interpreter 解析器 parser 抽象语法树AST(代码片