/* Emacs, this is -*- C++ -*- */

#ifndef _FI_H_
#define _FI_H_


#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <iostream.h>


/** Type for callback on table lookup.

	Functions of this type may be used as callback functions
	to look up cells in a table.

	@see #setLookupFunction()
*/
typedef double (*FI_LookupFunc)(const char*, int);


/** Type for callback on errors.

	Functions of this type may be used as callback functions
	for error reporting.

	@see #setErrorFunction()
*/
typedef void   (*FI_ErrorFunc) (const char*, const char*);


/** Class for representing variables in the formula interpreter.

	A variable for the formula interpreter consists of a name
	(maximum length maxNameLen=32) and a value.

	@author Patrick Schemitz
*/

class Variable
{
public:
  /// Construct empty variable.
  Variable ();
  /// Construct named variable, optionally with initial value.
  Variable (const char*, double=0.0);
  /// Change variable's name.
  void setName (const char*);
  /// Change variable's value.
  void setValue (double v) { value = v; }
  /// Retrieve variable's name.
  const char* const getName () const { return name; }
  /// Retrieve variable's value.
  double getValue () { return value; }
private:
  /// class constant for maximum name length (32 characters).
  static const int maxNameLen = 32;
  /// variable to store the name.
  char name [maxNameLen];
  /// variable to store the value.
  double value;
};


/** Representation of a Formula.

	A formula consists of an expression and a set of variables; some
	of the variables are global (shared by all formulas), others are
	local. Global variables are accessed via get/setGlobalVariable()
	and affect all formulas; local variables are accessed via
	get/setLocalVariable() and affect only the specified formula.

	The expression which is to be evaluated can be accessed by the
	functions set/getExpression(). The expression is a math term, e.g.
	"sin(x)*cos(y)+0.5*z*z". Note that the expression may *not* contain
	spaces or tab stops!

	A formula can be evaluated by the () operator, by placing a pair of
	brackets after an instance of class Formula.

	Warning: internally, the formula interpreter uses exceptions
	to handle errors. The file formula.cc must be compiled with
	exception handling on.

	@author Patrick Schemitz
*/

class Formula
{
public:

  /** Construct formula from string/expression.

	  The expression may not contain spaces!
  */
  Formula (const char*);

  /** Copy constructor.

	  Creates a deep copy, i.e. copies the expression and all local
	  variables of the r.h.s. formula.
  */
  Formula (const Formula&);

  /** Destruct formula and local variables.
	  
	  Frees all local variables; global variables remain untouched.
  */
  ~Formula ();

  /** Assign string expression to a formula; local variables remain. 

	  This just changes the expression of a formula. The same as
	  @ref #setExpression
  */
  Formula& operator= (const char*);

  /** Assign a formula to another formula.
	  
	  Creates a deep copy, i.e. copies the expression and all local
	  variables of the r.h.s. formula. The former left hand side
	  formula is wiped out.
  */
  Formula& operator= (const Formula&);

  /** Evaluate formula.

	  This operator evaluates the expression and returns the result.
	  Note that the evaluation may take some time (depending on the
	  expression, of course).

	  Two external functions are of interest here: the lookup function
	  and the error function. While the latter is called on parse errors
	  or in case an undefined variable is accessed, the lookup function
	  is called when the parser finds a pattern "col(name,integer)".
	  The name of the requested column is passed to the lookup function,
	  along with the integer row number.

	  If the evaluation was successful, the @ref #state function will return
	  zero.

	  @see state() to check success.
	  @return value of the expression.
  */
  double operator () ();

  /** Set the expression.

	  This function redefines the expression, leaving all variables
	  as they are.

	  @see #operator=()
  */
  void setExpression (const char*);

  /** Retrieve the expression.

	  @return the expression of the formula.
  */
  const char* expression () { return the_expression; }

  /** Set global variable.

	  This static member function defines/changes a global variable.
	  If the variable already exists, it is redefined; if it doesn´t,
	  it is newly defined. If the formula interpreter runs out of global
	  variables, the error function is called.

	  A global variable is accessible for all formulas.
	  (As opposed to global variables.)

	  @see #setLocalVariable()
	  @see #getGlobalVariables()
  */
  static void setGlobalVariable (Variable);

