#ifndef DEMETER_H
#define DEMETER_H

#include <stream.h>
#include <fstream.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define NULL	0
#define FALSE	0
#define TRUE	1
typedef void (*PF)(); // pointer to function type

#ifdef MI
#define VIRTUAL  virtual
#else
#define VIRTUAL
#endif

class Universal;
ostream &operator<< (ostream &os, Universal *u);

class Universal {
 private:
  static const char *type;
  int line_number;
 public:
  Universal() { this->type = NULL; this->line_number = 0; }
  virtual ~Universal() {}
  virtual const char *get_type() const { return( type ); }
  static const char *get_formal_type() { return type; }
  void set_line_number( int ln ) { this->line_number = ln; }
  int  get_line_number() const { return this->line_number; }
  virtual void set_data_member( int,Universal* );
  virtual Universal *get_data_member( int ) const;
  virtual int number_of_parts() const;
  virtual int number_of_imm_parts() const;
  
  Universal *g_parse( char* );
  virtual Universal* g_parse_aux();
  Universal *g_parse( char*,char* );
  Universal *g_parse_string( char* );
  
  virtual int g_equal( Universal* ) const;
  virtual Universal* g_copy() const;
  virtual void g_draw() const;
  virtual void print_open_delim(int num) const
    { if (num<=1) cout << " ELEMENT{"; else cout << " ELEMENTS{";}
  virtual void print_close_delim() const { cout <<  "}";}
  
  void g_print( ostream& = cout ) const;
  void g_print( char* ) const;
  void g_print( Universal*,char* ) const;
  virtual void g_print_aux( ostream& ) const;
  int g_check( char* = NULL ) const;
  virtual char* g_code( int&,ofstream& ) const;
  char* g_code( ofstream& ) const;
  char* g_code( char* ) const;
  void g_displayAsTree( ostream& = cout ) const;
  void g_delete( char* = NULL );
  
#ifdef MI
  // castdown functions
  static Universal *castdown( Universal *u ) { return u; }
  static const Universal *castdown( const Universal *u ) { return u; }
  void *_safe_castdown(const char*) const;
  virtual void* _castdown(const char*) const;
  
  // ambigCheck not needed if only virtual inheritance is supported
  // void ambigCheck (void*&, void*&, const char*) const;
#endif
};


class Construction : VIRTUAL public Universal {
 private:
  static const char *type;
 public:
  virtual ~Construction() {}
  static const char *get_formal_type() { return type; }
  virtual const char *get_type() const { return type; }

  void print_open_delim(int num) const
    { if (num<=1) cout << " PART("; else cout << " PARTS(";}
  void print_close_delim() const { cout <<  ")";}

#ifdef MI
  // castdown functions
  static Construction *castdown( Universal *u ) 
    {return (Construction*)(u ? u -> _safe_castdown(get_formal_type()):NULL); }
  static const Construction *castdown( const Universal *u )
    {return (const Construction*)(u ? u->_safe_castdown(get_formal_type()):NULL); }
  virtual void* _castdown(const char* target) const;
#endif
};


#include "D__repetition.h"

class Terminal : VIRTUAL public Universal {
 private:
  static const char *type;
 public:
  virtual ~Terminal() {}
  static const char *get_formal_type() { return type; }
  virtual const char *get_type() const { return type; }

  virtual void mkinst_set_val( char* ) = 0;
  
  Universal* g_parse_aux();
  void g_draw()  const;
  virtual void pp( ostream& = cout ) const;
  virtual void displayAsTree( char*& ) const;

#ifdef MI
  // castdown functions
  static Terminal *castdown( Universal *u ) 
    { return (Terminal*)(u ? u -> _safe_castdown(get_formal_type()):NULL); }
  static const Terminal *castdown( const Universal *u )
    {return (const Terminal*)(u ? u->_safe_castdown(get_formal_type()):NULL); }
  virtual void* _castdown(const char* target) const;
#endif
};

