///////////////////////////////////////////////////////////////////////////////
//  This file is generated automatically using Prop (version 2.3.0),
//  last updated on Feb 5, 1997.
//  The original source file is "persistence.pC".
///////////////////////////////////////////////////////////////////////////////

#define PROP_REWRITING_USED
#define PROP_PRINTER_USED
#define PROP_PERSISTENCE_USED
#define PROP_QUARK_USED
#include <propdefs.h>
//////////////////////////////////////////////////////////////////////////////
//  Testing persistence in Prop.
//
//  Persistence currently only means that objects are serializable into
//  a byte stream.  Objects are inserted in network byte order so that
//  they are portable across platforms.  Furthermore, pointer sharing
//  is preserved.
//////////////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include <fstream.h>
#include <assert.h>
#include <string.h>
#include <AD/generic/generic.h>  // Definition of type Bool
#include <AD/persist/pstream.h>  // persistence streams

//////////////////////////////////////////////////////////////////////////////
//
//  Define a datatype with pretty printing.
//
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Forward class definition for EXP
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_EXP_defined
#define datatype_EXP_defined
   typedef class a_EXP * EXP;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype EXP
///////////////////////////////////////////////////////////////////////////////
class a_EXP; // base class for datatype EXP
   class EXP_num;	// subclass for 'num int'
   class EXP_var;	// subclass for 'var ID'
   class EXP_add;	// subclass for 'add (EXP, EXP)'
   class EXP_sub;	// subclass for 'sub (EXP, EXP)'
   class EXP_mul;	// subclass for 'mul (EXP, EXP)'
   class EXP_div;	// subclass for 'div (EXP, EXP)'

