flex&bison 高级计算器

flex&bison 高级计算器

fb3_2.h

#ifndef _FB3_2_H_
#define _FB3_2_H_

extern int yylineno;
void yyerror(char *s, ...);

#define NHASH 9997

enum bifs {
    B_sqrt = 1,
    B_exp,
    B_log,
    B_print,
};

struct ast {
    int nodetype;
    struct ast *l;
    struct ast *r;
};

/* symbol */
struct symbol {
    char *name;
    double value;
    struct ast *func;
    struct symlist *syms; 
};

struct fncall {
    int nodetype;
    struct ast *l;
    struct symbol *s;
    int functype;
};

struct ufncall {
    int nodetype;
    struct ast *l;
    struct symbol *s;
};

struct symlist {
    struct symbol *sym;
    struct symlist *next;
};

struct flow {
    int nodetype;
    struct ast *cond;
    struct ast *tl;
    struct ast *el;
};

struct numval {
    int nodetype;
    double number;
};

struct symref {
    int nodetype;
    struct symbol *s;
};

struct symasgn {
    int nodetype;
    struct symbol *s;
    struct ast *v;
};

struct symbol symtab[NHASH];
struct symbol *lookup(char *name);


struct symlist *newsymlist(struct symbol *sym, struct symlist *next);
void symlistfree(struct symlist *sl);

struct ast *newast(int nodetype, struct ast *l, struct ast *r);
struct ast *newcmp(int cmptype, struct ast *l, struct ast  *r);
struct ast *newfunc(int functype, struct ast *l);
struct ast *newcall(struct symbol *s, struct ast *l);
struct ast *newref(struct symbol *s);
struct ast *newasgn(struct symbol *s, struct ast *v);
struct ast *newnum(double d);
struct ast *newflow(int nodetype, struct ast *cond, struct ast *tl, struct ast *tr);

void dodef(struct symbol *name, struct symlist *syms, struct ast *stmts);

double eval(struct ast *node);

void treefree(struct ast *node);
#endif

flex 文件 fb3_2.l

%option noyywrap nodefault yylineno
%{
    #include "fb3_2.h"
    #include "fb3_2.tab.h"
%}

EXP ([Ee][-+]?[0-9]+)

%%
"+" |
"-" |
"*" |
"/" |
"=" |
"|" |
"," |
";" |
"(" |
")" { return yytext[0]; }

">" {yylval.fn = 1; return CMP; } 
"<" {yylval.fn = 2; return CMP; }
"<>" {yylval.fn = 3; return CMP;}
"==" {yylval.fn = 4; return CMP;}
">=" {yylval.fn = 5; return CMP;}
"<=" {yylval.fn = 6; return CMP;}

"if" {return IF;}
"then" {return THEN;}
"else" {return ELSE;}
"while" {return WHILE;}
"do" {return DO;}
"let" {return LET;}

"sqrt" {yylval.fn = B_sqrt; return FUNC;}
"exp" { yylval.fn = B_exp; return FUNC;}
"log" { yylval.fn = B_log; return FUNC;}
"print" { yylval.fn = B_print; return FUNC;}

[a-zA-Z][a-zA-Z0-9]* {yylval.s = lookup(yytext); return NAME;}
[0-9]+"."[0-9]*{EXP}? | 
"."?[0-9]+{EXP}? {yylval.d = atof(yytext); return NUMBER;}

"//".* 
[ \t]
\\\n {printf("c> "); }

\n {return EOL; }

. {yyerror("mystery character %c\n", *yytext);}
%%

bison 文件 fb3_2.y

%{
#include <stdio.h>
#include <stdlib.h>
#include "fb3_2.h"

int yylex();
%}

%union {
    struct ast *a;
    double d;
    struct symbol *s;
    struct symlist *sl;
    int fn;
}

// define terminal charactor
%token <d> NUMBER
%token <s> NAME
%token <fn> FUNC
%token EOL

%token IF THEN ELSE WHILE DO LET

%nonassoc <fn> CMP
%right '='
%left  '+' '-'
%left '*' '/'
%nonassoc '|' UMINUS

//define no termimal charactor
%type <a> exp stmt list explist
%type <sl> symlist

%start calclist

%%
calclist: 
|calclist stmt EOL {
    printf("= %4.4g\n>", eval($2));
    treefree($2);
}
|calclist LET NAME '(' symlist ')' '=' list EOL {
    dodef($3, $5, $8);
    printf("Defined %s\n> ", $3->name);
}
| calclist error EOL {yyerrok; printf("> ");}

stmt: IF exp THEN list {
    $$ = newflow('I', $2, $4, NULL);
}
| IF exp THEN list ELSE list {
    $$ = newflow('I', $2, $4, $6);
}
| WHILE exp DO list { $$ = newflow('W', $2, $4, NULL);}
| exp
;

list: { $$ = NULL;}
| stmt ';' list {
    if ($3 == NULL)
        $$ = $1;
    else 
        $$ = newast('L', $1, $3);
};

