#include "ee.h" int error = 0; void printStack(STACK); int main (const int argc, const char* argv[]) { STACK expr = NULL; const char** endPtr = argv+argc, ** arg = argv+1 ; /* Guard for empty expressions */ if (arg>=endPtr) { error |= ERR_NO_EXPR; } char* fmt = "%g\n"; if (!error && strcmp(*arg,"-f") == 0) { fmt ="%f\n"; arg+= 1; } while ((arg < endPtr) && (!error)){ if(isNum(*arg)) push(strtod(*arg, NULL), &expr); else if (arrity(**arg)) push(evaluate(&expr, **arg), &expr); else if (strcmp(*arg, "") == 0) // Ignore empty arguments ; else error |= ERR_INVALID_INPUT; arg += 1; } /* Detect malformed expressions */ if (!error) { if (expr == NULL) error |= ERR_NS_OPERANDS; else if ((*expr).tail != NULL) error |= ERR_NS_OPERATORS; } report(&expr, fmt); return error; } int isNum(const char* query) { /* * If query is a string, isNum(query) iff query represents a number. */ char *extra_char; strtod(query, &extra_char); return (strcmp(query, "") != 0) && (strcmp(extra_char, "") == 0); } int arrity(const char query) { /* * If query is a string corresponding to an operator in {+,x,-,/,^,!,%}, then * arrity(query) is the number of operands required by the operator. * If query is any other string, arrity(query) is zero. */ return (query == '+')? 2: (query == 'x')? 2: (query == '-')? 2: (query == '/')? 2: (query == '^')? 2: (query == '%')? 2: (query == '!')? 1: 0; } bool isDivByZero(double *_operands) { return _operands[0] == 0; } double evaluate(STACK* target_stack, char operator) { /* * If target_stack is a pointer to a STACK and operator is * a char corresponding to a supported operator, * evaluate(target_stack,operator) is the result of * applying the given operator to the appropriate number of * operands from target_stack. */ double value = 0; // a = 0, // b = 0; double *_operands = operands(target_stack, arrity(operator)); switch (operator){ case '+' : value = _operands[1] + _operands[0]; break; case '-' : value = _operands[1] - _operands[0]; break; case 'x' : value = _operands[1] * _operands[0]; break; case '/' : if (isDivByZero(_operands)) error |= ERR_DIV_BY_ZERO; else value = _operands[1] / _operands[0]; break; case '^' : value = pow(_operands[1],_operands[0]); break; case '!' : if ( (*_operands != floor(*_operands)) || (*_operands < 0)) error |= ERR_INVALID_FACTORIAL; else value = fact(*_operands); break; case '%' : value = ((int)_operands[1] % (int)_operands[0]); break; default : break; } return value; } double* operands(STACK* target_stack, int size) { /* * if target_stack is a pointer to a STACK, and size is an integer * corresponding to the number of operands desired, * operands(target_stack,size) returns an array of operands and * pops them off *target_stack. */ double * const _operands = (double*)malloc(size*sizeof(double)); double * tPtr = _operands; double * endPtr = _operands + size; while ((tPtr < endPtr) && !error) { if ((*target_stack) == NULL) error |= ERR_NS_OPERANDS; *tPtr = peek((target_stack)); pop(target_stack); tPtr += 1; } return _operands; } double fact(int n) { /* * if n is an integer, fact(n) is 'n factorial'. */ return (n==0)? 1 : n*fact(n-1); } void report(STACK* expr, char* fmt) { /* * reportErrors() prints error strings according to the value of global * bitvector error if it is nonzero, or the result of evaluation if error * is zero. */ //printStack(expr); if (error & ERR_INVALID_INPUT) printf("Error: Unexpected input.\n"); else if (error & ERR_NS_OPERATORS) printf("Error: insufficient operators.\n"); else if (error & ERR_NS_OPERANDS) printf("Error: insufficient operands.\n"); else if (error & ERR_INVALID_FACTORIAL) printf("Error: Factorials are only supported for positive integers.\n"); else if (error & ERR_DIV_BY_ZERO) printf("Undefined\n"); else if (error & ERR_NO_EXPR) printf("No expression provided.\n"); else printf(fmt, peek(expr)); } void printStack(STACK s) { /* Given a stack, print "datum tail"*/ while (s != NULL) { printf("%g\t%p\n", s->datum, s->tail); s = s->tail; } printf("%s\n", "-----"); } void push(double datum, STACK* tail) { /* Given a double value (datum), and a STACK (tail), * push(datum,tail) is the STACK resulting from * prepending datum to the STACK tail. */ NODE* new_node = (NODE*)malloc(sizeof(NODE)); (*new_node).datum = datum; (*new_node).tail = *tail; (*tail) = new_node; } void pop(STACK* target_stack) { /* Given a STACK (target_stack), pop(target_stack) * is the STACK resulting from the removal of the first * item in target_stack; */ STACK tail = NULL; if ((*target_stack) != NULL){ tail = (*target_stack)->tail; free(*target_stack); } (*target_stack) = tail; } double peek(STACK* target_stack) { /* Given a STACK (target_stack), peek(STACK) * is the first element's datum. */ return (*target_stack)? (*target_stack)->datum : 0; }