/**************************************************************** 
 *
 *  fci.c
 *
 *  Interpetiert die von fcc erzeugten Felder.
 *
 *  Peter Gober, 08-May-88
 *               10-Jul-88 schnellerer Code durch Benutzung
 *                         direkter Adresserhöhung für Stack
 *
 ****************************************************************/

#include <errno.h>
#include <math.h>
#include "fc.h"

#define STACK_DEPTH 64                 /* Stacktiefe des internen Stacks */

/*
 *  fci
 *
 *  Gebrauch:       returncode = fcc(rules, constants, x, result)
 *                  int *rules;
 *                  float *constants;
 *                  float x;
 *                  float *result;
 *
 *  Eingaben:       rules        - Zeiger auf Feld mit Rechenregeln
 *                  constants    - Zeiger auf Feld mit Konstanten
 *                  x            - einzusetzendes x
 *                  result       - Zeiger auf float-Objekt für Ergebnis
 *  Ergebnisse:     returncode   - -1 im Fehlerfall, sonst NULL
                    *result      - Ergebnis
 */

int
fci(rules, constants, x, result)
register int *rules;
float *constants;
register float x;
float *result;
{
   float fcistack[STACK_DEPTH];               /* interner Stack */
   register float *stack = fcistack;          /* Zeiger auf momentane Position
                                                 im Stack */
   errno = 0;

   for(;;)
   {
      switch(*rules++)
      {
         case READ_CODE:
            *++stack = *constants++;
            break;
         case GETX_CODE:
            *++stack = x;
            break;
         case NEG_CODE:
            *stack = -*stack;
            break;
         case POW_CODE:
            *(stack-1) = pow(*(stack-1),*stack);
            stack--;
            break;
         case MULT_CODE:
            *(stack-1) *= *stack;
            stack--;
            break;
         case DIV_CODE:
            if (*stack == 0.0) return(-1);
            *(stack-1) /= *stack;
            stack--;
            break;
         case PLUS_CODE:
            *(stack-1) += *stack;
            stack--;
            break;
         case MINUS_CODE:
            *(stack-1) -= *stack;
            stack--;
            break;
         case SIN_CODE:
            *stack = sin(*stack);
            break;
         case COS_CODE:
            *stack = cos(*stack);
            break;
         case TAN_CODE:
            *stack = tan(*stack);
            break;
         case COTAN_CODE:
            *result = tan(*stack);
            if (*result != 0.0) *stack = 1 / *result;
               else return(-1);
            break;
         case ASIN_CODE:
            *stack = asin(*stack);
            break;
         case ACOS_CODE:
            *stack = acos(*stack);
            break;
         case ATAN_CODE:
            *stack = atan(*stack);
            break;
         case FLOOR_CODE:
            *stack = floor(*stack);
            break;
         case CEIL_CODE:
            *stack = ceil(*stack);
            break;
         case FABS_CODE:
            *stack = fabs(stack);
            break;
         case LOG_CODE:
            *stack = log(*stack);
            break;
         case LOG10_CODE:
            *stack = log10(*stack);
            break;
         case EXP_CODE:
            *stack = exp(*stack);
            break;
         case SQRT_CODE:
            *stack = sqrt(*stack);
            break;
         case SINH_CODE:
            *stack = sinh(*stack);
            break;
         case COSH_CODE:
            *stack = cosh(*stack);
            break;
         case TANH_CODE:
            *stack = tanh(*stack);
            break;
         case END_CODE:
            *result = *stack;
            if (errno) return(-1);
            return(0);
            break;
      }
   }
}
