#ifndef __EXPR_H
#define __EXPR_H

#ifndef __STRINGS_H
#include <strings.h>
#endif

#ifndef __REAL_H
#include <real.h>
#endif

// @doc INTERNAL

// @enum TCodesym | Lista di simboli/istruzioni possibili
enum TCodesym {
  _invalid,        // @emem Simbolo non riconosciuto
  _endsym,         // @emem Segnaposto per simbolo finale
  _comma,          // @emem Simbolo virgola ","
  _lpar,           // @emem Simbolo aperta parentesi "("
  _rpar,           // @emem Simbolo chiusa parentesi ")"
  _variable,       // @emem Nome di una variabile
  _number,         // @emem Numero
  _string,         // @emem Stringa
  _plus,           // @emem Simbolo piu' "+"
  _minus,          // @emem Simbolo meno "-"
  _multiply,       // @emem Simbolo per "*"
  _divide,         // @emem Simbolo diviso "/"
  _chgs,           // @emem MENO unario
  _and,            // @emem AND logico
  _or,             // @emem OR logico
  _not,            // @emem NOT logico
  _equal,          // @emem Simbolo uguale "="
  _match,          // @emem Confronto tra stringhe con wildcards
  _noteq,          // @emem Simbolo diverso "!="
  _lt,             // @emem Simbolo minore "<lt>"
  _gt,             // @emem Simbolo maggiore "<gt>"
  _lteq,           // @emem Simbolo minore o uguale "<lt>="
  _gteq,           // @emem Simbolo maggiore o uguale "<gt>="
  _sqrt,           // @emem Radice quadrata
  _sqr,            // @emem Elevamento al quadrato
  _exp10,          // @emem Funzione 10 a potenza
  _exp,            // @emem Funzione e (nepero) elevato a
  _log10,          // @emem Logaritmo in base 10
  _log,            // @emem Logaritmo naturale
  _sin,            // @emem Funzione seno
  _cos,            // @emem Funzione coseno
  _tan,            // @emem Funzione tangente
  _left,           // @emem Primi caratteri di una stringa
  _right,          // @emem Ultimi caratteri di una stringa
  _pow,            // @emem Elevamento a potenza
  _min,            // @emem Minimo tra piu' elementi
  _max,            // @emem Massimo tra piu' elementi
  _mid,            // @emem Media degli elementi
  _upper,          // @emem Trasformazione in maiuscolo
  _round,          // @emem Arrotondamento 
  _ansi } ;        // @emem Data in ansi

  // @enum TTypeesp | Tipi di espressioni definiti
  enum TTypeexp {
    _numexpr,        // @emem Espressione numerica
    _strexpr } ;     // @emem Espressione in lettere

    // @class TValue | Classe per la definizione dei valori che possono essere assunti
    //                             dai termini di una espressione o il valore dell'espressione stessa
    //
    // @base public | TObject
    class TValue : public TObject
{
  // @access Private Member

  // @cmember Valore real
  real _r;
  // @cmember Valore in formato stringa
  TString _s;

  // @access Public Member
public:
  // @cmember Assegnamento tra oggetti TValue
  TValue& operator =(const TValue& val)
  { _s = val._s; _r = val._r; return *this;}
  // @cmember Ritorna il valore numerico
  const real& number() const
  { return _r;}
  // @cmember Ritorna il valore come stringa
  const char* string() const
  { return (const char*) _s;}
  // @cmember Setta il valore passato come real
  void set(const real& val)
  { _r = val; _s = val.string();}
  // @cmember Setta il valore passato come stringa
  void set(const char* val)
  { _s = val; _r = real(val);}

  // @cmember Costruttore. Inizializza TValue con un reale
  TValue(const real& val);
  // @cmember Costruttore. Inizializza TValue con una stringa
  TValue(const char* val)
  { _s = val; _r = real(val);}
  // @cmember Costruttore. Inizializza TValue con un altro TValue
  TValue(const TValue& val)
  { *this = val; }
  // @cmember Costruttore. Inizializza TValue a 0,0 e ""
  TValue() { _r = 0.00; _s = ""; }
  // @cmember Distruttore
  virtual ~TValue()
  {}
};


#ifdef __EXPR_CPP
#define extern
#endif

extern TValue nulltvalue;

#undef extern

// @class TCode | Classe per la ridefinizione di una espressione in
//                                notazione polacca inversa (RPN)
//
// @base public | TObject
class TCode : public TObject
{
  // @access Private Member

  // @cmember Simbolo-istruzione-codice
  TCodesym _sym;
  // @cmember Valore
  TValue _val;

  // @access Public Member
public:
  // @cmember Assegnamento tra oggetti TCode
  TCode& operator =(const TCode& b);
  // @cmember Inizializza simbolo e valore
  void set(TCodesym sym, const TValue& val = nulltvalue)
  { _sym = sym; _val = val; }
  // @cmember Ritorna il simbolo
  TCodesym getsym() const
  { return _sym;}
  // @cmember Ritorna il valore come real
  const real& number() const
  { return _val.number();}
  // @cmember Ritorna il valore come stringa
  const char* string() const
  { return _val.string();}