///////////////////////////////////////////////////////////////////////////////
// Definition of type ID
///////////////////////////////////////////////////////////////////////////////
typedef char const * ID;

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'EXP'
///////////////////////////////////////////////////////////////////////////////
class a_EXP : public PObject {
public:
   enum Tag_EXP {
      tag_num = 0, tag_var = 1, tag_add = 2, tag_sub = 3, 
      tag_mul = 4, tag_div = 5
   };

protected:
   const Tag_EXP _tag_;
   inline a_EXP(Tag_EXP _t_) : _tag_(_t_) {}
public:
   inline int untag() const { return _tag_; }
   inline friend int boxed(const a_EXP * x) { return 1; }
   inline friend int untag(const a_EXP * x) { return x->_tag_; }
   ////////////////////////////////////////////////////////////////////////////
   // Downcasting functions for EXP
   ////////////////////////////////////////////////////////////////////////////
   inline friend EXP_num * _num(EXP _x_) { return (EXP_num *)_x_; }
   inline friend EXP_var * _var(EXP _x_) { return (EXP_var *)_x_; }
   inline friend EXP_add * _add(EXP _x_) { return (EXP_add *)_x_; }
   inline friend EXP_sub * _sub(EXP _x_) { return (EXP_sub *)_x_; }
   inline friend EXP_mul * _mul(EXP _x_) { return (EXP_mul *)_x_; }
   inline friend EXP_div * _div(EXP _x_) { return (EXP_div *)_x_; }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::num int'
///////////////////////////////////////////////////////////////////////////////
class EXP_num : public a_EXP {
public:
   int num; 
   inline EXP_num (int _xnum)
      : a_EXP(a_EXP::tag_num), num(_xnum) {}
   inline friend a_EXP * num (int _xnum)
      { return new EXP_num (_xnum); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_num >;
   inline EXP_num() : a_EXP(a_EXP::tag_num) {}
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::var ID'
///////////////////////////////////////////////////////////////////////////////
class EXP_var : public a_EXP {
public:
   ID var; 
   inline EXP_var (ID _xvar)
      : a_EXP(a_EXP::tag_var), var(_xvar) {}
   inline friend a_EXP * var (ID _xvar)
      { return new EXP_var (_xvar); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_var >;
   inline EXP_var() : a_EXP(a_EXP::tag_var) {}
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::add (EXP, EXP)'
///////////////////////////////////////////////////////////////////////////////
class EXP_add : public a_EXP {
public:
   EXP _1; EXP _2; 
   inline EXP_add (EXP _x1, EXP _x2)
      : a_EXP(a_EXP::tag_add), _1(_x1), _2(_x2) {}
   inline friend a_EXP * add (EXP _x1, EXP _x2)
      { return new EXP_add (_x1, _x2); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_add >;
   inline EXP_add() : a_EXP(a_EXP::tag_add) {}
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::sub (EXP, EXP)'
///////////////////////////////////////////////////////////////////////////////
class EXP_sub : public a_EXP {
public:
   EXP _1; EXP _2; 
   inline EXP_sub (EXP _x1, EXP _x2)
      : a_EXP(a_EXP::tag_sub), _1(_x1), _2(_x2) {}
   inline friend a_EXP * sub (EXP _x1, EXP _x2)
      { return new EXP_sub (_x1, _x2); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_sub >;
   inline EXP_sub() : a_EXP(a_EXP::tag_sub) {}
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::mul (EXP, EXP)'
///////////////////////////////////////////////////////////////////////////////
class EXP_mul : public a_EXP {
public:
   EXP _1; EXP _2; 
   inline EXP_mul (EXP _x1, EXP _x2)
      : a_EXP(a_EXP::tag_mul), _1(_x1), _2(_x2) {}
   inline friend a_EXP * mul (EXP _x1, EXP _x2)
      { return new EXP_mul (_x1, _x2); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_mul >;
   inline EXP_mul() : a_EXP(a_EXP::tag_mul) {}
public:
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'EXP::div (EXP, EXP)'
///////////////////////////////////////////////////////////////////////////////
class EXP_div : public a_EXP {
public:
   EXP _1; EXP _2; 
   inline EXP_div (EXP _x1, EXP _x2)
      : a_EXP(a_EXP::tag_div), _1(_x1), _2(_x2) {}
   inline friend a_EXP * div (EXP _x1, EXP _x2)
      { return new EXP_div (_x1, _x2); }
   ////////////////////////////////////////////////////////////////////////////
   // Methods for persistence and object serialization
   ////////////////////////////////////////////////////////////////////////////
protected:
   virtual const PObjectType& persist_type_id () const;
   virtual Pistream&          persist_read    (Pistream&);
   virtual Postream&          persist_write   (Postream&) const;
public:
private:
   ////////////////////////////////////////////////////////////////////////////
   // Default constructor used in persistence object factory
   ////////////////////////////////////////////////////////////////////////////
   friend class PObjectFactory< EXP_div >;
   inline EXP_div() : a_EXP(a_EXP::tag_div) {}
public:
};

ostream& operator << (ostream&,EXP);
ostream& pretty_print(ostream&,EXP,int = 0,int = 0);



//////////////////////////////////////////////////////////////////////////////
//  Make the datatype persistent by defining the persistence type tag for 
//  its constructors. 
//
//  The persistence type tag *must* be unique for each constructor.
//
//  The datatype definition together with the following refinement
//  declaration can together serve as some sort of interface definition.
//  The type EXP can now be communicated between programs through persistent
//  streams.
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//  Instantiate the datatype.  This declaration will generate all
//  necessary pretty printing and persistence serialization methods.
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type EXP
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, EXP _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case a_EXP::tag_num: 
         _f_ << _num(_x_)->num;
         break;
      case a_EXP::tag_var: 
         _f_ << _var(_x_)->var;
         break;
      case a_EXP::tag_add: 
         _f_ << "(";
         pretty_print(_f_, _add(_x_)->_1, _tab_, _prec_);
         _f_ << " + ";
         pretty_print(_f_, _add(_x_)->_2, _tab_, _prec_);
         _f_ << ")";
         break;
      case a_EXP::tag_sub: 
         _f_ << "(";
         pretty_print(_f_, _sub(_x_)->_1, _tab_, _prec_);
         _f_ << " - ";
         pretty_print(_f_, _sub(_x_)->_2, _tab_, _prec_);
         _f_ << ")";
         break;
      case a_EXP::tag_mul: 
         _f_ << "(";
         pretty_print(_f_, _mul(_x_)->_1, _tab_, _prec_);
         _f_ << " * ";
         pretty_print(_f_, _mul(_x_)->_2, _tab_, _prec_);
         _f_ << ")";
         break;
      case a_EXP::tag_div: 
         _f_ << "(";
         pretty_print(_f_, _div(_x_)->_1, _tab_, _prec_);
         _f_ << " / ";
         pretty_print(_f_, _div(_x_)->_2, _tab_, _prec_);
         _f_ << ")";
         break;
   }
   return _f_;
}

ostream& operator << (ostream& _f_, EXP _x_)
{ return pretty_print(_f_,_x_); }

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for base class of EXP
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T1("Simple expressions" "(EXP::base_class)");
const PObjectType& a_EXP::persist_type_id() const { return _T1; }
Pistream& a_EXP::persist_read  (Pistream& _f_)
{
}

Postream& a_EXP::persist_write (Postream& _f_) const
{
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::num int
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T2("Simple expressions" "(EXP::num)");
const PObjectType& EXP_num::persist_type_id() const { return _T2; }
static PObjectFactory< EXP_num > _T3(_T2);
Pistream& EXP_num::persist_read  (Pistream& _f_)
{
   _f_ >> num; // int
}

Postream& EXP_num::persist_write (Postream& _f_) const
{
   _f_ << num; // int
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::var ID
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T4("Simple expressions" "(EXP::var)");
const PObjectType& EXP_var::persist_type_id() const { return _T4; }
static PObjectFactory< EXP_var > _T5(_T4);
Pistream& EXP_var::persist_read  (Pistream& _f_)
{
   _f_ >> var; // ID
}

Postream& EXP_var::persist_write (Postream& _f_) const
{
   _f_ << var; // ID
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::add (EXP, EXP)
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T6("Simple expressions" "(EXP::add)");
const PObjectType& EXP_add::persist_type_id() const { return _T6; }
static PObjectFactory< EXP_add > _T7(_T6);
Pistream& EXP_add::persist_read  (Pistream& _f_)
{
   _1 = (EXP )read_object(_f_); // EXP
   _2 = (EXP )read_object(_f_); // EXP
}

Postream& EXP_add::persist_write (Postream& _f_) const
{
   _f_ << _1; // EXP
   _f_ << _2; // EXP
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::sub (EXP, EXP)
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T8("Simple expressions" "(EXP::sub)");
const PObjectType& EXP_sub::persist_type_id() const { return _T8; }
static PObjectFactory< EXP_sub > _T9(_T8);
Pistream& EXP_sub::persist_read  (Pistream& _f_)
{
   _1 = (EXP )read_object(_f_); // EXP
   _2 = (EXP )read_object(_f_); // EXP
}

Postream& EXP_sub::persist_write (Postream& _f_) const
{
   _f_ << _1; // EXP
   _f_ << _2; // EXP
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::mul (EXP, EXP)
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T10("Simple expressions" "(EXP::mul)");
const PObjectType& EXP_mul::persist_type_id() const { return _T10; }
static PObjectFactory< EXP_mul > _T11(_T10);
Pistream& EXP_mul::persist_read  (Pistream& _f_)
{
   _1 = (EXP )read_object(_f_); // EXP
   _2 = (EXP )read_object(_f_); // EXP
}

Postream& EXP_mul::persist_write (Postream& _f_) const
{
   _f_ << _1; // EXP
   _f_ << _2; // EXP
}

///////////////////////////////////////////////////////////////////////////////
// Persistence read/write methods for EXP::div (EXP, EXP)
///////////////////////////////////////////////////////////////////////////////
static PObjectType _T12("Simple expressions" "(EXP::div)");
const PObjectType& EXP_div::persist_type_id() const { return _T12; }
static PObjectFactory< EXP_div > _T13(_T12);
Pistream& EXP_div::persist_read  (Pistream& _f_)
{
   _1 = (EXP )read_object(_f_); // EXP
   _2 = (EXP )read_object(_f_); // EXP
}

Postream& EXP_div::persist_write (Postream& _f_) const
{
   _f_ << _1; // EXP
   _f_ << _2; // EXP
}



//////////////////////////////////////////////////////////////////////////////
//  A simple rewrite class to verify pointer sharing between nodes.
//////////////////////////////////////////////////////////////////////////////
class VerifySharing : public BURS {
private:
   VerifySharing(const VerifySharing&);               // no copy constructor
   void operator = (const VerifySharing&); // no assignment
public:
   struct VerifySharing_StateRec * stack__, * stack_top__;
public:
   void labeler(const char *, int&, int);
   void labeler(Quark, int&, int);
          void  labeler(EXP & redex, int&, int);
   inline virtual void  operator () (EXP & redex) { int s; labeler(redex,s,0); }
private: 
   public:
      VerifySharing() {}
};

inline void  VerifySharing::labeler(char const * redex,int& s__,int)
{
   {
s__ = 0;
   }
}

inline void  VerifySharing::labeler(Quark redex,int& s__,int)
{
   {
s__ = 0;
   }
}

void  VerifySharing::labeler (EXP & redex, int& s__, int r__)
{
replacement__:
   switch(redex->untag()) {
      case a_EXP::tag_num: { 
         int s0__;
         s0__ = 0; // int
         s__ = 0;} break;
      case a_EXP::tag_var: { 
         int s0__;
         labeler(_var(redex)->var, s0__, r__);
         s__ = 0;} break;
      case a_EXP::tag_add: { 
         int s0__;
         int s1__;
         labeler(_add(redex)->_1, s0__, r__);
         labeler(_add(redex)->_2, s1__, r__);
         s__ = 0;} break;
      case a_EXP::tag_sub: { 
         int s0__;
         int s1__;
         labeler(_sub(redex)->_1, s0__, r__);
         labeler(_sub(redex)->_2, s1__, r__);
         s__ = 1;} break;
      case a_EXP::tag_mul: { 
         int s0__;
         int s1__;
         labeler(_mul(redex)->_1, s0__, r__);
         labeler(_mul(redex)->_2, s1__, r__);
         s__ = 2;} break;
      default: { 
         int s0__;
         int s1__;
         labeler(_div(redex)->_1, s0__, r__);
         labeler(_div(redex)->_2, s1__, r__);
         s__ = 3;} break;
   }
   switch (s__) {
      case 3: { assert(_div(redex)->_1 == _div(redex)->_2); } break;
      case 2: { assert(_mul(redex)->_1 == _mul(redex)->_2); } break;
      case 1: { assert(_sub(redex)->_1 == _sub(redex)->_2); } break;
   }
   
}



//////////////////////////////////////////////////////////////////////////////
//  Equality between expressions.
//////////////////////////////////////////////////////////////////////////////
Bool equal(EXP a, EXP b) 
{  
{
   switch (a->untag()) {
      case a_EXP::tag_num: {
         switch (b->untag()) {
            case a_EXP::tag_num: { return _num(a)->num == _num(b)->num; } break;
            default: {
               L1:;  return false; } break;
         }
         } break;
      case a_EXP::tag_var: {
         switch (b->untag()) {
            case a_EXP::tag_var: { return strcmp(_var(a)->var,_var(b)->var) == 0; } break;
            default: { goto L1; } break;
         }
         } break;
      case a_EXP::tag_add: {
         switch (b->untag()) {
            case a_EXP::tag_add: { return equal(_add(a)->_1,_add(b)->_1) && equal(_add(a)->_2,_add(b)->_2); } break;
            default: { goto L1; } break;
         }
         } break;
      case a_EXP::tag_sub: {
         switch (b->untag()) {
            case a_EXP::tag_sub: { return equal(_sub(a)->_1,_sub(b)->_1) && equal(_sub(a)->_2,_sub(b)->_2); } break;
            default: { goto L1; } break;
         }
         } break;
      case a_EXP::tag_mul: {
         switch (b->untag()) {
            case a_EXP::tag_mul: { return equal(_mul(a)->_1,_mul(b)->_1) && equal(_mul(a)->_2,_mul(b)->_2); } break;
            default: { goto L1; } break;
         }
         } break;
      default: {
         switch (b->untag()) {
            case a_EXP::tag_div: { return equal(_div(a)->_1,_div(b)->_1) && equal(_div(a)->_2,_div(b)->_2); } break;
            default: { goto L1; } break;
         }
         } break;
   }
} 
}

//////////////////////////////////////////////////////////////////////////////
//  The main program just writes out an expression; then read it back.
//////////////////////////////////////////////////////////////////////////////
int main()
{  
   // Create an expression with sharing
   EXP e1 = add(num(1), var("x"));
   EXP e2 = mul(e1,e1);
   EXP e3 = div(e2,e2);
   EXP e4 = sub(e3,e3);
   EXP e5 = mul(e4,e4);
   EXP e6 = div(e5,e5);
   EXP e7 = sub(e6,e6);
   EXP e8 = add(var("foo"),e7);

   ///////////////////////////////////////////////////////////////////////////
   // Write the expression to a file.
   ///////////////////////////////////////////////////////////////////////////
   cout << "Original = " << e8 << '\n';
   {  ofstream out("persistence.dat");
      Postream pout(out);
      pout << e8;
      out.close();
   }

   ///////////////////////////////////////////////////////////////////////////
   // Read the expression back from the same file 
   ///////////////////////////////////////////////////////////////////////////
   EXP e;
   {  ifstream in("persistence.dat");
      Pistream pin(in);
      e = (EXP)read_object(pin);
      in.close();
   } 

   ///////////////////////////////////////////////////////////////////////////
   //  Verify the structure
   ///////////////////////////////////////////////////////////////////////////
   cout << "Copy = " << e << '\n';
   VerifySharing v;
   v(e);
   assert(equal(e8,e));

   cout << "Persistence seems to be working on your platform\n";
   return 0;
}
/*
------------------------------- Statistics -------------------------------
Merge matching rules         = yes
Number of DFA nodes merged   = 36
Number of ifs generated      = 0
Number of switches generated = 7
Number of labels             = 1
Number of gotos              = 5
Adaptive matching            = disabled
Fast string matching         = disabled
Inline downcasts             = disabled
--------------------------------------------------------------------------
*/