  /** Set local variable.

	  This function  defines/changes a local variable.
	  If the variable already exists, it is redefined; if it doesn´t,
	  it is newly defined. If the formula interpreter runs out of global
	  variables, the error function is called.

	  A local variable is accessible only in the formula in which it
	  is defined. (As opposed to global variables.)

	  @see #setGlobalVariable()
	  @see #getLocalVariables()
  */
  void setLocalVariable (Variable);

  /** Retrieve all global variables.

	  "v" must point to an (already allocated) array of variables,
	  and "max" must give the size of that array.

	  @param v Buffer to store the global variables in.
	  @param max Size of buffer "v".
	  @return Number of global variables in use.
	  @see #getLocalVariables()
	  @see #setGlobalVariable()
  */
  static int getGlobalVariables (int max, Variable* v);

  /** Retrieve all local variables.

	  "v" must point to an (already allocated) array of variables,
	  and "max" must give the size of that array.

	  @param v Buffer to store the local variables in.
	  @param max Size of buffer "v".
	  @return Number of local variables in use.
	  @see #getGlobalVariables()
	  @see #setLocalVariable()
  */
  int getLocalVariables (int max, Variable* v);

  /** Set lookup function for tables.

	  The lookup function is invoked if the expression contains
	  patterns "col(name,row)". Then, the lookup function
	  is called, with "name" and "row" as parameters.

	  Note that the lookup function, in case it fails to look up
	  the table's cell, should return NAN, not zero. This way, the
	  function calling the evaluation operator can conclude from
	  the result that something went wrong.

	  @return Pointer to old lookup function.
  */
  static FI_LookupFunc   setLookupFunction   (FI_LookupFunc);

  /** Set error report function.

	  The error function is called by the formula evaluation.
	  The default error handler prints out the message it gets passed,
	  and terminates the program. Your error handler might instead
	  open a message box, show the error message, and gracefully
	  close down the evaluation. Note that the error handler may
	  return (it does not *need* to terminate); in this case, the
	  evaluation will be aborted, and state() function will return
	  a non-zero value.

	  @return Pointer to old error function.
  */
  static FI_ErrorFunc    setErrorFunction    (FI_ErrorFunc);

  /** Toggle case sensitivity for expressions and variables.

	  Note that this won't toggle case sensitivity for table lookup,
	  since this is implemented completely different.
  */
  static bool caseSensitive;

  /** Check for errors during evaluation.

	  If the expression could be evaluated successfully, the
	  state() function returns zero; if there has been an error,
	  a non-zero value is returned. (Unless, of course, the error
	  handler function has terminated the program:-)

	  @see #operator()()
  */
  int state () { return fi_state; }

private:
  /// Internal. Evaluate expression and move pointer.
  double eval (char*&);
  /// Internal. Evaluate term and move pointer.
  double term (char*&);
  /// Internal. Evaluate factor and move pointer.
  double factor (char*&);
  /// Internal. Evaluate function and move pointer.
  double function (char*&);
  /// Internal. Evaluate numerical constant and move pointer.
  double number (char*&);
  /// Internal. Make call to lookup function.
  double table (char*& expr);
  /// Internal. Make call to built-in function.
  double callf (char*,double);
  /// Internal. Resolve variable.
  double variable (char*);

private:
  /// Internal. Class constant for max. number of global variables (1024).
  static const int maxGlobalVars = 1024;
  /// Internal. Class constant for max. number of local variables (1024).
  static const int maxLocalVars = 1024;
  /// Internal. Class constant for delta function (delta(fabs(x)<epsilon)=1).
  static const double epsilon = 1e-15;

private:
  /// Internal. Initialization of global variables.
  static void init ();
  /// Internal. String compare, w.r.t. case sensitivity.
  static int stringcmp (const char* s1, const char* s2);
  /// Internal. Strip whitespaces from string.
  char* stripped_string (const char*);
  /// Internal. State. See state() function.
  int fi_state;
  /// Internal. Global variable counter.
  static int globalVarCount;
  /// Internal. Global variables.
  static Variable globalVar [maxGlobalVars];
  /// Internal. Local variable counter.
  int localVarCount;
  /// Internal. Local variables.
  Variable localVar [maxLocalVars];
  /// Internal. Pointer to error handler function.
  static FI_ErrorFunc    error;
  /// Internal. Pointer to lookup function.
  static FI_LookupFunc   lookup;
  /// Internal. The expression string.
  char* the_expression;
  /// Internal. A working copy of the expression string pointer.
  char* workcopy;
};

#endif // _FI_H_

Documentation generated by mh@jeff_clever on Thu Feb 5 14:15:25 MET 1998