%{
#include"calc.tab.h"
%}
EXP ([Ee][-+]?[0-9]+)
%%
"+" |
"-" |
"*" |
"/" |
"|" |
"(" |
")" { return yytext[0]; }
([0-9]+"."[0-9]*{EXP}?)|("."?[0-9]+{EXP}?) { yylval.d = atof(yytext); return NUMBER; }
\n { return EOL; }
"//".*
[ \t] { /* ignore white space */ }
. { yyerror("Mystery character %c\n", *yytext); }
%%
%{
#include<stdio.h>
#include<stdlib.h>
#include <stdarg.h>
extern int yylineno; /* from lexer */
void yyerror(char *s, ...);
/* nodes in the abstract syntax tree */
struct ast {
int nodetype;
struct ast *l;
struct ast *r;
};
struct numval {
int nodetype; /* type K for constant */
double number;
};
/* build an AST */
struct ast *newast(int nodetype, struct ast *l, struct ast *r);
struct ast *newnum(double d);
/* evaluate an AST */
double eval(struct ast *);
/* delete and free an AST */
void treefree(struct ast *);
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 = 'K';
a->number = d;
return (struct ast *)a;
}
double
eval(struct ast *a)
{
double v;
switch(a->nodetype) {
case 'K': 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); if(v < 0) v = -v; break;
case 'M': v = -eval(a->l); break;
default: printf("internal error: bad node %c\n", a->nodetype);
}
return v;
}
void
treefree(struct ast *a)
{
switch(a->nodetype) {
/* two subtrees */
case '+':
case '-':
case '*':
case '/':
treefree(a->r);
/* one subtree */
case '|':
case 'M':
treefree(a->l);
/* no subtree */
case 'K':
free(a);
break;
default: printf("internal error: free bad node %c\n", a->nodetype);
}
}
void
yyerror(char *s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "%d: error: ", yylineno);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
}
%}
%union{
struct ast *a;
double d;
}
%token <d> NUMBER
%token EOL
%type <a> exp
%left '+' '-'
%left '*' '/'
%nonassoc '|' UMINUS
%%
calclist: /* nothing */
| calclist exp EOL {printf("= %4.4g\n", eval($2)); }
| calclist EOL { printf("> "); } /* blank line or a comment */
;
exp: 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); }
;
%%
int
main()
{
printf("> ");
return yyparse();
}
flex calc.l & bison -d calc.y
cc *.c -lfl