1. 程式人生 > >C指針原理(27)-編譯基本原理-語法樹及其實現7

C指針原理(27)-編譯基本原理-語法樹及其實現7

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