
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "getline.h"

#define WHITESPACE " \t"
#define OPERATORS "*/+-%"


bool isInteger(char *tok) 
{
  int val;
  // for debugging: printf("%s: %d\n", tok, sscanf(tok, "%d", &val));
  return (sscanf(tok, "%d", &val) == 1);
  /*
  int i = 0;
  while (tok[i]) {
    if (!isdigit(tok[i]))
      return false;
    i++;
  }
  return true;
  */
}


bool isOperator(char *tok)
{
  return (strlen(tok)==1 && strchr(OPERATORS, tok[0]));
}


int evalOperator(char *optok, int v1, int v2)
{
  int val;
  switch (optok[0]) {
  case '*': return v1 * v2;
  case '/': return v1 / v2;
  case '%': return v1 % v2;
  case '+': return v1 + v2;
  case '-': return v1 - v2;
  }
  return 0; /* should never happen but need it to compile without warnings */
}


int postfixEvaluate(char *exp) 
{
  /* init if (size(s) < 2) {
	printf("ERROR: not enough operands for %s.\n", tok);
	return -ialize an empty stack (of ints) */
  STACK s = createStack();
  int *op1, *op2, *result;
  int retval;


  /* while there are more tokens in exp
       get next token */
  char *tok = strtok( exp, WHITESPACE );  /* get first token */
  while (tok) {
    /* if token is operand
          push onto stack */
    if ( isInteger(tok) ) {
      int* ip = (int*) malloc(sizeof(int));
      *ip = atoi( tok );
      push(s, ip);
    }
    /* else if it is an operator */
    else if ( isOperator(tok) ) {
      /* if sizeof(stack) < 2
	    error, not enough operands */
      if (size(s) < 2) {
	printf("ERROR: not enough operands for %s.\n", tok);
	exit(-1);
      }

      /* pop off two operands from the stack */
      op1 = pop(s);
      op2 = pop(s);

      /* apply  the operator */
      result = (int*) malloc(sizeof(int));
      *result = evalOperator(tok, *op2, *op1);

      /* push the result back onto the stack */
      push(s, result);

      /* (free memory of two operands that were popped) */
      free(op1);
      free(op2);
    }
    /* else syntax error */
    else {
      printf("ERROR: bad token %s.\n", tok);
      exit(-1);
    }
     
    tok = strtok( NULL, WHITESPACE ); /* for subsequent tokens pass NULL */
  }
  
  /* if sizeof(stack) > 1
     error, not enough operators */
  if (size(s) != 1) {
    printf("ERROR: syntax error in input.\n");
    exit(-1);
  }

  /* pop value on the stack and return it */
  retval = *((int*)top(s));
  free(pop(s));
  destroyStack(s);

  return retval;
}


int main() 
{
  char *exp;
  int val;

  printf( "Enter a postfix expression for evaluation: \n" );
  exp = getline(stdin);

  val = postfixEvaluate(exp);
  printf( "Result = %d\n", val );
  return 0;
}
