/* Below is the worlds sleaziest little numerical expression * evaluator. Used to do only ints, now does doubles as well. * * This file is copyright 2002 Jim Kent, but license is hereby * granted for all use - public, private or commercial. */ #include "common.h" #include "kxTok.h" static struct kxTok *tok; #define nextTok() (tok = tok->next) #ifdef DEBUG static void nextTok() /* Advance to next token. */ { if (tok == NULL) printf("(null)"); else { printf("'%s' -> ", tok->string); if (tok->next == NULL) printf("(null)\n"); else printf("'%s'\n", tok->next->string); } tok = tok->next; } #endif /* DEBUG */ static double expression(); /* Forward declaration of main expression handler. */ static double number() /* Return number. */ { double val; if (tok == NULL) errAbort("Parse error in numerical expression"); if (!isdigit(tok->string[0])) errAbort("Expecting number, got %s", tok->string); val = atof(tok->string); nextTok(); return val; } static double atom() /* Return parenthetical expression or number. */ { double val; if (tok->type == kxtOpenParen) { nextTok(); val = expression(); if (tok->type == kxtCloseParen) { nextTok(); return val; } else { errAbort("Unmatched parenthesis"); return 0; } } else return number(); } static double uMinus() /* Unary minus. */ { double val; if (tok->type == kxtSub) { nextTok(); val = -atom(); return val; } else return atom(); } static double mulDiv() /* Multiplication or division. */ { double val = uMinus(); for (;;) { if (tok->type == kxtMul) { nextTok(); val *= uMinus(); } else if (tok->type == kxtDiv) { nextTok(); val /= uMinus(); } else break; } return val; } static double addSub() /* Addition or subtraction. */ { double val; val = mulDiv(); for (;;) { if (tok->type == kxtAdd) { nextTok(); val += mulDiv(); } else if (tok->type == kxtSub) { nextTok(); val -= mulDiv(); } else break; } return val; } static double expression() /* Wraps around lowest level of expression. */ { return addSub(); } double doubleExp(char *text) /* Convert text to double expression and evaluate. */ { double val; struct kxTok *tokList = tok = kxTokenize(text, FALSE); val = expression(); slFreeList(&tokList); return val; } int intExp(char *text) /* Convert text to int expression and evaluate. */ { return round(doubleExp(text)); }