# include "dvoshell.h"

static int NallocBinary = 0;
static int NallocUnary = 0;

dbStack *dbBinary (dbStack *V1, dbStack *V2, char *op, float *fields) {

  int N;
  float M1, M2;
  dbStack *OUT;
  
  if (V1->type == 'F') {
    N = V1->field;
    M1 = fields[N];
  } else {
    M1 = V1->Float;
  }
  
  if (V2->type == 'F') {
    N = V2->field;
    M2 = fields[N];
  } else {
    M2 = V2->Float;
  }

  NallocBinary ++;
  ALLOCATE (OUT, dbStack, 1);
  OUT->type = 'T';
  OUT->name = NULL;

  // use an enum for the op...
  switch (op[0]) { 
  case '+': 
    OUT->Float = M1 + M2;
    break; 
  case '-': 
    OUT->Float = M1 - M2;
    break; 
  case '*': 
    OUT->Float = M1 * M2;
    break; 
  case '/': 
    OUT->Float = M1 / M2;
    break; 
  case '%': 
    OUT->Float = (int) M1 % (int) M2;
    break; 
  case 0x5e: 
    OUT->Float = pow (M1, M2);
    break; 
  case 'D': 
    OUT->Float = MIN (M1, M2);
    break; 
  case 'U': 
    OUT->Float = MAX (M1, M2);
    break; 
  case '<': 
    OUT->Float = (M1 < M2) ? 1 : 0;
    break; 
  case '>': 
    OUT->Float = (M1 > M2) ? 1 : 0;
    break; 
  case '&': 
    OUT->Float = ((int)M1 & (int)M2);
    break; 
  case '|': 
    OUT->Float = ((int)M1 | (int)M2);
    break; 
  case 'E': 
    OUT->Float = (M1 == M2) ? 1 : 0;
    break; 
  case 'N': 
    OUT->Float = (M1 != M2) ? 1 : 0;
    break; 
  case 'L': 
    OUT->Float = (M1 <= M2) ? 1 : 0;
    break; 
  case 'G': 
    OUT->Float = (M1 >= M2) ? 1 : 0;
    break; 
  case 'A': 
    OUT->Float = (M1 && M2) ? 1 : 0;
    break; 
  case 'O': 
    OUT->Float = (M1 || M2) ? 1 : 0;
    break; 
  default:
    return (NULL);
  }

  return (OUT);
}

dbStack *dbUnary (dbStack *V1, char *op, float *fields) {

  int N;
  float M1;
  dbStack *OUT;

  if (V1->type == 'F') {
    N = V1->field;
    M1 = fields[N];
  } else {
    M1 = V1->Float;
  }
  
  NallocUnary ++;
  ALLOCATE (OUT, dbStack, 1);
  OUT->type = 'T';
  OUT->name = NULL;

  if (!strcmp (op, "="))      {   OUT->Float = M1;                 }
  if (!strcmp (op, "abs"))    {   OUT->Float = fabs(M1);           }
  if (!strcmp (op, "int"))    {   OUT->Float = (float)(int)(M1);   }
  if (!strcmp (op, "exp"))    {   OUT->Float = exp (M1);           }
  if (!strcmp (op, "ten"))    {   OUT->Float = pow (10.0,M1);      }
  if (!strcmp (op, "log"))    {   OUT->Float = log10 (M1);         }
  if (!strcmp (op, "ln"))     {   OUT->Float = log (M1);           }
  if (!strcmp (op, "sqrt"))   {   OUT->Float = sqrt (M1);          }
  if (!strcmp (op, "erf"))    {   OUT->Float = erf (M1);           }
			      			      
  if (!strcmp (op, "sinh"))   {   OUT->Float = sinh (M1);          }
  if (!strcmp (op, "cosh"))   {   OUT->Float = cosh (M1);          }
  if (!strcmp (op, "asinh"))  {   OUT->Float = asinh (M1);         }
  if (!strcmp (op, "acosh"))  {   OUT->Float = acosh (M1);         }
  if (!strcmp (op, "lgamma")) {   OUT->Float = lgamma (M1);        }

  if (!strcmp (op, "sin"))    {   OUT->Float = sin (M1);           }
  if (!strcmp (op, "cos"))    {   OUT->Float = cos (M1);           }
  if (!strcmp (op, "tan"))    {   OUT->Float = tan (M1);           }
  if (!strcmp (op, "dsin"))   {   OUT->Float = sin (M1*RAD_DEG);   }
  if (!strcmp (op, "dcos"))   {   OUT->Float = cos (M1*RAD_DEG);   }
  if (!strcmp (op, "dtan"))   {   OUT->Float = tan (M1*RAD_DEG);   }
  if (!strcmp (op, "asin"))   {   OUT->Float = asin (M1);          }
  if (!strcmp (op, "acos"))   {   OUT->Float = acos (M1);          }
  if (!strcmp (op, "atan"))   {   OUT->Float = atan (M1);          }
  if (!strcmp (op, "dasin"))  {   OUT->Float = asin (M1)*DEG_RAD;  }
  if (!strcmp (op, "dacos"))  {   OUT->Float = acos (M1)*DEG_RAD;  }
  if (!strcmp (op, "datan"))  {   OUT->Float = atan (M1)*DEG_RAD;  }
  if (!strcmp (op, "rnd"))    {   OUT->Float = drand48();          }
  if (!strcmp (op, "not"))    {   OUT->Float = !(M1);              }
  if (!strcmp (op, "--"))     {   OUT->Float = - (M1);             }
  if (!strcmp (op, "isinf"))  {   OUT->Float = !finite(M1);        }
  if (!strcmp (op, "isnan"))  {   OUT->Float = isnan(M1);          } 

  return (OUT);
}

int dbStackAllocPrint () {

  fprintf (stderr, "dbAllocBinary: %d\n", NallocBinary);
  fprintf (stderr, "dbAllocUnary:  %d\n", NallocUnary);
  return (TRUE);
}

int dbStackAllocReset () {

  NallocBinary = 0;
  NallocUnary = 0;
  return (TRUE);
}
