Lex&yacc简单计算器

本文介绍了一个简单的符号表及语法解析器的实现过程。该解析器能够处理数学表达式,支持基本算术运算和一些预定义的数学函数,如sin、cos等,并通过词法分析和语法分析实现了表达式的求值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

symtab.h
 
 #define NSYMS 20 /* max number of symbols */
 struct symtab 
 {
    char *name;
    double (*funcptr)();
    double value;
 } symtab[NSYMS];
 struct symtab *symlook(char*);
/*************************************************************/
 
y.tab.h
 
#define PIVAL 257
#define NAME 258
#define NUMB 259
#define UMINUS 260
#ifdef YYSTYPE
#undef  YYSTYPE_IS_DECLARED
#define YYSTYPE_IS_DECLARED 1
#endif
#ifndef YYSTYPE_IS_DECLARED
#define YYSTYPE_IS_DECLARED 1
typedef union 
 {
    double dval;
    struct symtab *symp;
 } YYSTYPE;
#endif /* !YYSTYPE_IS_DECLARED */
extern YYSTYPE yylval;
/*************************************************************/
 
lex.l
 
%{
 
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "symtab.h"
#include "y.tab.h"
%}
 
%%
 
pi          return PIVAL;
[ t] ;
[A-Za-z][A-Za-z0-9]*        {yylval.symp = symlook(yytext); return NAME;}
([0-9]+|([0-9]*.[0-9]+)([eE][-+]?[0-9]+)?)  {yylval.dval = atof(yytext); return NUMB;}
"$"         return 0; 
n           |
.       return yytext[0];
%%
 
int yywrap(void)
{
    return 1;
}
/*************************************************************/
 
yacc.y
 
 %{
    #include "symtab.h"
    #include <string.h>
    #include <math.h>
    #include <stdlib.h>
    #include <stdio.h>
 
    int nsym = 0;
 %}
  
 %union 
 {
    double dval;
    struct symtab *symp;
 }
 %token PIVAL
 %token <symp> NAME
 %token <dval> NUMB
 %left '+' '-'
 %left '*' '/'
 %nonassoc UMINUS
 %type <dval> expr
  
 %%
 
 line   : stmt 'n'
    | line stmt  'n'
    ;
 stmt   : NAME '=' expr {$1->value=$3;}
    | expr { printf("=%gn", $1);}
    ;
 expr   : expr '+' expr {$$ = $1 +$3;}
    | expr '-' expr {$$ = $1 - $3;}
    | expr '*' expr {$$ = $1 * $3;}
    | expr '/' expr 
      {
        if($3==0.0) 
            yyerror("Divided by zero!n");
        else 
            $$ = $1 / $3;
      }
    | '-' expr %prec UMINUS {$$ = -$2;}
    | '(' expr ')' {$$ = $2;}
    | NUMB
    | NAME {$$ = $1->value;}
    | NAME '(' expr ')' 
      {
        if ($1->funcptr) 
            $$ = ($1->funcptr)($3);
        else
        {
            printf("%s is not a function!n", $1->name);
            $$ = 0.0;
        }
      }
    | NAME '(' expr ',' expr ')' 
      {
        if ($1->funcptr)
             $$ = ($1->funcptr)($3, $5);
        else
        {
            printf("%s is not a function!n", $1->name);
            $$ = 0.0;
        }
       }
    | PIVAL {$$ = M_PI;}
    ;
 %%
 int yyerror (char *err)
 {  
    fprintf(stderr, "%s", err);  
 }  
 struct symtab *symlook(char *s)
 {
    int i;
    for (i = 0; i < nsym; ++i)
    {
        if (!strcmp(symtab[i].name, s))
            return &symtab[i];
    }
    if (nsym < NSYMS)
    {
        symtab[nsym].name = strdup(s);
        ++nsym;
        return &symtab[nsym-1];
    }
    yyerror("Too many symbols!n");
    exit(1);
 }
  
 void addfunc( char *name, double(*func)() ) 
 {
    struct symtab *sp = symlook(name);
    sp->funcptr = func;
 }
 
 int main(void)
 {
    extern double pow(), sqrt(), log(), exp(), sin(), cos(), tan();
     
    addfunc("pow", pow);
    addfunc("sqrt", sqrt);
    addfunc("log", log);
    addfunc("exp", exp);
    addfunc("sin", sin);
    addfunc("cos", cos);
    addfunc("tan", tan);
    yyparse();
    return 0;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值