  // @cmember Costruttore, inizializza simbolo con "invalid", valore a nullvalue
  TCode()
  {set(_invalid);}
  TCode(TCodesym sym, const TValue& val = nulltvalue)
    // @cmember Costruttore, inizializza simbolo con <p sym> e valore con <p val>
  { set(sym, val);}
  // @cmember Distruttore
  virtual ~TCode()
  {}
};

// @class TCodearray | Classe per la definizione di un array di istruzioni da valutare
//                                         passo per passo in una espressione
//
// @base public | TObject
class TCodearray : public TObject
{
  // @access Private Member

  // @cmember Numero di istruzioni
  int _last;
  // @cmember Puntatore all'istruzione corrente (Istruction pointer)
  int _ip;
  // @cmember Array
  TArray _rpn;

  // @access Public Member
public:
  // @cmember Cancella contenuto array
  void clear();
  // @cmember Aggiunge un'istruzione all'array
  void add(TCodesym sym, const TValue& val = nulltvalue);
  // @cmember Posiziona all'inizio il puntatore all'istruzione corrente
  void begin()
  { _ip = 0;}
  // @cmember Incrementa l'istruction pointer
  TCode& step()
  { return (TCode&) _rpn[end() ? _ip : _ip++];}
  // @cmember Ritorna TRUE se l'istruction pointer ha raggiunto il simbolo di fine codice
  bool end() const
  { return ((TCode&) _rpn[_ip]).getsym() == _endsym;}
  // @cmember Sposta indietro l'istruction pointer di <p step> passi (si ferma
  //          quando trova l'inizio del puntatore)
  void backtrace(int step = 1)
  { if (_ip > step) _ip -= step; else begin(); }
  // @cmember Costruttore. Crea un array di 10 elementi
  TCodearray(int size = 50);
  // @cmember Distruttore
  virtual ~TCodearray()
  {}
};

// @class TVar | Classe per la definizione delle variabile delle espressioni
//
// @base public | TObject
class TVar : public TObject
{
  // @access Private Member

  // @cmember Nome della variabile
  TString _name;
  // @cmember Valore assegnato alla variabile
  TValue _val;

  // @access Public Member
public:

  // #DES Operatore = tra vari oggetti
  // #FPUB
  // @cmember Assegnamento di una stringa all'oggetto Tval
  const char* operator =(const char* val)
  { _val.set(val); return val;}
  // @cmember Assegnamento di un numero all'oggetto TVal
  const real& operator =(const real& val)
  { _val.set(val); return val;}
  // @cmember Assegamento di un oggetto <c TValue>
  TVar& operator =(const TValue& val)
  { _val = val; return *this;}
  // @cmember Assegnamento tra oggetti TVal
  TVar& operator =(const TVar& var)
  { _name = var._name ; _val = var._val; return *this;}
  // @cmember Setta l'oggetto TVal con il nome e il valore passati
  void set(const char* name, const TValue& val = nulltvalue)
  { _name = name ; _val = val;}
  // @cmember Setta a name il nome della variabile
  void setname(const char* name)
  { _name = name;}
  // @cmember Ritorna il nome della variabile
  const char* getname() const
  { return _name;}

  // @cmember Ritorna _val (un TValue)
  operator TValue&()
  { return _val;}
  // @cmember Ritorna il valore real della variabile
  const real& number() const
  { return _val.number();}
  // @cmember Ritorna il valore stringa della variabile
  const char* string() const
  { return _val.string();}

  // @cmember Costruttore (assegna "" ed il valore nulltvalue)
  TVar()
  { _name = ""; _val = nulltvalue;}
  // @cmember Costruttore (assegna nome e valore passato)
  TVar(const char* name, const TValue& val = nulltvalue)
  { _name = name; _val = val;}
  // @cmember Costruttore (assegna l'oggetto TVal passato)
  TVar(TVar& v)
  { _name = v._name; _val = v._val;}
  // @cmember Distruttore
  virtual ~TVar()
  {}
};

// @class TVararray | Classe per la definizione di un array di variabili da
//                    valutare nell'esspressione
//
// @base public | TObject
class TVararray : public TObject
{
  // @access Private Member

  // @cmember Numero di variabili
  int _last;
  // @cmember Array
  TArray _array;

  // @access Public Member
public:
  // @cmember Cancella il contenuto dell'array
  void clear()
  { _last = 0; }
  // @cmember Aggiunge un oggetto TVar
  void add(const TVar& var);
  // @cmember Aggiunge un nome di variabile e il suo valore
  void add(const char* name, const TValue& val = nulltvalue);
  // @cmember Ritorna il nome della variabile di posto varnum
  const char* varname(int varnum) const
  { return  varnum < _array.items() ? ((TVar&) _array[varnum]).getname() : "";}