exp: exp CMP exp { $$ = newcmp($2, $1, $3);}
    | exp '+' exp { $$ = newast('+', $1, $3);}
    | exp '-' exp { $$ = newast('-', $1, $3);}
    | exp '*' exp { $$ = newast('*', $1, $3);}
    | exp '/' exp { $$ = newast('/', $1, $3);}
    | '|' exp { $$ = newast('|', $2, NULL);}
    | '(' exp ')' { $$ = $2; }
    | '-' exp %prec UMINUS { $$ = newast('M', $2, NULL);}
    | NUMBER { $$ = newnum($1);}
    | NAME { $$ = newref($1);}
    | NAME '=' exp { $$ = newasgn($1, $3);}
    | FUNC '(' explist ')' { $$ = newfunc($1, $3);}
    | NAME '(' explist ')' {$$ = newcall($1, $3);}
    ;

explist: exp
| exp ',' explist {$$ = newast('L', $1, $3);}
;

symlist: NAME { $$ = newsymlist($1, NULL);}
| NAME ',' symlist {$$ = newsymlist($1, $3);}
;
%%

fb3_func.c

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include "fb3_2.h"
#include "fb3_2.tab.h"

static unsigned symhash(char *sym)
{
    unsigned int hash = 0;
    char c;

    while(c = *sym++)
        hash = hash*9 ^c;
    
    return hash;
}

struct symbol *lookup(char *sym)
{
    struct symbol *sp = &symtab[symhash(sym)%NHASH];
    int scount = NHASH;

    while(--scount >= 0) {
        if (sp->name && !strcmp(sp->name, sym)) {
            return sp;
        }

        if (!sp->name) {
            sp->name = strdup(sym);
            sp->value = 0;
            sp->func = NULL;
            sp->syms = NULL;
            return sp;
        }

        if (++sp >= symtab + NHASH) sp = symtab;
    }

    yyerror("symbol table overflow\n");
    abort();
}

struct ast *newast(int nodetype, struct ast *l, struct ast *r)
{
    struct ast *a = NULL;

    a = malloc(sizeof(struct ast));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }
    a->nodetype = nodetype;
    a->l = l;
    a->r = r;

    return a;
}

struct ast *newnum(double d)
{
    struct numval *a = NULL;

    a = malloc(sizeof(struct numval));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }

    a->nodetype = 'K';
    a->number = d;

    return (struct ast *)a;
}

struct ast *newcmp(int cmptype, struct ast *l, struct ast *r)
{
    struct ast *a = NULL;

    a = malloc(sizeof(struct ast));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }

    a->nodetype = '0' + cmptype;
    a->l = l;
    a->r = r;

    return a;
}

struct ast *newfunc(int functype, struct ast *l)
{
    struct fncall *a = NULL;

    a = malloc(sizeof(struct fncall));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }

    a->nodetype = 'F';
    a->l = l;
    a->functype = functype;
    return (struct ast *)a;
}

struct ast *newcall(struct symbol *s, struct ast *l)
{
    struct ufncall *a = NULL;

    a = malloc(sizeof(struct ufncall));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }
    a->nodetype = 'C';
    a->l = l;
    a->s = s;

    return (struct ast *)a;
}

struct ast *newref(struct symbol *s)
{
    struct symref *a = NULL;

    a = malloc(sizeof(struct symref));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    } 

    a->nodetype = 'N';
    a->s = s;
    return (struct ast *)a;
}

struct ast *newasgn(struct symbol *s, struct ast *v)
{
    struct symasgn *a = NULL;

    a = malloc(sizeof(struct symasgn));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }

    a->nodetype = '=';
    a->s = s;
    a->v = v;
    return (struct ast *)a;
}

struct ast *newflow(int nodetype, struct ast *cond, struct ast *tl, struct ast *el)
{
    struct flow *a = NULL;

    a = malloc(sizeof(struct flow));
    if (!a) {
        yyerror("out of space\n");
        exit(-1);
    }

    a->nodetype = nodetype;
    a->cond = cond;
    a->tl = tl;
    a->el = el;

    return (struct ast *)a;
}

void treefree(struct ast *a)
{
    switch(a->nodetype) {
        case '+': 
        case '-':
        case '*':
        case '/':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case 'L':
            treefree(a->r);

        case '|':
        case 'M':
        case 'C':
        case 'F':
            treefree(a->l);
        case 'K':
        case 'N': 
            break;
        case '=':
            free(((struct symasgn *)a)->v);
            break;
        case 'I': 
        case 'W':
            free(((struct flow *)a)->cond);
            if (((struct flow *)a)->tl)
                treefree(((struct flow *)a)->tl);
            if (((struct flow *)a)->el)
                treefree(((struct flow *)a)->el);
            break;
    default: 
            printf("internal error: free bad node %c\n", a->nodetype);
    }
    free(a);
}

struct symlist *newsymlist(struct symbol *sym, struct symlist *next)
{
    struct symlist *sl = NULL;

    sl = malloc(sizeof(struct symlist));
    if (!sl) {
        yyerror("out of space\n");
        exit(-1);
    }

    sl->sym = sym;
    sl->next = next;
    return sl;
}

