/*======================================================================*/
/*  Calculator Expression Evaluation Routine(s)                         */
/*======================================================================*/

#include stdio
#include ctype
#include errno
#include math

/* calculator common definitions */

#include "calc_include.h"

/* global flags and variables */

extern int    debug_flag;
extern int    error_flag;
extern int    func_error_flag;
extern int    format_precision;
extern struct token_struct numeric_value;

/* local flags, variables and definitions */

static int top  = 0;             /* top of stack (next writeable pos)   */
static int next = 0;             /* next free position in FIFO queue    */
static int free = 0;             /* next free token data structure      */

static int    queue[tokmax];              /* FIFO token queue           */
static int    stack[tokmax];              /* token stack                */
static struct token_struct token[tokmax]; /* free token array           */


/*----------------------------------------------------------------------*/
/*  Initilialize Pointer, Values, Etc. For Expression Evaluation        */
/*                                                                      */
/*----------------------------------------------------------------------*/

int evaluation_initilization()
{
   top  = 0;
   next = 0;
   free = 0;
   return 1;
}


/*----------------------------------------------------------------------*/
/*  Create A Function Token And Insert It Into The Expression Token     */
/*  Stream To Be Evaluated                                              */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  func       arithemetic fuction token type                           */
/*                                                                      */
/*----------------------------------------------------------------------*/

int create_function_token(func)
enum functype func;
{
   int idx;

   if (error_flag) return 1;                     /* test for error      */

