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

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

下面完成一個簡單的計算器通過語法樹進行計算,首先定義一個語法樹的結構,然後編寫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 %