void symlistfree(struct symlist *sl)
{
    struct symlist *nsl;

    while(sl) {
        nsl = sl->next;
        free(sl);
        sl = nsl;
    }
}

static double callbuiltin(struct fncall *tmp);
static double calluser(struct ufncall *tmp);

double eval(struct ast *a)
{
    double v;
    if(!a) {
        yyerror("internal error, null eval\n");
        return 0.0;
    }

    switch(a->nodetype) {
        case 'K': 
            v = ((struct numval *)a)->number;
            break;
        case 'N':
            v = ((struct symasgn *)a)->s->value;
            break;
        case '=': 
            v = ((struct symasgn *)a)->s->value = eval(((struct symasgn *)a)->v);
            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 = fabs(eval(a->l));
            break;
        case 'M':
            v = -eval(a->l);
            break;
        case '1':
            v = (eval(a->l) > eval(a->r))? 1:0;
            break;
        case '2':
            v = (eval(a->l) < eval(a->r))? 1: 0;
            break;
        case '3':
            v = (eval(a->l) != eval(a->r))? 1:0;
            break;
        case '4': 
            v = (eval(a->l) == eval(a->r))? 1:0;
            break;
        case '5':
            v = (eval(a->l) >= eval(a->r))? 1:0;
            break;
        case '6':
            v = (eval(a->l) <= eval(a->r))? 1:0;
            break;
        case 'I':
            if (eval(((struct flow *)a)->cond) != 0) {
                if (((struct flow *)a)->tl) {
                    v = eval( ((struct flow *)a)->tl);
                } else {
                    v = 0.0;
                }
            } else {
                if (((struct flow *)a)->el) {
                    v = eval(((struct flow *)a)->el);
                } else v = 0.0;
            }
            break;
        case 'W': 
            v = 0.0;
            if (((struct flow *)a)->tl) {
                while (eval(((struct flow *)a)->cond) != 0)
                    v = eval(((struct flow *)a)->tl);
            }
            break;
        case 'L': 
            eval(a->l);
            v = eval(a->r);
            break;
        case 'F': 
            v = callbuiltin((struct fncall *)a);
            break;
        case 'C': 
            v = calluser((struct ufncall *)a);
            break;
        default: printf("internal error: bad node %c\n", a->nodetype);
    }
    return v;
}

static double callbuiltin(struct fncall *f)
{
    int functype = f->functype;
    double v = eval(f->l);

    switch(functype) {
        case B_sqrt:
            return sqrt(v);
        case B_exp:
            return exp(v);
        case B_log: 
            return log(v);
        case B_print: 
            printf("= %4.4g\n", v);
            return v;
        default:
            yyerror("unknown builtin function %d\n", functype);
            return 0.0;
    }
}

void dodef(struct symbol *name, struct symlist *syms, struct ast *func)
{
    if (name->syms) 
        symlistfree(name->syms);

    if (name->func)
        treefree(name->func);

    name->syms = syms;
    name->func = func;
}

static double calluser(struct ufncall *f)
{
    struct symbol *fn = f->s;
    struct symlist *sl;
    struct ast *args = f->l;
    double *oldval, *newval;
    double v;
    int nargs;
    int i;

    if (!fn->func) {
        yyerror("call to undefined function\n", fn->name);
        return 0;
    }

    sl = fn->syms;
    for (nargs = 0; sl; sl = sl->next)
        nargs ++;

    oldval = (double*) malloc(nargs * sizeof(double));
    newval = (double *)malloc(nargs * sizeof(double));
    if (!oldval||!newval) {
        yyerror("out of space in %s\n", fn->name);
        return 0.0;
    }

    for (i = 0; i < nargs; i ++) {
        if (!args) {
            yyerror("too few args in call to %s\n", fn->name);
            free(oldval);
            free(newval);
            return 0.0;
        }

        if (args->nodetype == 'L') {
            newval[i] = eval(args->l);
            args = args->r;
        } else {
            newval[i] = eval(args);
            args = NULL;
        }
    }

        sl = fn->syms;
        for (i = 0; i < nargs; i ++) {
            struct symbol *s = sl->sym;

            oldval[i] = s->value;
            s->value = newval[i];
            sl = sl->next;
        }

        free(newval);

        v = eval(fn->func);
        sl = fn->syms;
        for (i = 0; i < nargs; i++) {
            struct symbol *s = sl->sym;
            s->value = oldval[i];
            sl = sl->next;
        }

        free(oldval);
        return v;
}

void yyerror(char *s, ...)
{
    va_list ap;
    va_start(ap, s);

    fprintf(stderr, "%d: error:", yylineno);
    vfprintf(stderr, s, ap);
    fprintf(stderr, "\n");
}

int main(int argc, char *argv[])
{
    printf("> ");
    return yyparse();
}

编译

bison -d fb3_2.y
flex -o fb3_2.lex.c fb3_2.l
gcc -o calculater fb3_2.tab.c fb3_2.lex.c fb3_func.c -lfl -lm

运行

./calculater 
> sqrt(10)
= 3.162
>let avg(a,b) =(a+b)/2;
Defined avg
> avg(10, 100)
=   55
>^C
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值