   if (get_free_token(&idx))                     /* get a free token    */
      {
      token[idx].type = FUNCTION;                /* token type          */
      token[idx].func = func;                    /* function code       */
      token[idx].prec = 1;                       /* precedence level    */
      push_token(idx);
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Create An Operator Token And Insert It Into The Expression Token    */
/*  Stream To Be Evaluated                                              */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  type       operator token type                                      */
/*  oper       operator string                                          */
/*                                                                      */
/*----------------------------------------------------------------------*/

int create_operator_token(type,oper)
char oper;
enum tokentype type;
{
   int idx;

   if (error_flag) return 1;                     /* test for error      */

   if (get_free_token(&idx))                     /* get free token      */
      {
      token[idx].type = type;                    /* token type          */
      token[idx].oper = oper;                    /* operator character  */
      if (type == UNARY_OP)
         token[idx].prec = 0;                    /* precedence level    */
      else if (type==BINARY_OP)
         {
         if ((oper == '*') || (oper == '/'))
            token[idx].prec = 2;                 /* precedence level    */
         if ((oper == '+') || (oper == '-'))
            token[idx].prec = 3;                 /* precedence level    */
         }
      push_operator(idx);
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Create A Paren Token And Insert It Into The Expression Token        */
/*  Stream To Be Evaluated                                              */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  chr        paren character                                          */
/*                                                                      */
/*----------------------------------------------------------------------*/

int create_paren_token(chr)
char chr;
{
   int idx;

   if (error_flag) return 1;                     /* test for error      */

   if (chr == '(')
      {
      if (get_free_token(&idx))                  /* get free token      */
         {
         token[idx].type = PAREN;                /* token type          */
         token[idx].oper = chr;                  /* character           */
         token[idx].prec = 4;                    /* precedence level    */
         push_token(idx);
         }
      }
   else
      {
      /* move operators on the stack to the queue until a PAREN token   */
      /* is found, remove the paren token                               */

      for (;;)
         {
         if (top == 0) break;
         pop_token(&idx);
         if (token[idx].type == PAREN) break;
         insert_token(idx);
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Create A Value Token And Insert It Into The Expression Token        */
/*  Stream To Be Evaluated, The Value Is Found In NUMERIC_VALUE         */
/*                                                                      */
/*----------------------------------------------------------------------*/

int create_value_token()
{
   int idx;

   if (error_flag) return 1;                     /* test for error      */

   if (get_free_token(&idx))                     /* get free token      */
      {
      token[idx] = numeric_value;
      insert_token(idx);
      }
   return 1;
}


/*----------------------------------------------------------------------*/
/*  Return The Index To A Free (unused) Token From The Token Array      */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token returned to caller                  */
/*                                                                      */
/*----------------------------------------------------------------------*/

int get_free_token (idx)
int *idx;
{
   if (free < tokmax)
      {
      *idx = free;
      free += 1;
      return 1;
      }
   else
      {
      printf
      ("-- Internal error, free tokens exausted\n");
      error_flag = TRUE;
      return 0;
      }
}


/*----------------------------------------------------------------------*/
/*  Move Token From The Top Of The Stack To The End Of The Queue        */
/*----------------------------------------------------------------------*/

int move_token ()
{
   /* test stack for underflow */

   if (top <= 0)
      {
      printf ("-- Internal error, arithmetic stack underflow\n");
      error_flag = TRUE;
      return 0;
      }

   /* test queue for overflow */

   if (next >= tokmax)
      {
      printf ("-- Internal error, queue overflow\n");
      error_flag = TRUE;
      return 0;
      }

   /* move token from stack to queue */

   top  -= 1;
   queue[next] = stack[top];
   next += 1;
   return 1;
}


/*----------------------------------------------------------------------*/
/*  Push Token Onto The Stack                                           */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be pushed onto stack             */
/*                                                                      */
/*----------------------------------------------------------------------*/

int push_token (idx)
int idx;
{
   if (top < tokmax)
      {
      stack[top] = idx;
      top += 1;
      return 1;
      }
   else
      {
      printf ("-- Internal error, arithmetic stack overflow\n");
      error_flag = TRUE;
      return 0;
      }
}


/*----------------------------------------------------------------------*/
/*  Pop Token From The Stack                                            */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be pop from the stack            */
/*                                                                      */
/*----------------------------------------------------------------------*/

int pop_token (idx)
int *idx;
{
   if (top > 0)
      {
      top -= 1;
      *idx = stack[top];
      return 1;
      }
   else
      {
      printf ("-- Internal error, arithmetic stack underflow\n");
      error_flag = TRUE;
      return 0;
      }
}


/*----------------------------------------------------------------------*/
/*  Insert Token Onto The End Of The Queue                              */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be inseted into the queue        */
/*                                                                      */
/*----------------------------------------------------------------------*/

int insert_token (idx)
int idx;
{
   if (next < tokmax)
      {
      queue[next] = idx;
      next += 1;
      return 1;
      }
   else
      {
      printf
      ("-- Internal error, queue overflow\n");
      error_flag = TRUE;
      return 0;
      }
}


/*----------------------------------------------------------------------*/
/*  Push Operator Token Onto The Stack                                  */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be inseted into the queue        */
/*                                                                      */
/*----------------------------------------------------------------------*/

int push_operator (idx)
int idx;
{
   if (top < 0)
      {
      printf ("-- Internal error, stack underflow (%d)\n",top);
      error_flag = TRUE;
      return 0;
      }

   if (top >= tokmax)
      {
      printf ("-- Internal error, stack overflow\n");
      error_flag = TRUE;
      return 0;
      }

   /* move all operators of equal or greater precedence to the queue */

   for (;;)
      {
      if (top == 0) break;
      if (token[idx].prec < token[stack[top-1]].prec) break;
      move_token();
      }

   /* push operator onto stack */

   stack[top] = idx;
   top += 1;

   return 1;
}


/*----------------------------------------------------------------------*/
/*  The End Of A Compound Expression Was Detected,  Move All            */
/*  Operator Tokens Fron The Stack To The Queue Evaluation              */
/*----------------------------------------------------------------------*/

int end_compound_expression ()
{
   int idx;

   /* do not proceed if there were any errors */

   if (error_flag) return 1;

   /* move any operator tokens left on the stack to the queue */

   for (;;)
      {
      if (top == 0) break;
      if (token[stack[top-1]].type == PAREN) break;
      move_token();
      if (error_flag) return 1;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Evaluate The Parsed Expresson Placing The Results In NUMERIC_VALUE  */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  options    processing option flags                                  */
/*  stringcnt  length of input string                                   */
/*  stringptr  address of input string                                  */
/*  tokencnt   length of current token                                  */
/*  tokenptr   address of current token                                 */
/*  character  character value of character token                       */
/*  number     binary value of numeric token                            */
/*  param      user supplied argument                                   */
/*                                                                      */
/*----------------------------------------------------------------------*/

int evaluate_expression(options,stringcnt,stringptr,tokencnt,
                        tokenptr,character,number,param)
int  options,stringcnt,tokencnt,number,param;
char character,stringptr[],tokenptr[];
{
   int i,idx;

   /* do not proceed if there were any errors */

   if (error_flag) return 1;

   /* debug message */

   if (debug_flag) printf("Evaluate:   %.*s\n",tokencnt,tokenptr);

   /* move any tokens left on the stack to the queue */
   /* there should not be any, but just in case      */

   for (;;)
      {
      if (top == 0) break;
      move_token();
      }

   /* debug message */

   if (debug_flag) display_queue_stack();

   /* clear the function error flag */

   func_error_flag = FALSE;

   /* evaluate expresson by looking at eack token in the queue */

   for (i=0;i<next;i++)
      {
      switch (token[queue[i]].type)
         {
         case INTEGER:
         case FLOAT:
            push_token(queue[i]);
            break;
         case UNARY_OP:
            if      (token[queue[i]].oper == '-') negate();
            else if (token[queue[i]].oper != '+') error_flag = TRUE;
            break;
         case BINARY_OP:
            if      (token[queue[i]].oper == '+') add();
            else if (token[queue[i]].oper == '-') subtract();
            else if (token[queue[i]].oper == '*') multiply();
            else if (token[queue[i]].oper == '/') divide();
            else error_flag = TRUE;
            break;
         case FUNCTION:
            switch (token[queue[i]].func)
               {
               case ABS:
                  exec_abs_function();
                  break;
               case ACOS:
                  exec_acos_function();
                  break;
               case ASIN:
                  exec_asin_function();
                  break;
                case ATAN:
                  exec_atan_function();
                  break;
               case CEILING:
                  exec_ceiling_function();
                  break;
               case COS:
                  exec_cos_function();
                  break;
               case COSH:
                  exec_cosh_function();
                  break;
               case EXP:
                  exec_exp_function();
                  break;
               case FLT:
                  exec_flt_function();
                  break;
               case FLOOR:
                  exec_floor_function();
                  break;
               case INT:
                  exec_int_function();
                  break;
               case LN:
                  exec_ln_function();
                  break;
               case LOG:
                  exec_log_function();
                  break;
               case POW:
                  exec_pow_function();
                  break;
               case RAND:
                  exec_rand_function();
                  break;
               case MAX:
                  exec_max_function();
                  break;
               case MIN:
                  exec_min_function();
                  break;
               case MOD:
                  exec_mod_function();
                  break;
               case SEED:
                  exec_seed_function();
                  break;
               case SIN:
                  exec_sin_function();
                  break;
               case SINH:
                  exec_sinh_function();
                  break;
               case SQRT:
                  exec_sqrt_function();
                  break;
               case TAN:
                  exec_tan_function();
                  break;
               case TANH:
                  exec_tanh_function();
                  break;
               default:
                  error_flag = TRUE;
                  break;
               }
            break;
         default:
         error_flag = TRUE;
         break;
         }
      if (debug_flag)
         {
         printf("PROCESSED QUEUE ENTRY %d\n",i);
         display_queue_stack();
         }

      /* if func_error_flag is TRUE a math function error occured */
      /* and was reported to the user                             */

      if (func_error_flag)
         {
         error_flag = TRUE;
         return 1;
         }

      /* if error_flag is TRUE an error occured but was not       */
      /* reported to the user                                     */

      if (error_flag)
         {
         printf ("-- Internal error, expression evaluation failed\n");
         return 1;
         }
      }

    /* copy the results to numeric_value */
                  
    numeric_value = token[stack[0]];

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Convert Integer Token To Float Token                                */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be converted                     */
/*                                                                      */
/*----------------------------------------------------------------------*/

int convert_to_float (idx)
int idx;
{
   int temp;
   if (token[idx].type == FLOAT) return 1;
   if (token[idx].type == INTEGER)
      {
      temp = token[idx].idata;
      token[idx].fdata = temp;
      token[idx].type  = FLOAT;
      }
   else
      error_flag = TRUE;

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Convert Float Token To Integer Token                                */
/*                                                                      */
/*  Parameter  Description                                              */
/*                                                                      */
/*  idx        array index of token to be converted                     */
/*                                                                      */
/*----------------------------------------------------------------------*/

int convert_to_integer (idx)
int idx;
{
   int temp;
   if (token[idx].type == INTEGER) return 1;
   if (token[idx].type == FLOAT)
      {
      temp = token[idx].fdata;
      token[idx].idata = temp;
      token[idx].type  = INTEGER;
      }
   else
      error_flag = TRUE;

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Negate the Value Token On the Top Of The Stack And Place The        */
/*  Results Back On The Stack                                           */
/*----------------------------------------------------------------------*/

int negate ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get token index */

      a = stack[top-1];

      /* negate the token on the top of the stack */

      if (token[a].type == FLOAT)
         token[a].fdata = -token[a].fdata;
      else if (token[a].type == INTEGER)
         token[a].idata = -token[a].idata;
      else error_flag = TRUE;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Add The Two Value Tokens On the Top Of The Stack And Place The      */
/*  Results Back On The Stack                                           */
/*----------------------------------------------------------------------*/

int add ()
{
   int a,b;

   /* make sure there are two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top two tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform arithmetic operation on tokens of the same type */

      if ((token[a].type == FLOAT) || (token[b].type == FLOAT))
         {
         convert_to_float(a);
         convert_to_float(b);
         token[a].fdata += token[b].fdata;
         }
      else if ((token[a].type == INTEGER) || (token[b].type == INTEGER))
         token[a].idata += token[b].idata;
      else error_flag = TRUE;

      /* remove the top token on the stack */

      top -= 1;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Subtract The Two Value Tokens On the Top Of The Stack And Place The */
/*  Results Back On The Stack                                           */
/*----------------------------------------------------------------------*/

int subtract ()
{
   int a,b;

   /* make sure there are two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top two tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform arithmetic operation on tokens of the same type */

      if ((token[a].type == FLOAT) || (token[b].type == FLOAT))
         {
         convert_to_float(a);
         convert_to_float(b);
         token[a].fdata -= token[b].fdata;
         }
      else if ((token[a].type == INTEGER) || (token[b].type == INTEGER))
         token[a].idata -= token[b].idata;
      else error_flag = TRUE;

      /* remove the top token on the stack */

      top -= 1;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Multiply The Two Value Tokens On the Top Of The Stack And Place The */
/*  Results Back On The Stack                                           */
/*----------------------------------------------------------------------*/

int multiply ()
{
   int a,b;

   /* make sure there are two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top two tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform arithmetic operation on tokens of the same type */

      if ((token[a].type == FLOAT) || (token[b].type == FLOAT))
         {
         convert_to_float(a);
         convert_to_float(b);
         token[a].fdata *= token[b].fdata;
         }
      else if ((token[a].type == INTEGER) || (token[b].type == INTEGER))
         token[a].idata *= token[b].idata;
      else  error_flag = TRUE;

      /* remove the top token on the stack */

      top -= 1;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Divide The Two Value Tokens On the Top Of The Stack And Place The   */
/*  Results Back On The Stack                                           */
/*----------------------------------------------------------------------*/

int divide ()
{
   int a,b;

   /* make sure there are two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top two tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform arithmetic operation on tokens of the same type */

      if ((token[a].type == FLOAT) || (token[b].type == FLOAT))
         {
         convert_to_float(a);
         convert_to_float(b);
         token[a].fdata /= token[b].fdata;
         }
      else if ((token[a].type == INTEGER) || (token[b].type == INTEGER))
         token[a].idata /= token[b].idata;
      else error_flag = TRUE;
   
      /* remove the top token on the stack */

      top -= 1;
         }
   
   return 1;
}


/*----------------------------------------------------------------------*/
/*  ABS Function                                                        */
/*----------------------------------------------------------------------*/

int exec_abs_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* perform function */

      if (token[a].type == FLOAT)
         token[a].fdata = fabs(token[a].fdata);
      else if (token[a].type == INTEGER)
         token[a].idata = abs(token[a].idata);
      else
        error_flag = TRUE;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  ACOS Function                                                       */
/*----------------------------------------------------------------------*/

int exec_acos_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is a float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = acos(token[a].fdata);

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to ACOS function\n");
         func_error_flag = TRUE;
         errno = 0;                      
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  ASIN Function                                                       */
/*----------------------------------------------------------------------*/

int exec_asin_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = asin(token[a].fdata);

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to ACOS function\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  ATAN Function                                                       */
/*----------------------------------------------------------------------*/

int exec_atan_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];


      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = atan(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  CEILING Function                                                    */
/*----------------------------------------------------------------------*/

int exec_ceiling_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = ceil(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  COS Function                                                        */
/*----------------------------------------------------------------------*/

int exec_cos_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = cos(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  COSH Function                                                       */
/*----------------------------------------------------------------------*/

int exec_cosh_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = cosh(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  EXP Function                                                        */
/*----------------------------------------------------------------------*/

int exec_exp_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = exp(token[a].fdata);

      /* check for errors */

      if (errno == ERANGE)
         {
         printf("-- EXP function overflow\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  FLT Function                                                        */
/*----------------------------------------------------------------------*/

int exec_flt_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      convert_to_float(stack[top-1]);

   return 1;
}


/*----------------------------------------------------------------------*/
/*  FLOOR Function                                                      */
/*----------------------------------------------------------------------*/

int exec_floor_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = floor(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  INT Function                                                        */
/*----------------------------------------------------------------------*/

int exec_int_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      convert_to_integer(stack[top-1]);

   return 1;
}


/*----------------------------------------------------------------------*/
/*  LN Function                                                         */
/*----------------------------------------------------------------------*/

int exec_ln_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = log(token[a].fdata);

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to LN function\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  LOG Function                                                        */
/*----------------------------------------------------------------------*/

int exec_log_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = log10(token[a].fdata);

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to LOG function\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  POW Function                                                        */
/*----------------------------------------------------------------------*/

int exec_pow_function ()
{
   int a,b;

   /* make sure there is are least two element on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* make sure the values are float */

      if (token[a].type == INTEGER) convert_to_float(a);
      if (token[b].type == INTEGER) convert_to_float(b);

      /* perform function */

      token[a].fdata = pow(token[a].fdata,token[b].fdata);

      /* remove the token on the top of the stack */

      top -= 1;

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to LOG function\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  RAND Function                                                       */
/*----------------------------------------------------------------------*/

int exec_rand_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an integer */

      if (token[a].type == FLOAT) convert_to_integer(a);

      /* perform function */

      token[a].idata = rand();

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  MAX Function                                                        */
/*----------------------------------------------------------------------*/

int exec_max_function ()                  
{
   int a,b;

   /* make sure there is at least two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform function */

      if ((token[a].type == INTEGER) && (token[b].type == INTEGER))
         {
         if (token[a].idata < token[b].idata)
            token[a].idata = token[b].idata;
         }
      else if ((token[a].type == FLOAT) && (token[b].type == FLOAT))
         {
         if (token[a].fdata < token[b].fdata)
            token[a].fdata = token[b].fdata;
         }
      else if (token[a].type == FLOAT)
         {
         if (token[a].fdata < token[b].idata)
            token[a] = token[b];
         }
      else
         {
         if (token[a].idata < token[b].fdata)
            token[a] = token[b];
         }

      /* remove the token on the top of the stack */

      top -= 1;

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  MIN Function                                                        */
/*----------------------------------------------------------------------*/

int exec_min_function ()
{
   int a,b;

   /* make sure there is at least two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform function */

      if ((token[a].type == INTEGER) && (token[b].type == INTEGER))
         {
         if (token[a].idata > token[b].idata)
            token[a].idata = token[b].idata;
         }
      else if ((token[a].type == FLOAT) && (token[b].type == FLOAT))
         {
         if (token[a].fdata > token[b].fdata)
            token[a].fdata = token[b].fdata;
         }
      else if (token[a].type == FLOAT)
         {
         if (token[a].fdata > token[b].idata)
            token[a] = token[b];
         }
      else
         {
         if (token[a].idata > token[b].fdata)
            token[a] = token[b];
         }

      /* remove the token on the top of the stack */

      top -= 1;

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  MOD Function                                                        */
/*----------------------------------------------------------------------*/

int exec_mod_function ()
{
   int a,b;

   /* make sure there is at least two elements on the stack */

   if (top < 2)
      error_flag = TRUE;
   else
      {
      /* get the index of the top tokens on the stack */

      a = stack[top-2];
      b = stack[top-1];

      /* perform arithmetic operation on tokens of the same type */

      convert_to_integer(a);
      convert_to_integer(b);

      if ((token[a].type == INTEGER) && (token[b].type == INTEGER))
         token[a].idata %= token[b].idata;
      else error_flag = TRUE;

      /* remove the token on the top of the stack */

      top -= 1;
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  SEED Function                                                       */
/*----------------------------------------------------------------------*/

int exec_seed_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an integer */

      if (token[a].type == FLOAT) convert_to_integer(a);

      /* perform function */

      token[a].idata = srand(token[a].idata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  SIN Function                                                        */
/*----------------------------------------------------------------------*/

int exec_sin_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = sin(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  SINH Function                                                       */
/*----------------------------------------------------------------------*/

int exec_sinh_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = sinh(token[a].fdata);

      /* check for errors */

      if (errno == ERANGE)
         {
         printf("-- SINH function overflow\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  SQRT Function                                                       */
/*----------------------------------------------------------------------*/

int exec_sqrt_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = sqrt(token[a].fdata);

      /* check for errors */

      if (errno == EDOM)
         {
         printf("-- Illegal input to SQRT function\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  TAN Function                                                        */
/*----------------------------------------------------------------------*/

int exec_tan_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = tan(token[a].fdata);

      /* check for errors */

      if (errno == ERANGE)
         {
         printf("-- TAN function overflow\n");
         func_error_flag = TRUE;
         errno = 0;
         }
      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  TANH Function                                                       */
/*----------------------------------------------------------------------*/

int exec_tanh_function ()
{
   int a;

   /* make sure there is at least one element on the stack */

   if (top < 1)
      error_flag = TRUE;
   else
      {
      /* get the index of the top token on the stack */

      a = stack[top-1];

      /* make sure the value is an float */

      if (token[a].type == INTEGER) convert_to_float(a);

      /* perform function */

      token[a].fdata = tanh(token[a].fdata);

      }

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Display Queue And Stack Tokens (for debugging)                      */
/*----------------------------------------------------------------------*/

int display_queue_stack ()
{
   int  i;

   /* display stack operands */

   printf("\n---- Stack ----------\n");
   if (top < 0)
      printf("  Stack error - stack pointer is %d\n",top);
   else if (top == 0)
      printf("  Stack empty\n");
   else
      for (i=top-1;i>=0;i--) display_token_info(token[stack[i]]);

   /* display queue operands */

   printf("\n---- Queue ----------\n");
   if (next < 0)
      printf("  Queue error - queue pointer is %d\n",top);
   else if (next == 0)
      printf("  Queue empty\n");
   else
      for (i=0;i<next;i++) display_token_info(token[queue[i]]);

   printf("\n");

   return 1;
}


/*----------------------------------------------------------------------*/
/*  Display Token Information                                           */
/*----------------------------------------------------------------------*/

int display_token_info (token)
struct token_struct token;
{
   switch (token.type)
      {
      case UNKNOWN:
         printf("  Unknown token\n");
         break;
      case INTEGER:
         printf("  Integer   %d\n",token.idata);
         break;
      case FLOAT:
         printf("  Float     %f\n",token.fdata);
         break;
      case UNARY_OP:
         printf("  Unary op  %c (Prec %d)\n",token.oper,token.prec);
         break;
      case BINARY_OP:
         printf("  Binary op %c (Prec %d)\n",token.oper,token.prec);
         break;
      case PAREN:
         printf("  Paren     %c (Prec %d)\n",token.oper,token.prec);
         break;
      case FUNCTION:
         switch (token.func)
            {
            case ABS:
               printf("  Function  ABS\n");
               break;
            case ACOS:
               printf("  Function  ACOS\n");
               break;
            case ASIN:
               printf("  Function  ASIN\n");
               break;
            case ATAN:
               printf("  Function  ATAN\n");
               break;
            case CEILING:
               printf("  Function  CEILING\n");
               break;
            case COS:
               printf("  Function  COS\n");
               break;
            case COSH:
               printf("  Function  COSH\n");
               break;
            case EXP:
               printf("  Function  EXP\n");
               break;
            case FLT:
               printf("  Function  FLT\n");
               break;
            case FLOOR:
               printf("  Function  FLOOR\n");
               break;
            case INT:
               printf("  Function  INT\n");
               break;
            case LN:
               printf("  Function  LN\n");
               break;
            case LOG:
               printf("  Function  LOG\n");
               break;
            case POW:
               printf("  Function  POW\n");
               break;
            case RAND:
               printf("  Function  RAND\n");
               break;
            case MAX:
               printf("  Function  MAX\n");
               break;
            case MIN:
               printf("  Function  MIN\n");
               break;
            case MOD:
               printf("  Function  MOD\n");
               break;
            case SEED:
               printf("  Function  SEED\n");
               break;
            case SIN:
               printf("  Function  SIN\n");
               break;
            case SINH:
               printf("  Function  SINH\n");
               break;
            case SQRT:
               printf("  Function  SQRT\n");
               break;
            case TAN:
               printf("  Function  TAN\n");
               break;
            case TANH:
               printf("  Function  TANH\n");
               break;
            default: printf("  Unknown Function Type (%d)\n",token.func);
            }
         break;
      default:
         printf("  Illegal token type (%d)\n",token.type);
         break;
      }
   return 1;
}
