/*/////////////////////////////////////////////////////////////////////////////////////
// project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalutaor )
// author  : Mateusz Malczak ( mateusz@malczak.info )
// wpage   : www.segfaultlabs.com/projects/sffe
///////////////////////////////////////////////////////////////////////////////////////
// possible config definitions
//   general
//	SFFE_DEVEL - print extra info to stdout
//	SFFE_DLL - Windows DLL
//   complex numbers
//	SFFE_CMPLX_GSL - uses GSL complex number routines
//	SFFE_CMPLX_ASM - uses my asm complex unit (compile it with NASM)
///////////////////////////////////////////////////////////////////////////////////////
// special build for XaoS, for more info visit
// http://www.segfaultlabs.com/projects/sfXaos
/////////////////////////////////////////////////////////////////////////////////////*/

#ifndef SFFE_H
#define SFFE_H
#include <config.h>
#include <stdlib.h>

/* dont udef next line. removing this definitions can lead to compile and/or runtime errors */
#define SFFE_COMPLEX 1

/* --- */
/*TODO long double needed*/
#ifdef SFFE_CMPLX_ASM
typedef struct cmpx__ {
    double r, i;
} cmplx;
#define sfNumber 		cmplx
#elif SFFE_CMPLX_GSL
#include <gsl/gsl_complex.h>
typedef gsl_complex cmplx;
#define sfNumber 		gsl_complex
#endif

/* basic sffe argument 'stack' */
typedef struct sfargument__ {
    struct sfargument__ *parg;
    sfNumber *value;
} sfarg;

/* sffe function prototype, parameters order is right-to-left (cdecl) */
typedef sfarg *(*sffptr) (sfarg * const a);

/* constats eval functions */
typedef void (*cfptr) (sfNumber * cnst);

/* function type structure */
typedef struct sffunction__ {
    sffptr fptr;
    unsigned char parcnt;
    /*FIXME changed from char* to char[20] to get rid of warnings during compilation */
    char name[20];
} sffunction;

/* basic sffe 'stack' operation ( function + result slot ) */
typedef struct sfoperation__ {
    sfarg *arg;
    sffptr f;
} sfopr;

/* SFFE main structure */
typedef struct sffe__ {
/*public*/
    char *expression;		/* parsed expression (read-only) */
    char *errormsg;		/* parser errors (read-only) */
    sfNumber *result;		/* evaluation result (read-only) */
/* protected/private */
    unsigned int argCount;	/* number of argument in use */
    sfarg *args;
    unsigned int oprCount;	/* number of operations in use */
    sfopr *oprs;
    unsigned int varCount;	/* number of used variables */
    char *varChars;
    sfNumber **varPtrs;
    unsigned int userfCount;	/* number of user functions */
    sffunction *userf;
/* not used 
  unsigned int	stCount;	    
  sfNumber*		statics;
*/
} sffe;

#define SFFE sffe
#define sffeparser sffe
#define sfparser sffe
#define SFFEPARSER sffe

/* 'stack' slot value */
#define sfvalue(p) (*((p)->value))

/* function parameters */
#define sfaram1(p) ((p)->parg)
#define sfaram2(p) ((p)->parg->parg)
#define sfaram3(p) ((p)->parg->parg->parg)
#define sfaram4(p) ((p)->parg->parg->parg->parg)
#define sfaram5(p) ((p)->parg->parg->parg->parg->parg)
/* and so on */


#ifdef __cplusplus
extern "C" {
#endif

/* create formula evaluator structure */
    sffe *sffe_alloc(void);
/* free fe structure */
    void sffe_free(sffe ** parser);
/* parse expression 'expression' and strore result in 'parser' struct, error (if any) returned */
    int sffe_parse(sffe ** parser, char *expression);
/* evaulate function and return evaluation result */
    sfNumber sffe_eval(sffe * const parser);
/* evaluate without returnig result */
//void sffe_eval2(sffe *const parser);
/* register user function with name 'vname', with 'parcnt' parameters and defined with function pointed by 'funptr'*/
    void *sffe_regfunc(sffe ** parser, char *vname, unsigned int parcnt,
		       sffptr funptr);
/* register single variable 'vptrs' identified by name 'vchars' */
    void *sffe_regvar(sffe ** parser, sfNumber * vptrs, char vchars);
/* register multiple variables */
    void *sffe_regvars(sffe ** parser, unsigned int cN, sfNumber ** vptrs,
		       char *vchars);
/* get variable 'vchar' pointer */
    sfNumber *sffe_varptr(sffe * const parser, char vchar);
/* set 'vptrs' as 'vchars' variable  */
    sfNumber *sffe_setvar(sffe ** parser, sfNumber * vptrs, char vchars);

#ifdef __cplusplus
}
#endif
#ifdef SFFE_CMPLX_ASM
#include "sffe_cmplx_asm.h"
#elif SFFE_CMPLX_GSL
#include "sffe_cmplx_gsl.h"
#endif
#endif
