C指標原理(27)-編譯基本原理-語法樹及其實現7
阿新 • • 發佈:2019-01-01
下面完成一個簡單的計算器通過語法樹進行計算,首先定義一個語法樹的結構,然後編寫flex檔案,解析數字或符號,對於 符號返回本身,對於數字,返回NUMBER,並對yylval的d進行賦值,yylval指向一個聯合型別,接著,在語法分析器中完成語法樹的節點的增加,分別對應數字和符號有不同的增加方式,最後有一個單獨的C程式碼處理計算,以及語法樹相關計算的函式。對結果的計算的方式是對語法樹進行遞迴。
詞法分析器為:
[email protected]:~/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);} %%
語法分析器為:
[email protected]:~/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);} ; %%
然後標頭檔案 為:
[email protected]:~/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程式碼檔案的內容為:
[email protected]:~/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檔案為:
[email protected]:~/flexbison % cat makefile
myjs:myast.l myast.y myast.h
bison -d myast.y
flex -omyast.lex.c myast.l
cc -o [email protected] myast.tab.c myast.lex.c myastfunc.c
[email protected]:~/flexbison %
執行效果如下
[email protected]:~/flexbison % ./myjs
$ 12+99
= 111
$11*(9-3)+6/3
= 68
$Q
[email protected]:~/flexbison %