#include /* printf(), etc. */ #include /* powf(), etc. */ #include "stk.h" #include "mystring.h" #include "cal.h" /* * eval: * o evaluates expression string, assuming postfix order! * o returns resultant float value */ float eval(char *input) { char c; float lhs,rhs; Stack stack; stk_init(&stack); while((c = *input++) != '\0') { if(isdigit(c)) { input--; stk_push(&stack,myatof(&input)); } else { switch(c) { case '*': rhs = stk_pop(&stack); lhs = stk_pop(&stack); stk_push(&stack,lhs * rhs); break; case '/': rhs = stk_pop(&stack); lhs = stk_pop(&stack); stk_push(&stack,lhs / rhs); break; case '+': rhs = stk_pop(&stack); lhs = stk_pop(&stack); stk_push(&stack,lhs + rhs); break; case '-': rhs = stk_pop(&stack); lhs = stk_pop(&stack); stk_push(&stack,lhs - rhs); break; case '^': rhs = stk_pop(&stack); lhs = stk_pop(&stack); stk_push(&stack,powf(lhs,rhs)); break; case ' ': case '\t': /* do nothing - eat white space */ break; default: printf(" UNK "); } } } return(stk_top(&stack)); } /* * in2post: * o convert infix expression (char array) into postfix * o uses integer stack, where enum int values (operators) are pushed * o operator values are enumerated according to operator precedence * (this facilitates comparison of top operator on stack) * o the algorithm is fairly straightforward: when parsing, * - operands: output immediately (to output infix string) * - close parenthesis: pop all stack symbols until an open ( is seen * - operator: pop all stack symbols until we see a symbol of lower * precedence or a right associative symbol of equal precedence. * Then push operator. * - end of input: pop all remaining stack symbols. * (algorithm obtained from: * Weiss, Mark Allen, ``Algorithms, data structures, and problem * solving with C++'', Addison-Wesley Longman, Inc., 1996, pp.359-364) * o note1: regarding the operator decision above, what this boils down * is equivalence classes among like operators, e.g., +, -, and *, /, * and operators with themselves, __except__ for ^. This is because * the exponent is processed right-to-left. */ char *in2post(char *infix) { int nesting=0; char c; Stack stack; char *p,*postfix; /* allocate new postfix array */ if((postfix = (char *)malloc(MAXLINE*sizeof(char)))==NULL) { fprintf(stderr,"out of memory\n"); exit(1); } /* set pointer to postfix array which to increment as array is filled in */ p = postfix; stk_init(&stack); while((c = *infix++) != '\0') { switch(c) { case '(': stk_push(&stack,LPR); /* suspend popping until we clear all nested () expressions */ nesting++; break; case ')': /* pop all operators until we see a ( */ while( !stk_empty(&stack) && (stk_top(&stack) != LPR) ) pop2postfix(&p,&stack); stk_pop(&stack); /* reduce one level of nesting */ nesting--; break; case '^': /* pop all operators that have higher precedence */ while( !nesting && !stk_empty(&stack) && (stk_top(&stack) > EXP) ) pop2postfix(&p,&stack); /* push current operator on stack */ stk_push(&stack,EXP); break; case '*': /* pop all operators that have higher or equal precedence */ while( !nesting && !stk_empty(&stack) && (stk_top(&stack) >= DIV) ) pop2postfix(&p,&stack); /* push current operator on stack */ stk_push(&stack,MUL); break; case '/': /* pop all operators that have higher or equal precedence */ while( !nesting && !stk_empty(&stack) && (stk_top(&stack) >= DIV) ) pop2postfix(&p,&stack); /* push current operator on stack */ stk_push(&stack,DIV); break; case '+': /* pop all operators that have higher or equal precedence */ while( !nesting && !stk_empty(&stack) && (stk_top(&stack) >= MNS) ) pop2postfix(&p,&stack); /* push current operator on stack */ stk_push(&stack,PLS); break; case '-': /* pop all operators that have higher or equal precedence */ while( !nesting && !stk_empty(&stack) && (stk_top(&stack) >= MNS) ) pop2postfix(&p,&stack); /* push current operator on stack */ stk_push(&stack,MNS); break; default: /* operand (or white space): simply "output" to postfix string */ *p++ = c; } } /* pop all remaining operators, then terminate string with \0 character */ while(!stk_empty(&stack)) pop2postfix(&p,&stack); *p = '\0'; /* return ptr to first element of postfix array (not p, pointint to end) */ return(postfix); } /* * pop2postfix: * o pops element off stack and appends to character array (surrounded by * spaces for readibilty and for subsequent evaluation) * o pointer to (char) pointer is used since we want to advance the array * pointer as we write to the array */ void pop2postfix(char **p, Stack *stack) { *(*p)++ = ' '; *(*p)++ = token2char((TokenType)(int)stk_pop(stack)); *(*p)++ = ' '; } /* * token2char: * o returns character "encoding" of given operator (token) */ char token2char(TokenType t) { switch(t) { case EXP: return('^'); case MUL: return('*'); case DIV: return('/'); case PLS: return('+'); case MNS: return('-'); default: return(' '); } }