当前位置:网站首页>flex&bison 高级计算器
flex&bison 高级计算器
2022-07-15 16:45:00 【LUCKY-LIVING】
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
边栏推荐
- R language ggplot2 visualization: use the ggboxplot function of ggpubr package to visualize the box graph, set the add parameter to add the distribution data point graph (dot plot, dot plot) to the bo
- urllib.error.URLError: <urlopen error [Errno 11004] getaddrinfo failed>
- [CQOI2012]局部极小值 & Mike and Foam
- 2021-05-30
- 业务发展陷入停滞,决策没有信息支撑,数据分析才是解决方案
- room android sqlite
- G1 is so strong, are you sure you don't know?
- 生命游戏,25号宇宙与奋斗者
- 关于一些字符串相关函数,内存函数及部分模拟
- markdown学习笔记 第二章 基本语法 (非markdown编辑器下显示)
猜你喜欢

MySQL index

关于一些字符串相关函数,内存函数及部分模拟

免驱 USB 转串口 Billboard 芯片(LDR2001)

YOLACT结构图

Application du moteur de visualisation Web de topologie dans le domaine de la simulation et de l'analyse

scala 分支控制 (单分支、双分支、多分支)、 分支判断的返回值

Canal realizes real-time synchronization of data from Mysql to es

Redis介绍和安装

Serialization and deserialization of flip word /maxqueue/ quadratic tree

MPC_ORCA
随机推荐
基于OSQP的二次规划
【云原生】3.4 RuoYi-Cloud部署实战(上)
国产之光!高分时空表征学习模型 UniFormer
PM 和 PO 有什么区别&&PMO的中文含义
centernet(objects as points)的尝试[基于tf.slim]
[CQOI2012]局部极小值 & Mike and Foam
What app should individuals use to buy stocks is safer and faster
MySQL数据库安装&问题
GridSearchCV报错:ValueError: Input contains NaN, infinity or a value too large for dtype(‘float64‘).
Notes on custom types such as structs, enumerations, unions, etc
要想不踩SaaS那些坑,得先了解“SaaS架构”
[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (4)
The meaning of sprint in Agile Development
【专有名词】
"Immersive" accommodation experience - new bottle of hotel, old wine of B & B
免驱 USB 转串口 Billboard 芯片(LDR2001)
Hongke case | nanogue uses Onyx system to realize nondestructive characterization of graphene electrical properties
MySQL index
Explanation of specific terms of smart factory
数据库笔记整理