  // @cmember Setta l'oggetto TVararray con il nome e il valore della variabile
  void set(const char* varname, const real& val);
  // @cmember Setta l'oggetto TVararray con il nome e il valore della variabile
  //          (passato come stringa)
  void set(const char* varname, const char* val);
  // @cmember Setta l'elemnto dell varaibile <p varnum>-esima al valore passato
  void set(int varnum, const real& val)
  { if (varnum < _array.items()) ((TVar&) _array[varnum]) = val;}
  // @cmember Setta l'elemnto dell varaibile <p varnum>-esima al valore passato 
  //              come stringa
  void set(int varnum, const char* val)
  { if (varnum < _array.items()) ((TVar&) _array[varnum]) = val;}

  // @cmember Ritorna il valore della variabile con nome <p varname>
  const real& getnum(const char* varname);
  // @cmember Ritorna il valore della variabile di posto <p varnum>-esimo
  const real& getnum(int varnum);
  // @cmember Ritorna il nome della variabile con nome <p varname>
  const char* getstring(const char* varname);
  // @cmember Ritorna il nome della variabile di posto <p varnum>-esimo
  const char* getstring(int varnum);

  // @cmember Ritorna il numero di variabili utilizzate
  int numvar() const
  { return _last;}

  // @cmember Costruttore
  TVararray(int size = 10);
  // @cmember Distruttore
  virtual ~TVararray()
  {}
};

// @doc EXTERNAL

// @class TExpression | Classe per la interpretazione e valutazione di espressioni
//                                              numerica e di stringhe
//
// @base public | TObject
class TExpression : public TObject
{
  // @access Provate Member

  // @cmember Array di codice
  TCodearray _code;
  // @cmember Array di variabili
  TVararray _var;
  // @cmember Valore dell'espressione
  TValue _val;
  // @cmember TRUE se l'espressione e' stata modificata
  bool _dirty;
  // @cmember Tipo dell'espressione
  TTypeexp _type;
  // @cmember Stringa originale
  TString _original;

  // @access Protected Member
protected:
  // @cmember Valuta (calcola) l'espressione
  void eval();
  // @cmember Ritorna il prossimo token dell'espressione (se <p reduct> e' TRUE interpreta
  //              la virgola come un token)
  TCodesym __gettoken(bool reduct = FALSE);
  // @cmember Ritorna il prossimo fattore
  TCodesym __factor(TCodesym startsym);
  // @cmember Ritorna il prossimo termine
  TCodesym __term(TCodesym startsym);
  // @cmember Ritorna la prossima espressione
  TCodesym __expression(TCodesym startsym);
  // @cmember Compila l'espressione
  bool compile(const char* expression, TTypeexp type);
  
protected: // TObject
  // @cmember Stampa l'espressione su <p out> (serve per implementare l'insertore)
  virtual void print_on(ostream& out) const ;

  // @access Protected Member
public:
  // @cmember operator const | real& | | Ritorna il valore real dell'espressione
  operator const real&();
  // @cmember operator const | char* | | Ritorna il valore dell'espressione come stringa
  operator const char*();
  // @cmember Ritorna il valore dell'espressione come booleano
  operator bool();
  // @cmember Ritorna il nome della variabile di posto <p varnum>
  const char* varname(int varnum) const
  { return _var.varname(varnum); }
  // @cmember Ritorna il numero di variabili nell'espressione
  int numvar() const
  { return _var.numvar(); }
  // @cmember Ritorna il tipo dell'espressione
  const TTypeexp type() const
  { return _type; }
  TCodearray& code() const
    // @cmember Ritorna l'array del codice
  { return (TCodearray&)_code; }
  // @cmember Ritorna l'array di variabili
  const TVararray& vars() const
  { return _var; }

  // @cmember Setta la variabile con nome e numero
  void setvar(const char* varname, const real& val);
  // @cmember Setta la variabile con poszione e numero
  void setvar(int varnum, const real& val);
  // @cmember Setta la variabile con nome e valore passato come stringa
  void setvar(const char* varname, const char* val);
  // @cmember Setta la variabile passato co poszione e numero passato come stringa
  void setvar(int varnum, const char* val);
  // @cmember Setta il tipo dell'espressione
  void set_type(const TTypeexp type)
  { _type = type; }
  // @cmember Setta l'espressione e la compila (ritorna il risultato della compilazione)
  bool set(const char* expression, TTypeexp type = _numexpr);

  // @cmember Costruttore (assegna l'estressione e il suo tipo)
  TExpression(const char* expression, TTypeexp type = _numexpr);
  // @cmember Costruttore (assegna il tipo dell'istruzione)
  TExpression(TTypeexp type = _numexpr);
  // @cmember Distruttore
  virtual ~TExpression()
  {}
};

#endif // __EXPR_H
