From 7e0f021a9aec35fd8e6725e87e3313b101d26f5e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 27 Jan 2008 11:37:44 +0100 Subject: Initial import (2.0.2-6) --- reference/C/CONTRIB/SNIP/eval.c | 314 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100755 reference/C/CONTRIB/SNIP/eval.c (limited to 'reference/C/CONTRIB/SNIP/eval.c') diff --git a/reference/C/CONTRIB/SNIP/eval.c b/reference/C/CONTRIB/SNIP/eval.c new file mode 100755 index 0000000..5829724 --- /dev/null +++ b/reference/C/CONTRIB/SNIP/eval.c @@ -0,0 +1,314 @@ +/* +** EVAL.C - A simple mathematical expression evaluator in C +** +** operators supported: ( +** ) +** + +** - +** * +** / +** ^ +** +** limitations: 1 - No precedence rules are implemented. +** 2 - Numbers can be negated (e.g. "-13"), but not +** expressions (e.g. "-(13)"). +** +** Original Copyright 1991 by Bob Stout as part of +** the MicroFirm Function Library (MFL) +** +** This subset* version is hereby donated to the public domain. +** +** *(The MFL version adds 150 lines of code, 5 level precedence, +** logarithmic and transcendental operators, pi as a constant, +** named variables, and fully understands negation.) +*/ + +#include +#include +#include +#include +#include + +#define NUL '\0' + +typedef enum {R_ERROR = -2 /* range */, ERROR /* syntax */, SUCCESS} STATUS; + +static char delims[] = "+-*/^)("; /* Tokens */ +static char op_stack[256]; /* Operator stack */ +static double arg_stack[256]; /* Argument stack */ +static char token[256]; /* Token buffer */ +static int op_sptr, /* op_stack pointer */ + arg_sptr, /* arg_stack pointer */ + parens, /* Nesting level */ + state = 0; /* 0 = Awaiting expression + 1 = Awaiting operator + */ + +int evaluate(char *, double *); + +static int do_op(void); +static int do_paren(void); +static void push_op(char); +static void push_arg(double); +static STATUS pop_arg(double *); +static STATUS pop_op(int *); +static char *getexp(char *); +static char *getop(char *); +static void pack(char *); + +#ifdef TEST + +void main(int argc, char *argv[]) +{ + double val; + + printf("evaluate(%s) ", argv[1]); + printf("returned %d\n", evaluate(argv[1], &val)); + printf("val = %f\n", val); +} + +#endif + +/* +** Evaluate a mathematical expression +*/ + +int evaluate(char *line, double *val) +{ + double arg; + char *ptr = line, *str, *endptr; + int ercode; + + pack(line); + + while (*ptr) + { + switch (state) + { + case 0: + if (NULL != (str = getexp(ptr))) + { + if ('(' == *str) + { + push_op(*str); + ptr += strlen(str); + break; + } + + if (0.0 == (arg = strtod(str, &endptr)) && + NULL == strchr(str, '0')) + { + return ERROR; + } + push_arg(arg); + ptr += strlen(str); + } + else return ERROR; + + state = 1; + break; + + case 1: + if (NULL == (str = getop(ptr))) + return ERROR; + + if (strchr(delims, *str)) + { + if (')' == *str) + { + if (SUCCESS > (ercode = do_paren())) + return ercode; + } + else + { + push_op(*str); + state = 0; + } + + ptr += strlen(str); + } + else return ERROR; + + break; + } + } + + while (1 < arg_sptr) + { + if (SUCCESS > (ercode = do_op())) + return ercode; + } + if (!op_sptr) + return pop_arg(val); + else return ERROR; +} + +/* +** Evaluate stacked arguments and operands +*/ + +static int do_op(void) +{ + double arg1, arg2; + int op; + + if (ERROR == pop_op(&op)) + return ERROR; + + pop_arg(&arg1); + pop_arg(&arg2); + + switch (op) + { + case '+': + push_arg(arg2 + arg1); + break; + + case '-': + push_arg(arg2 - arg1); + break; + + case '*': + push_arg(arg2 * arg1); + break; + + case '/': + if (0.0 == arg1) + return R_ERROR; + push_arg(arg2 / arg1); + break; + + case '^': + if (0.0 > arg2) + return R_ERROR; + push_arg(pow(arg2, arg1)); + break; + + case '(': + arg_sptr += 2; + break; + + default: + return ERROR; + } + if (1 > arg_sptr) + return ERROR; + else return op; +} + +/* +** Evaluate one level +*/ + +static int do_paren(void) +{ + int op; + + if (1 > parens--) + return ERROR; + do + { + if (SUCCESS > (op = do_op())) + break; + } while ('('!= op); + return op; +} + +/* +** Stack operations +*/ + +static void push_op(char op) +{ + if ('(' == op) + ++parens; + op_stack[op_sptr++] = op; +} + +static void push_arg(double arg) +{ + arg_stack[arg_sptr++] = arg; +} + +static STATUS pop_arg(double *arg) +{ + *arg = arg_stack[--arg_sptr]; + if (0 > arg_sptr) + return ERROR; + else return SUCCESS; +} + +static STATUS pop_op(int *op) +{ + if (!op_sptr) + return ERROR; + *op = op_stack[--op_sptr]; + return SUCCESS; +} + +/* +** Get an expression +*/ + +static char *getexp(char *str) +{ + char *ptr = str, *tptr = token; + + while (*ptr) + { + if (strchr(delims, *ptr)) + { + if ('-' == *ptr) + { + if (str != ptr && 'E' != ptr[-1]) + break; + } + + else if (str == ptr) + return getop(str); + + else if ('E' == *ptr) + { + if (!isdigit(ptr[1]) && '-' != ptr[1]) + return NULL; + } + else break; + } + + *tptr++ = *ptr++; + } + *tptr = NUL; + + return token; +} + +/* +** Get an operator +*/ + +static char *getop(char *str) +{ + *token = *str; + token[1] = NUL; + return token; +} + +/* +** Remove whitespace & capitalize +*/ + +static void pack(char *str) +{ + char *ptr = str, *p; + + strupr(str); + + for ( ; *ptr; ++ptr) + { + p = ptr; + while (*p && isspace(*p)) + ++p; + if (ptr != p) + strcpy(ptr, p); + } +} -- cgit v1.2.3-54-g00ecf