#include #include #include #include #include #include "sheets.h" /* EXPR := VALUE | VALUE POSTFIX | '(' EXPR ')' VALUE := NUM | LOC POSTFIX := OP EXPR OP := '+' | '-' | '*' | '/' | '^' lOC := '[' NUM ',' NUM ']' */ #define TODO(s) fprintf(stderr, "TODO:%d: %s\n", __LINE__, s); exit(1); typedef struct expr expr; typedef struct value value; /* for recursive case */ typedef struct postfix postfix; typedef enum exprType { VALUE, POSTFIX, NESTED, } exprType; typedef enum valueType { NUM, LOC, } valueType; typedef struct loc { int x, y; } loc; typedef struct expr { char *expr; exprType t; union { expr *nested; struct { value *value; postfix *postfix; }; }; } expr; typedef struct postfix { char op; expr *expr; } postfix; typedef struct value { valueType t; union { int num; loc *loc; }; } value; char isop(char c) { switch (c) { case '+': case '-': case '*': case '/': case '^': return c; } return 0; } char *in; char *Pin; void consumeleading(char c) { loop: if (*in == c) { in++; goto loop; } } expr *parseExpr(); loc *parseLoc() { consumeleading(' '); loc *l = malloc(sizeof(loc)); if (*in == '[') { int i; sscanf(in, "[%d,%d]%n", &l->x, &l->y, &i); if (i != 0) { in += i; return l; } TODO("ERROR"); } return NULL; } postfix *parsePostfix() { consumeleading(' '); postfix *p = malloc(sizeof(postfix)); if (p->op = isop(*in)) { in++; if (p->expr = parseExpr()) return p; } return NULL; } value *parseValue() { consumeleading(' '); value *v = malloc(sizeof(value)); if (v->loc = parseLoc()) { v->t = LOC; return v; } else if (isdigit(*in)) { int i; sscanf(in, "%d%n", &v->num, &i); if (i != 0) { in += i; v->t = NUM; return v; } TODO("ERROR"); } return NULL; } expr *parseExpr() { consumeleading(' '); expr *e = malloc(sizeof(expr)); if (e->value = parseValue()) { e->t = VALUE; if (e->postfix = parsePostfix()) e->t = POSTFIX; return e; } else if (*in == '(') { in++; if (e->nested = parseExpr()) if (*in == ')') { e->t = NESTED; return e; } TODO("ERROR"); } return NULL; } double evalExpr(expr *e, sheet *s); double evalValue(value *v, sheet *s) { if (v->t == NUM) return v->num; return evalExpr(s->cells[v->loc->y][v->loc->x], s); } double evalPostfix(value *v, postfix *p, sheet *s) { switch (p->op) { case '+': return evalValue(v, s) + evalExpr(p->expr, s); case '-': return evalValue(v, s) - evalExpr(p->expr, s); case '*': return evalValue(v, s) * evalExpr(p->expr, s); case '/': return evalValue(v, s) / evalExpr(p->expr, s); case '^': return pow(evalValue(v, s), evalExpr(p->expr, s)); } } double evalExpr(expr *e, sheet *s) { switch (e->t) { case VALUE: return evalValue(e->value, s); break; case POSTFIX: return evalPostfix(e->value, e->postfix, s); break; case NESTED: return evalExpr(e->nested, s); } } expr *makeNumber(int n) { in = Pin; memset(in, 0, 255); snprintf(in, 16, "%d", n); expr *e = parseExpr(); e->expr = strdup(Pin); return e; } void freeValue(value *v) { if (v->t == LOC) free(v->loc); free(v); } void freePostfix(value *v, postfix *p) { freeValue(v); freeExpr(p->expr); free(p); } void freeExpr(expr *e) { switch (e->t) { case VALUE: freeValue(e->value); break; case POSTFIX: freePostfix(e->value, e->postfix); break; case NESTED: freeExpr(e->nested); break; } free(e); }