// saved from url
// http://www-cs.canisius.edu/PL_TUTORIALS/C++/EXAMPLES/MRD/SRC/expressions.c -->
//------------------------------------expressions.c--------------------------

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#include "expressions.h"

void Arithparser::tokenize (char *string, double lookup (char *))
{
     char ch, lastch;
     int n=0, k;
     int token=0;
     char valstring[WORD_MAX];

     while (1) {
          /* skip over white space */
          while ((ch = string[n]) && string[n] == ' ') n++;
          if (!ch) break;
          if (ch == '(') {
               tokens[token].type = '(';
               tokens[token].value = 0;
               n++;
          }
          else if (ch == ')') {
               tokens[token].type = ')';
               tokens[token].value = 0;
               n++;
          }
          else if (ch == '+') {
               tokens[token].type = 'o';
               tokens[token].value = 1.0;
               n++;
          }
          else if (ch == '-') {
               tokens[token].type = 'o';
               tokens[token].value = 2.0;
               n++;
          }
          else if (ch == '*') {
               tokens[token].type = 'o';
               tokens[token].value = 3.0;
               n++;
          }
          else if (ch == '/') {
               tokens[token].type = 'o';
               tokens[token].value = 4.0;
               n++;
          }
          else if (isalpha(ch)) {
               tokens[token].type = 'n';
               valstring[0] = ch;
               n++;
               k = 1;
               while (1) {
                    ch = string[n];
                    if (isalpha(ch) || isdigit(ch)) {
                         valstring[k++] = ch;
                         n++;
                         continue;
                    }
                    break;
               }
               valstring[k] = 0;
               tokens[token].value = lookup (valstring);
          }
          else if (isdigit(ch)) {
               tokens[token].type = 'n';
               /* continue to accumulate numerical stuff */
               k = 0;
               ch = ' ';
               while (1) {
                    lastch = ch;
                    ch = string[n];
                    if ((ch == '+' || ch == '-') && lastch == 'e') {
                         valstring[k++] = ch;
                        n++;
                        continue;
                    }
                    if (isdigit(ch) || ch == '.' || ch == 'e') {
                         valstring[k++] = ch;
                        n++;
                        continue;
                    }
                    break;
               }
               valstring[k] = 0;
               tokens[token].value = atof (valstring);
          }
          token++;
     }

     tokens[token].type = 'z';
}


double Arithparser::perform (double operand1, double opcode, double operand2)
{
	 if (opcode == 1.0)
          return operand1 + operand2;
     else if (opcode == 2.0)
          return operand1 - operand2;
     else if (opcode == 3.0)
          return operand1 * operand2;
     else if (opcode == 4.0)
          return operand1 / operand2;
	 else 
		  throw "bad opcode!";
	 return -1;
}


double Arithparser::parseval (int *tptr)
{
     double currentvalue = 0.0;
     double opcode, operand2;

     if (tokens[*tptr].type == 'z')
          return 0;

     currentvalue = nextoperand (tptr);
     (*tptr)++;

     while (1) {
          if (tokens[*tptr].type == ')' || tokens[*tptr].type == 'z') break;

          opcode = tokens[*tptr].value;
          (*tptr)++;

          operand2 = nextoperand (tptr);
          (*tptr)++;

          currentvalue = perform (currentvalue, opcode, operand2);
     }

     return currentvalue;
}

double Arithparser::nextoperand (int *tptr)
{
     if (tokens[*tptr].type == '(') {
          (*tptr)++;
          return parseval (tptr);
     }
     else
          return tokens[*tptr].value;
}

double Arithparser::parse (char *string, double lookup(char *))
{
     tokenize (string, lookup);
     tokenpointer = 0;
     return (parseval(&tokenpointer));
}
