%{
#include <math.h> #include <stdio.h>
#define FALSE (0) #define TRUE (1)
int yylex(void);
void yyerror(const char* s) { printf("%s\n", s); }
typedef enum { VAR_DOUBLE, VAR_FNCTPTR, } VarType;
typedef struct { VarType type; union { double d; double (*fnctptr)(double); } u; } Value;
typedef struct symrec { struct symrec* next; char* name; } symrec;
int refer(Value*, symrec*); void assign(const char*, Value); int funcall(Value*, Value, Value); int arith1(Value*, Value, double (*)(double)); int arith2(Value*, Value, Value, double (*)(double, double)); double add(double x, double y) { return x + y; } double sub(double x, double y) { return x - y; } double mul(double x, double y) { return x * y; } double div(double x, double y) { return x / y; } double neg(double x) { return -x; } void dump_value(FILE*, Value);
%}
%union { Value val; symrec* sym; }
%token <val> VAL %token <sym> SYM %type <val> exp prim
%right '=' %left '+' '-' %left '*' '/' %left UNARY_NEG %left '^'
%%
input : | input line ;
line : '\n' | exp '\n' { putchar('\t'); dump_value(stdout, $1); putchar('\n'); } | error '\n' { yyerrok; } ;
exp : prim { $$ = $1; } | SYM '=' exp { assign($1->name, $$ = $3); } | exp '+' exp { if (!arith2(&$$, $1, $3, add)) YYERROR; } | exp '-' exp { if (!arith2(&$$, $1, $3, sub)) YYERROR; } | exp '*' exp { if (!arith2(&$$, $1, $3, mul)) YYERROR; } | exp '/' exp { if (!arith2(&$$, $1, $3, div)) YYERROR; } | '-' exp %prec UNARY_NEG { if (!arith1(&$$, $2, neg)) YYERROR; } | exp '^' exp { if (!arith2(&$$, $1, $3, pow)) YYERROR; } | '(' exp ')' { $$ = $2; } ;
prim : VAL { $$ = $1; } | SYM { if (!refer(&$$, $1)) YYERROR; } | prim '(' exp ')' { if (!funcall(&$$, $1, $3)) YYERROR; } ;
%%
#include <ctype.h> #include <malloc.h> #include <string.h>
symrec* sym_table = NULL;
symrec* putsym(const char* sym_name) { symrec* ptr = (symrec*)malloc(sizeof(symrec)); ptr->name = (char*)malloc(strlen(sym_name) + 1); strcpy(ptr->name, sym_name); ptr->next = sym_table; sym_table = ptr; return ptr; }
symrec* getsym(const char* sym_name) { symrec* ptr; for (ptr = sym_table; ptr != NULL; ptr = ptr->next) { if (strcmp(ptr->name, sym_name) == 0) return ptr; } return NULL; }
static int skip_spaces() { int c; while (c = getchar(), c == ' ' || c == '\t'); return c; }
static int read_symbol(int c) { static char* buf; static int length; symrec* s; int i = 0; do { if (i >= length) { if (length == 0) length = 16/2; buf = (char*)realloc(buf, (length *= 2) + 1); } buf[i++] = c; c = getchar(); } while (c != EOF && isalnum(c)); ungetc(c, stdin); buf[i] = '\0';
s = getsym(buf); if (s == NULL) s = putsym(buf); yylval.sym = s; return SYM; }
int yylex(void) { int c = skip_spaces(); if (c == EOF) return 0; if (c == '.' || isdigit(c)) { ungetc(c, stdin); scanf("%lf", &yylval.val.u.d); yylval.val.type = VAR_DOUBLE; return VAL; } if (isalpha(c)) { return read_symbol(c); } return c; }
void set_double(Value* p, double x) { p->type = VAR_DOUBLE; p->u.d = x; } void set_fnctptr(Value* p, double (*f)(double)) { p->type = VAR_FNCTPTR; p->u.fnctptr = f; }
int arith1(Value* result, Value a, double (*f)(double)) { if (a.type != VAR_DOUBLE) { fprintf(stderr, "Can't operate arithmetic: "); dump_value(stderr, a); fprintf(stderr, "\n"); return FALSE; } else { set_double(result, f(a.u.d)); return TRUE; } }
int arith2(Value* result, Value a, Value b, double (*f)(double, double)) { if (a.type != VAR_DOUBLE) { fprintf(stderr, "Can't operate arithmetic: "); dump_value(stderr, a); fprintf(stderr, "\n"); return FALSE; } else if (b.type != VAR_DOUBLE) { fprintf(stderr, "Can't operate arithmetic: "); dump_value(stderr, b); fprintf(stderr, "\n"); return FALSE; } else { set_double(result, f(a.u.d, b.u.d)); return TRUE; } }
void dump_value(FILE* ofp, Value v) { switch (v.type) { case VAR_DOUBLE: fprintf(ofp, "%.10g", v.u.d); break; case VAR_FNCTPTR: fprintf(ofp, "function"); break; default: fprintf(ofp, "?? Illegal value"); break; } }
#include <map> #include <string> using namespace std;
static map<string, Value> GlobalVariableTable;
int refer(Value* result, symrec* sym) { map<string, Value>::const_iterator it = GlobalVariableTable.find(sym->name); if (it == GlobalVariableTable.end()) { fprintf(stderr, "unbound `%s'\n", sym->name); return FALSE; } else { *result = GlobalVariableTable[sym->name]; return TRUE; } }
void assign(const char* name, Value val) { GlobalVariableTable[name] = val; }
int funcall(Value* result, Value fnct, Value x) { if (fnct.type != VAR_FNCTPTR) { fprintf(stderr, "Can't call: "); dump_value(stderr, fnct); fprintf(stderr, "\n"); return FALSE; } else if (x.type != VAR_DOUBLE) { fprintf(stderr, "Illegal argument: "); dump_value(stderr, x); fprintf(stderr, "\n"); return FALSE; } else { set_double(result, fnct.u.fnctptr(x.u.d)); return TRUE; } }
void init_table() { struct { const char* fname; double (*fnct)(double); } static const arith_fncts[] = { { "sin", sin, }, { "cos", cos, }, { "atan", atan, }, { "ln", log, }, { "exp", exp, }, { "sqrt", sqrt, }, { 0, 0 } };
int i; for (i = 0; arith_fncts[i].fname != NULL; ++i) { Value v; set_fnctptr(&v, arith_fncts[i].fnct); assign(arith_fncts[i].fname, v); } }
int main() { init_table(); yyparse(); return 0; }
|