C指针原理(27)-编译基本原理-语法树及其实现7

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

}


?{return?EOL;}

"//".*

[?	]?{}

"Q"?{exit(0);}

.?{sprintf(buffer,"invalid?character?%c
",*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
",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
",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
",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

[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?%?

以上是关于C指针原理(27)-编译基本原理-语法树及其实现7的主要内容,如果未能解决你的问题,请参考以下文章

读龙书学编译原理 语法翻译...

python实现算术表达式的词法语法语义分析(编译原理应用)

编译原理1----编译原理的基本概念

JavaScript的工作原理:解析抽象语法树(AST)+ 提升编译速度5个技巧

编译原理笔记7:语法分析(1)语法分析器的任务、语法错误的处理

golang编译原理