C指針原理(27)-編譯基本原理-語法樹及其實現7
阿新 • • 發佈:2019-01-02
pac {} 返回 all calc null 原理 new 分析器 下面完成一個簡單的計算器通過語法樹進行計算,首先定義一個語法樹的結構,然後編寫flex文件,解析數字或符號,對於?符號返回本身,對於數字,返回NUMBER,並對yylval的d進行賦值,yylval指向一個聯合類型,接著,在語法分析器中完成語法樹的節點的增加,分別對應數字和符號有不同的增加方式,最後有一個單獨的C代碼處理計算,以及語法樹相關計算的函數。對結果的計算的方式是對語法樹進行遞歸。
詞法分析器為:
dp@dp:~/flexbison?%?cat?myast.l %option?noyywrap?nodefault?yylineno %{ #include?"myast.h" #include?"myast.tab.h" char?buffer[20]; %} EXP?([Ee][-+]?[0-9]+) %% "+"|"-"|"*"|"/"|"("|")"|"|"??{ return?yytext[0]; } [0-9]+"."[0-9]*{EXP}?|"."?[0-9]+{EXP}??{ yylval.d=atof(yytext); return?NUMBER; } \n?{return?EOL;} "//".* [?\t]?{} "Q"?{exit(0);} .?{sprintf(buffer,"invalid?character?%c\n",*yytext);?yyerror(buffer);}? %%
語法分析器為:
dp@dp:~/flexbison?%?cat?myast.y %{ #include?<stdio.h> #include?<stdlib.h> #include?"myast.h" %} %union{ struct?myast?*mya; double?d; } %token?<d>?NUMBER %token?EOL %type?<mya>?exp?factor?term %% calclist:|calclist?exp?EOL{ printf("=?%g\n",eval($2)); treefree($2); printf("$"); } |calclist?EOL{printf("$");} ; exp:factor|exp?‘+‘?factor?{$$=newast(‘+‘,$1,$3);} ???|exp?‘-‘?factor{$$=newast(‘-‘,$1,$3);} ; factor:term ??????|factor?‘*‘?term?{$$=newast(‘*‘,$1,$3);} ??????|factor?‘/‘?term?{$$=newast(‘/‘,$1,$3);} ; term:NUMBER{$$=newnum($1);} |‘|‘?term{$$=newast(‘|‘,$2,NULL);} |‘(‘?exp?‘)‘?{$$=$2;}??? |‘-‘?term?{$$=newast(‘M‘,$2,NULL);} ; %%
然後頭文件?為:
dp@dp:~/flexbison?%?cat?myast.h extern?int?yylineno; void?yyerror(char?*s); struct?ast{ int?nodetype; struct?ast?*l; struct?ast?*r; }; struct?numval{ int?nodetype; double?number; }; struct?ast?*newast(int?nodetype,struct?ast?*l,struct?ast?*r); struct?ast?*newnum(double?d); double?eval(struct?ast?*); void?treefree(struct?ast?*);
C代碼文件的內容為:
dp@dp:~/flexbison?%?cat?myastfunc.c
#include?<stdio.h>
#include?<stdlib.h>
#include?<stdarg.h>
#include?"myast.h"
struct?ast?*?newast(int?nodetype,struct?ast?*l,struct?ast?*r)
{
struct?ast?*a=malloc(sizeof(struct?ast));
if?(!a){
yyerror("out?of?space");
exit(0);
}
a->nodetype=nodetype;
a->l=l;
a->r=r;
return?a;
}
struct?ast?*?newnum(double?d)
{
struct?numval?*a=malloc(sizeof(struct?numval));
if?(!a)
{
yyerror("out?of?space");
exit(0);
}
a->nodetype=‘D‘;
a->number=d;
return?(struct?ast?*)a;
}
double?eval(struct?ast?*a){
double?v;
????????switch(a->nodetype){
case?‘D‘:v=((struct?numval?*)a)->number;break;
case?‘+‘:v=eval(a->l)+eval(a->r);break;
case?‘-‘:v=eval(a->l)-eval(a->r);break;
case?‘*‘:v=eval(a->l)*eval(a->r);break;
case?‘/‘:v=eval(a->l)/eval(a->r);break;
case?‘|‘:v=eval(a->l);v=v<0?v:-v;break;
case?‘M‘:v=-eval(a->l);break;
???? defaut:printf("bad?node:%c\n",a->nodetype); ?
}
??return?v;
}
void?treefree(struct?ast*a)
{
switch(a->nodetype){
case?‘+‘:
case?‘-‘:
case?‘*‘:
case?‘/‘:
treefree(a->r);
case?‘|‘:
case?‘M‘:
treefree(a->l);
case?‘D‘:
free(a);
break;
default:printf("free?bad?node?%c\n",a->nodetype);
}
}
void?yyerror(char?*s){
fprintf(stderr,"line?%d?error!:%s",yylineno,s);
}
int?main()
{
printf("$?");
return?yyparse();
}
Makefile文件為:
dp@dp:~/flexbison?%?cat?makefile
myjs:myast.l?myast.y?myast.h?
bison?-d?myast.y
flex?-omyast.lex.c?myast.l
cc?-o?$@?myast.tab.c?myast.lex.c?myastfunc.c
dp@dp:~/flexbison?%
運行效果如下
dp@dp:~/flexbison?%?./myjs
$?12+99
=?111
$11*(9-3)+6/3
=?68
$Q
dp@dp:~/flexbison?%?
C指針原理(27)-編譯基本原理-語法樹及其實現7