class DemNumber : VIRTUAL public Terminal {
private:
  int val;
  static const char* type;

public:
  DemNumber( const int val_in = 0 ) : val( val_in ) { /* empty */ }
  DemNumber( const DemNumber* n ) { this->val = n->val; }
  ~DemNumber() { /* empty */ }
  const char        *get_type() const { return( type ); }
  static const char *get_formal_type()  { return( type ); }

  int        get_val() const { return( val ); }
  int        rset_val( int );
  void       set_val( int new_val ) { val = new_val; }
  void       mkinst_set_val( char* new_val ) { this->val = atoi( new_val ); }

  operator int() const { return this->val; }   // conversion operator
  DemNumber& operator=( const int n ) { this->val = n; return *this; }

  DemNumber* operator+=( const int i ) { this->val += i; return this; }
  DemNumber* operator+=( const DemNumber* n ) { this->val += n->val; return this; }

  DemNumber* operator-=( const int i ) { this->val -= i; return this; }
  DemNumber* operator-=( const DemNumber* n ) { this->val -= n->val; return this; }

  DemNumber* operator*=( const int i ) { this->val *= i; return this; }
  DemNumber* operator*=( const DemNumber* n ) { this->val *= n->val; return this; }

  DemNumber* operator/=( const int i ) { this->val /= i; return this; }
  DemNumber* operator/=( const DemNumber* n ) { this->val /= n->val; return this; }

