home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 14
/
CD_ASCQ_14_0694.iso
/
maj
/
653
/
eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-03
|
7KB
|
315 lines
/*
** 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#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);
}
}