yacc学习笔记(五)支持数学函数的计算器程序

支持数学函数的计算器程序

为计算器生成的另一个指令是添加用于平方根、指数和对数的数学函数。以如下方式处理输入:
s2=sqrt(2)
s2=1.41421

二种实现方式:

方式一、

为每个函数添加单独的规则
例:
语法分析添加:

%token SQRT LOG EXP
。。。
%%
expression: ...
	|	SQRT '(' expression ')'  { $$=sqrt($3); }
	|	LOG  '(' expression ')'  { $$=log($3);  }
	|	EXP  '(' expression ')'  { $$=exo($3);  }

词法分析添加:

sqrt  return SQRT;
log   return LOG;
exp  return EXP;
[A-Za-z][A-Za-z0-9]*    { ...... }

(匹配函数名的特定模式要在前面,它们要比一般标识符匹配的要早。)

这种实现的缺点:
1、每个函数硬编码到词法分析程序和语法分析程序中,这样会比较冗长,而且很难添加更多的函数;
2、函数名是保留字,不能将sqrt再做为变量名;

方式二:

从词法分析程序中拿出函数名采用的特定模式并将它们放入符号表。给每个符号表条目添加新的字段funcptr,如果这个条目是函数名,那么它就是调用c函数的指针。

struct symtab {
	char *name;
	double (*funcprt)();
	double value;
}symtab[NSYMS];

在开始分析程序前必须先将函数名放进符号表,所以需要在main函数中添加代码,调用函数addfunc()将每个函数名添加到符号表,然后调用yyparse()。

int main(){
	extern double sqrt(),exp(),log();
	addfunc("sqrt",sqrt);
	addfunc("exp",exp);
	addfunc("log",log);
    yyparse();
    return 0;
}

void addfunc(char *name,double (*func)()){
        struct symtab *sp=symlook(name);
        sp->funcptr=func;
}

最终的程序代码:

最终的计算器头文件ch3hdr2.h


#define NSYMS 20        /* maximum number of symbols */

struct symtab {
        char *name;
        double (*funcptr)();
        double value;
}symtab[NSYMS];

struct symtab *symlook(char *s);

最终的计算器语法分析程序ch3-5.y

%{
#include "stdio.h"
#include "ch3hdr2.h"
#include <string.h>
#include <math.h>
%}

%union {
        double  dval;
        struct symtab *symp;
}

%token <symp> NAME
%token <dval> NUMBER
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS

%type <dval> expression

%%
statement_list: statement '\n'
        |       statement_list statement '\n'

statement:      NAME '=' expression     { $1->value=$3; }
        |       expression              { printf("=%g\n",$1); }
        ;

expression:     expression '+' expression       { $$=$1+$3; }
        |       expression '-' expression       { $$=$1-$3; }
        |       expression '*' expression       { $$=$1*$3; }
        |       expression '/' expression
        { if($3==0.0)
                yyerror("divided by zero.\n");
          else
                $$=$1 / $3;
        }
        |       '-' expression %prec UMINUS     { $$ = -$2; }
        |       '(' expression ')'              { $$ = $2; }
        |       NUMBER                          { $$ = $1; }
        |       NAME                            { $$ = $1->value; }
        |       NAME '(' expression ')'
                {
                        if($1->funcptr)
                                $$=($1->funcptr)($3);
                        else {
                                printf("%s is not a function.\n",$1->name);
                                $$=0.0;
                        }
                }
        ;

%%
void yyerror(char *s);
struct symtab *symlook(char *s){
        char *p;
        struct symtab *sp;

        for(sp=symtab;sp<&symtab[NSYMS];sp++){
                if(sp->name && !strcmp(sp->name,s))
                        return sp;
                if(!sp->name){
                        sp->name=strdup(s);
                        return sp;
                }
        }
        yyerror("Too many symbols.");
        exit(1);
}

void addfunc(char *name,double (*func)()){
        struct symtab *sp=symlook(name);
        sp->funcptr=func;
}

int main(){
        extern double sqrt(),exp(),log();

        addfunc("sqrt",sqrt);
        addfunc("exp",exp);
        addfunc("log",log);
        yyparse();
        return 0;
}

void yyerror(char *s){
        fprintf(stderr,"%s\n",s);
}


最终的词法分析程序ch3-5.l


%{
#include "y.tab.h"
#include "ch3hdr.h"
#include <math.h>
#undef yywrap
%}

%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)     {
                yylval.dval = atof(yytext);
                return NUMBER;
        }
[ \t] ;
[A-Za-z][A-Za-z0-9]*    {
                struct symtab *sp=symlook(yytext);
                yylval.symp=sp;
                return NAME;
        }
"$"     { return 0; }
\n      |
.       return yytext[0];
%%

int yywrap()
{
        return 1;
}


程序编译及运行:

[postgre@host132 ch3]$ yacc -d ch3-5.y
[postgre@host132 ch3]$ lex ch3-5.l
[postgre@host132 ch3]$ cc -o test lex.yy.c y.tab.c -lm
[postgre@host132 ch3]$ ./test
sqrt(3)
=1.73205
foo(3)
foo is not a function.
=0
sqrt=5
sqrt(sqrt)
=2.23607
log(4)
=1.38629
sqrt(4)
=2

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值