  DemNumber* operator%=( const int i ) { this->val %= i; return this; }
  DemNumber* operator%=( const DemNumber* n ) { this->val %= n->val; return this; }

#ifdef MI
  static DemNumber* castdown( Universal* u ) 
    { return (DemNumber*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  static const DemNumber* castdown( const Universal* u ) 
    { return (const DemNumber*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  virtual void* _castdown( const char* ) const;
#endif

  Universal* g_copy() const;
  int        g_equal( Universal* ) const;
  void       pp( ostream& = cout ) const;
  void       g_print_aux( ostream& ) const;
  char*      g_code( int&, ofstream& ) const;
  void       displayAsTree( char*& ) const;
};

class DemReal : VIRTUAL public Terminal {
private:
  double val;
  static const char *type;

public:
  DemReal( const double val_in = 0 ) : val( val_in ) { /* empty */ }
  DemReal( const DemReal* r ) { this->val = r->val; }
  ~DemReal() { /* empty */ }
  const char*        get_type() const { return( type ); }
  static const char* get_formal_type()  { return( type ); }

  double     get_val() const { return( val ); }
  double     rset_val( double );
  void       set_val( double new_val ) { val = new_val; }
  void       mkinst_set_val( char* new_val ) { this->val = atof( new_val ); }

  operator double() const { return this->val; }  // conversion operator
  DemReal& operator=( const double d ) { this->val = d; return *this; }

  DemReal* operator+=( const double d ) { this->val += d; return this; }
  DemReal* operator+=( const DemReal* r ) { this->val += r->val; return this; }

  DemReal* operator-=( const double d ) { this->val -= d; return this; }
  DemReal* operator-=( const DemReal* r ) { this->val -= r->val; return this; }

  DemReal* operator*=( const double d ) { this->val *= d; return this; }
  DemReal* operator*=( const DemReal* r ) { this->val *= r->val; return this; }

  DemReal* operator/=( const double d ) { this->val /= d; return this; }
  DemReal* operator/=( const DemReal* r ) { this->val /= r->val; return this; }

#ifdef MI
  static DemReal* castdown( Universal* u ) 
    { return (DemReal*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  static const DemReal* castdown( const Universal *u ) 
    { return (const DemReal*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  virtual void* _castdown( const char* ) const;
#endif

  Universal* g_copy() const;
  int        g_equal( Universal* ) const;
  void       pp( ostream& = cout ) const;
  void       g_print_aux( ostream& ) const;
  char*      g_code( int&, ofstream& ) const;
  void       displayAsTree( char*& ) const;
};

class DemIdent : VIRTUAL public Terminal {
private:
  char* val;
  static const char* type;

public:
  DemIdent( char* = NULL );
  DemIdent( DemIdent& );
  ~DemIdent();
  const char*        get_type() const { return this->type; }
  static const char* get_formal_type()  { return type; }

  char*      get_val() const { return this->val; }
  char*      rset_val( char* );
  void       set_val( char* );
  void       mkinst_set_val( char* );

  operator char*() const { return this->val; }  // conversion operator
  int operator==( const char* str ) { return strcmp( this->val,str ) == 0; }
  int operator==( const DemIdent& other ) { return *this == other.val; }
  int operator!=( const char* str ) { return !(*this == str); }
  int operator!=( const DemIdent& other ) { return !(*this == other.val); }

#ifdef MI
  static DemIdent* castdown( Universal* u ) 
    { return (DemIdent*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  static const DemIdent* castdown( const Universal* u ) 
    { return (const DemIdent*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  virtual void* _castdown( const char* ) const;
#endif

  Universal* g_copy() const;
  int        g_equal( Universal* ) const;
  void       pp( ostream& = cout ) const;
  void       g_print_aux( ostream& ) const;
  char*      g_code( int&, ofstream& ) const;
  void       displayAsTree( char*& ) const;
};

class DemString : VIRTUAL public Terminal {
private:
  char* val;
  static const char* type;

public:
  DemString( char* = NULL );
  DemString( DemString& );
  ~DemString();
  static Universal*  make_instance();
  const char*        get_type() const { return this->type; }
  static const char* get_formal_type()  { return type; }

  char*      get_val() const { return this->val; }
  char*      rset_val( char* );
  void       set_val( char* );
  void       mkinst_set_val( char* );

  operator char*() const { return this->val; }  // conversion operator
  int operator==( const char* str ) { return strcmp( this->val,str ) == 0; }
  int operator==( const DemString& other ) { return *this == other.val; }
  int operator!=( const char* str ) { return !(*this == str); }
  int operator!=( const DemString& other ) { return !(*this == other.val); }

#ifdef MI
  static DemString* castdown( Universal* u ) 
    { return (DemString*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  static const DemString* castdown( const Universal* u ) 
    { return (const DemString*)(u ? u->_safe_castdown(get_formal_type()) : 0); }
  virtual void* _castdown(const char* ) const;
#endif

  Universal* g_copy() const;
  int        g_equal( Universal* ) const;
  void       pp( ostream& = cout ) const;
  void       g_print_aux( ostream& ) const;
  char*      g_code( int&, ofstream& ) const;
  void       displayAsTree( char*& ) const;
};

class DemText : VIRTUAL public Terminal {
private:
  char* val;
  int   len;
  static const char* type;

public:
  DemText( char* = NULL, int = 0 );
  DemText( DemText& );
  ~DemText();
  const char*        get_type() const { return this->type; }
  static const char* get_formal_type()  { return type; }

  char*      get_val() const { return this->val; }
  char*      rset_val( char* );
  void       set_val( char* );
  void       mkinst_set_val( char* );
  int        get_len() const { return len; }

  operator char*() const { return this->val; }  // conversion operator
  int operator==( const char* str ) { return strcmp( this->val,str ) == 0; }
  int operator==( const DemText& other ) { return *this == other.val; }
  int operator!=( const char* str ) { return !(*this == str); }
  int operator!=( const DemText& other ) { return !(*this == other.val); }

#ifdef MI
  static DemText* castdown( Universal* u ) 
    { return (DemText*) (u ? u->_safe_castdown(get_formal_type()) : 0); }
  static const DemText* castdown( const Universal* u ) 
    { return (const DemText*)(u ? u->_safe_castdown(get_formal_type()) : 0); }
  virtual void* _castdown( const char* ) const;
#endif

  Universal* g_copy() const;
  int        g_equal( Universal* ) const;
  void       pp( ostream& = cout ) const;
  void       g_print_aux( ostream& ) const;
  char*      g_code( int&, ofstream& ) const;
  void       displayAsTree( char*& ) const;
};

ostream& operator<<( ostream&, Universal* );


class DemTrace {

 private:
     static int traceIndent;
     char*  filename;
     char*  classname;
     char*  methodname;
     int    lineno;

 public:

     DemTrace(char*, int, char*, char*);
     ~DemTrace();

};


#endif

