/*********************************************************************
 *
 * File: eval.c
 * Auth: Fredrik Kling, gnilk@noice.org
 * Desc: Tree evaluator functions.
 *
 *
 *
 *********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include "misc/eval.h"


/********************************************************
 *  Error handler...
 ********************************************************/
void raise (char *sorg, char ec, int en)
{

  char *estring[] = {"","Element not member of base!",
              "Illeagal use of operator!",
              "Parse error, due to paratheses!",
              "Illegal character!",
              "Type mismatch!"};
  fprintf (stderr,"\n[!] Error in parser: %s\n",estring[en]);
  fprintf (stderr," - Error in: \'%s\', at:\'%c\'.'\n",strrev(sorg),ec);
  exit (1);
}
void dispose_tree (TREE *t)
{
  if (t -> left != NULL) dispose_tree (t ->left);
  if (t -> right != NULL) dispose_tree (t ->right);

  free (t);
}

/********************************************************
 * simple evaluator...
 *   rightmost oriented...
 ********************************************************/
double evaltree (TREE *tree)
{
  if (tree->type==OPR)
  {
    switch (tree -> opr)
    {
      case '+' : return ( (evaltree (tree -> right)) + (evaltree (tree -> left)));
      case '-' : return ( (evaltree (tree -> right)) - (evaltree (tree -> left)));
      case '*' : return ( (evaltree (tree -> right)) * (evaltree (tree -> left)));
      case '/' : return ( (evaltree (tree -> right)) / (evaltree (tree -> left)));
    }
  }
  return (tree -> value);
}
/********************************************************
 * numerical converters
 ********************************************************/
int isvalue(char *s)
{
  int temp=0,ok1=1,ok2=1,ok=-1;
  int neg=0;
  char tempstr[255];

  if ((*s=='$') || (*s=='#') || (*s=='%')) s++;
  if (*s=='-')
  {
    neg=1;
    s++;
  }
  while ((ok1>=0) && (ok2>=0) && (*s!='\0') && ( (isdigit(*s)) || (temp==0) && ((*s=='+') || (*s=='-')) || (*s=='.')))
  {
    ok=1;
    if(*s=='.') ok1--;
    tempstr[temp++]=*s++;
  }
  if ((ok>=0) && (ok1>=0))
  {
    if ((temp==1) && (!isdigit(tempstr[0]))) return (0);
    else return (temp);
  } else return(0);
}
long chrint (char c)
{
  if (c >= 'A') return ((long)((int)c-(int)'A')+10);
    else return ((long)((int)c-(int)'0'));
}
long cbase (char *str, long x, long base)
{
  long num = 0, y;
  char *sorg = str;

  while (*str!='\0')
  {
    if ((y = chrint (*str)) >= base) raise (sorg,*str, ERR_BASE);
    num = num + y*x;
    x*=base;
    str++;
  }
  return (num);
}

long strint (char *str, char base, int l)
{
  char tmp[256];
  int neg=0;
  long r;


  if ((base=='$') || (base=='#') || (base=='%')) str++;
  if (base=='-')
  {
    neg=1;
    str++;
  }
  strncpy (tmp,str,l);
  tmp[l]='\0';

  switch (base)
  {
    case '$' : return (cbase (strrev (tmp),1,16));
    case '#' : return (cbase (strrev (tmp),1,10));
    case '%' : return (cbase (strrev (tmp),1,2));
    default : r = cbase (strrev (tmp),1,10);
              if (neg) return -r;
                else return r;
              break;
  }
}
double getvalue(char *stringptr, int length)
{
  char tempstr[255];
  strncpy(tempstr,stringptr,length);
  tempstr[length]='\0';
  return(atof(tempstr));
}

/**********************************/
TREE *expr (char **sp)
{
  TREE *node,*old;

  node=term (sp);

  if ((**sp=='+') || (**sp=='-'))
  {
    old=node;
    node=(TREE *) malloc (sizeof (TREE));
    node->opr=**sp;
    node->right=old;
    node->type=OPR;
    (*sp)++;
    node->left=expr (sp);
  }
  return (node);


}
TREE *term (char **sp)
{
  TREE *node,*old;

  node=factor (sp);

  if ((**sp=='*') || (**sp=='/'))
  {
    old=node;                 /* spara gamla */
    node=(TREE*)malloc (sizeof (TREE)); /* allokera nytt.. */
    node->opr=**sp;
    node->right=old;            /* s„tt gammal som barn, till h”ger! */
    node->type=OPR;
    (*sp)++;
    node->left=term(sp);        /* forts„tt i v„nstra tr„det */
  }

  return (node);

}
TREE *factor (char **sp)
{
  TREE *node;
  int len;

  if (**sp=='(')
  {
    (*sp)++;
    node=expr (sp);
    if (**sp==')') (*sp)++;
      else {
         printf ("ž Nonmatching paranthesis...\n");
         }
  } else
    if ((len=isvalue (*sp))>0)
    {
      node=(TREE *)malloc (sizeof (TREE));  /* bygg f”rsta noden! */
      node->left=NULL;            /* allt annat „r null */
      node->right=NULL;
      node->value=(double)strint (*sp,**sp,len);
      node->type=VAL;             /* s„tt v„rdes flaggan */
      *sp+=len;
    } else {
       // placera variabler functioner etc.. h„r!
         printf ("ž Error in expression...\n");
         exit(1);
       }

  return node;
}

double eval_string (char *s)
{
  TREE *root;
  root=expr (&s);
  return evaltree (root);
  dispose_tree (root);
}


