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

#define PROP_REWRITING_USED
#define PROP_PRINTER_USED
#define PROP_QUARK_USED
#include <propdefs.h>
/////////////////////////////////////////////////////////////////////////////
//  This test implements a rewrite based simplifier for the abstract
//  syntax of a toy imperative language.  
/////////////////////////////////////////////////////////////////////////////
#include <iostream.h>

/////////////////////////////////////////////////////////////////////////////
//  The following recursive type equations define the abstract syntax
//  of our small language.
//  ( Note: we define our own boolean type because not all C++ compilers
//    have bool built-in yet. )
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Forward class definition for List<T>
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_List_defined
#define datatype_List_defined
#   define List(T) a_List<T> *
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype List<T>
///////////////////////////////////////////////////////////////////////////////
template <class T> class a_List; // base class for datatype List<T>

///////////////////////////////////////////////////////////////////////////////
// Definition of datatype 'BOOL'
///////////////////////////////////////////////////////////////////////////////
enum BOOL {
   False = 0, True = 1
};

///////////////////////////////////////////////////////////////////////////////
// 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_integer;	// subclass for 'integer int'
   class Exp_real;	// subclass for 'real double'
   class Exp_string;	// subclass for 'string char *'
   class Exp_boolean;	// subclass for 'boolean BOOL'
   class Exp_binop;	// subclass for 'binop (BinOp, Exp, Exp)'
   class Exp_unaryop;	// subclass for 'unaryop (UnaryOp, Exp)'
   class Exp_var;	// subclass for 'var Id'

///////////////////////////////////////////////////////////////////////////////
// Definition of datatype 'BinOp'
///////////////////////////////////////////////////////////////////////////////
enum BinOp {
   add = 0, sub = 1, mul = 2, divide = 3, 
   mod = 4, logical_and = 5, logical_or = 6, eq = 7, 
   ge = 8, le = 9, lt = 10, gt = 11, 
   ne = 12
};

///////////////////////////////////////////////////////////////////////////////
// Definition of datatype 'UnaryOp'
///////////////////////////////////////////////////////////////////////////////
enum UnaryOp {
   uminus = 0, logical_not = 1
};

///////////////////////////////////////////////////////////////////////////////
// Forward class definition for Stmt
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_Stmt_defined
#define datatype_Stmt_defined
   typedef class a_Stmt * Stmt;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype Stmt
///////////////////////////////////////////////////////////////////////////////
class a_Stmt; // base class for datatype Stmt
   class Stmt_assign_stmt;	// subclass for 'assign_stmt (Id, Exp)'
   class Stmt_while_stmt;	// subclass for 'while_stmt (Exp, Stmt)'
   class Stmt_if_stmt;	// subclass for 'if_stmt (Exp, Stmt, Stmt)'
   class Stmt_print_stmt;	// subclass for 'print_stmt Exp'
   class Stmt_block_stmt;	// subclass for 'block_stmt (List<Decl> , List<Stmt> )'

///////////////////////////////////////////////////////////////////////////////
// Forward class definition for Type
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_Type_defined
#define datatype_Type_defined
   typedef class a_Type * Type;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype Type
///////////////////////////////////////////////////////////////////////////////
class a_Type; // base class for datatype Type
   class Type_primitive_type;	// subclass for 'primitive_type Id'
   class Type_pointer_type;	// subclass for 'pointer_type Type'
   class Type_array_type;	// subclass for 'array_type { element : Type, bound : Exp }'
   class Type_function_type;	// subclass for 'function_type { arg : Type, ret : Type }'
   class Type_tuple_type;	// subclass for 'tuple_type List<Type> '
   class Type_record_type;	// subclass for 'record_type List<LabeledType> '

///////////////////////////////////////////////////////////////////////////////
// Forward class definition for Decl
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_Decl_defined
#define datatype_Decl_defined
   typedef class a_Decl * Decl;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype Decl
///////////////////////////////////////////////////////////////////////////////
class a_Decl; // base class for datatype Decl

///////////////////////////////////////////////////////////////////////////////
// Forward class definition for LabeledType
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_LabeledType_defined
#define datatype_LabeledType_defined
   typedef class a_LabeledType * LabeledType;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype LabeledType
///////////////////////////////////////////////////////////////////////////////
class a_LabeledType; // base class for datatype LabeledType

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'List<T>'
///////////////////////////////////////////////////////////////////////////////
template <class T> 
   class a_List : public TermObj {
   public:
#  define nil_1_ 0
      inline friend int boxed(const a_List * x) { return x != 0; }
      inline friend int untag(const a_List * x) { return x ? 1 : 0; }
      T _1; a_List<T> *  _2; 
      inline a_List (T _x1, a_List<T> *  _x2)
         : _1(_x1), _2(_x2) {}
      inline friend a_List<T> * list_1_ (T _x1, a_List<T> *  _x2)
         { return new a_List<T> (_x1, _x2); }
   };

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Exp'
///////////////////////////////////////////////////////////////////////////////
class a_Exp : public TermObj {
public:
   enum Tag_Exp {
      tag_integer = 0, tag_real = 1, tag_string = 2, tag_boolean = 3, 
      tag_binop = 4, tag_unaryop = 5, tag_var = 6
   };

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_integer * _integer(Exp _x_) { return (Exp_integer *)_x_; }
   inline friend Exp_real * _real(Exp _x_) { return (Exp_real *)_x_; }
   inline friend Exp_string * _string(Exp _x_) { return (Exp_string *)_x_; }
   inline friend Exp_boolean * _boolean(Exp _x_) { return (Exp_boolean *)_x_; }
   inline friend Exp_binop * _binop(Exp _x_) { return (Exp_binop *)_x_; }
   inline friend Exp_unaryop * _unaryop(Exp _x_) { return (Exp_unaryop *)_x_; }
   inline friend Exp_var * _var(Exp _x_) { return (Exp_var *)_x_; }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::integer int'
///////////////////////////////////////////////////////////////////////////////
class Exp_integer : public a_Exp {
public:
   int integer; 
   inline Exp_integer (int _xinteger)
      : a_Exp(a_Exp::tag_integer), integer(_xinteger) {}
   inline friend a_Exp * integer (int _xinteger)
      { return new Exp_integer (_xinteger); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::real double'
///////////////////////////////////////////////////////////////////////////////
class Exp_real : public a_Exp {
public:
   double real; 
   inline Exp_real (double _xreal)
      : a_Exp(a_Exp::tag_real), real(_xreal) {}
   inline friend a_Exp * real (double _xreal)
      { return new Exp_real (_xreal); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::string char *'
///////////////////////////////////////////////////////////////////////////////
class Exp_string : public a_Exp {
public:
   char * string; 
   inline Exp_string (char * _xstring)
      : a_Exp(a_Exp::tag_string), string(_xstring) {}
   inline friend a_Exp * string (char * _xstring)
      { return new Exp_string (_xstring); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::boolean BOOL'
///////////////////////////////////////////////////////////////////////////////
class Exp_boolean : public a_Exp {
public:
   BOOL boolean; 
   inline Exp_boolean (BOOL _xboolean)
      : a_Exp(a_Exp::tag_boolean), boolean(_xboolean) {}
   inline friend a_Exp * boolean (BOOL _xboolean)
      { return new Exp_boolean (_xboolean); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::binop (BinOp, Exp, Exp)'
///////////////////////////////////////////////////////////////////////////////
class Exp_binop : public a_Exp {
public:
   BinOp _1; Exp _2; Exp _3; 
   inline Exp_binop (BinOp _x1, Exp _x2, Exp _x3)
      : a_Exp(a_Exp::tag_binop), _1(_x1), _2(_x2), _3(_x3) {}
   inline friend a_Exp * binop (BinOp _x1, Exp _x2, Exp _x3)
      { return new Exp_binop (_x1, _x2, _x3); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Exp::unaryop (UnaryOp, Exp)'
///////////////////////////////////////////////////////////////////////////////
class Exp_unaryop : public a_Exp {
public:
   UnaryOp _1; Exp _2; 
   inline Exp_unaryop (UnaryOp _x1, Exp _x2)
      : a_Exp(a_Exp::tag_unaryop), _1(_x1), _2(_x2) {}
   inline friend a_Exp * unaryop (UnaryOp _x1, Exp _x2)
      { return new Exp_unaryop (_x1, _x2); }
};

///////////////////////////////////////////////////////////////////////////////
// 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); }
};

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

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

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Stmt'
///////////////////////////////////////////////////////////////////////////////
class a_Stmt : public TermObj {
public:
   enum Tag_Stmt {
      tag_assign_stmt = 0, tag_while_stmt = 1, tag_if_stmt = 2, tag_print_stmt = 3, 
      tag_block_stmt = 4
   };

protected:
   const Tag_Stmt _tag_;
   inline a_Stmt(Tag_Stmt _t_) : _tag_(_t_) {}
public:
   inline int untag() const { return _tag_; }
   inline friend int boxed(const a_Stmt * x) { return 1; }
   inline friend int untag(const a_Stmt * x) { return x->_tag_; }
   ////////////////////////////////////////////////////////////////////////////
   // Downcasting functions for Stmt
   ////////////////////////////////////////////////////////////////////////////
   inline friend Stmt_assign_stmt * _assign_stmt(Stmt _x_) { return (Stmt_assign_stmt *)_x_; }
   inline friend Stmt_while_stmt * _while_stmt(Stmt _x_) { return (Stmt_while_stmt *)_x_; }
   inline friend Stmt_if_stmt * _if_stmt(Stmt _x_) { return (Stmt_if_stmt *)_x_; }
   inline friend Stmt_print_stmt * _print_stmt(Stmt _x_) { return (Stmt_print_stmt *)_x_; }
   inline friend Stmt_block_stmt * _block_stmt(Stmt _x_) { return (Stmt_block_stmt *)_x_; }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Stmt::assign_stmt (Id, Exp)'
///////////////////////////////////////////////////////////////////////////////
class Stmt_assign_stmt : public a_Stmt {
public:
   Id _1; Exp _2; 
   inline Stmt_assign_stmt (Id _x1, Exp _x2)
      : a_Stmt(a_Stmt::tag_assign_stmt), _1(_x1), _2(_x2) {}
   inline friend a_Stmt * assign_stmt (Id _x1, Exp _x2)
      { return new Stmt_assign_stmt (_x1, _x2); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Stmt::while_stmt (Exp, Stmt)'
///////////////////////////////////////////////////////////////////////////////
class Stmt_while_stmt : public a_Stmt {
public:
   Exp _1; Stmt _2; 
   inline Stmt_while_stmt (Exp _x1, Stmt _x2)
      : a_Stmt(a_Stmt::tag_while_stmt), _1(_x1), _2(_x2) {}
   inline friend a_Stmt * while_stmt (Exp _x1, Stmt _x2)
      { return new Stmt_while_stmt (_x1, _x2); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Stmt::if_stmt (Exp, Stmt, Stmt)'
///////////////////////////////////////////////////////////////////////////////
class Stmt_if_stmt : public a_Stmt {
public:
   Exp _1; Stmt _2; Stmt _3; 
   inline Stmt_if_stmt (Exp _x1, Stmt _x2, Stmt _x3)
      : a_Stmt(a_Stmt::tag_if_stmt), _1(_x1), _2(_x2), _3(_x3) {}
   inline friend a_Stmt * if_stmt (Exp _x1, Stmt _x2, Stmt _x3)
      { return new Stmt_if_stmt (_x1, _x2, _x3); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Stmt::print_stmt Exp'
///////////////////////////////////////////////////////////////////////////////
class Stmt_print_stmt : public a_Stmt {
public:
   Exp print_stmt; 
   inline Stmt_print_stmt (Exp _xprint_stmt)
      : a_Stmt(a_Stmt::tag_print_stmt), print_stmt(_xprint_stmt) {}
   inline friend a_Stmt * print_stmt (Exp _xprint_stmt)
      { return new Stmt_print_stmt (_xprint_stmt); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Stmt::block_stmt (List<Decl> , List<Stmt> )'
///////////////////////////////////////////////////////////////////////////////
class Stmt_block_stmt : public a_Stmt {
public:
   a_List<Decl> *  _1; a_List<Stmt> *  _2; 
   inline Stmt_block_stmt (a_List<Decl> *  _x1, a_List<Stmt> *  _x2)
      : a_Stmt(a_Stmt::tag_block_stmt), _1(_x1), _2(_x2) {}
   inline friend a_Stmt * block_stmt (a_List<Decl> *  _x1, a_List<Stmt> *  _x2)
      { return new Stmt_block_stmt (_x1, _x2); }
};

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Type'
///////////////////////////////////////////////////////////////////////////////
class a_Type : public TermObj {
public:
   enum Tag_Type {
      tag_primitive_type = 0, tag_pointer_type = 1, tag_array_type = 2, tag_function_type = 3, 
      tag_tuple_type = 4, tag_record_type = 5
   };

protected:
   const Tag_Type _tag_;
   inline a_Type(Tag_Type _t_) : _tag_(_t_) {}
public:
   inline int untag() const { return _tag_; }
   inline friend int boxed(const a_Type * x) { return 1; }
   inline friend int untag(const a_Type * x) { return x->_tag_; }
   ////////////////////////////////////////////////////////////////////////////
   // Downcasting functions for Type
   ////////////////////////////////////////////////////////////////////////////
   inline friend Type_primitive_type * _primitive_type(Type _x_) { return (Type_primitive_type *)_x_; }
   inline friend Type_pointer_type * _pointer_type(Type _x_) { return (Type_pointer_type *)_x_; }
   inline friend Type_array_type * _array_type(Type _x_) { return (Type_array_type *)_x_; }
   inline friend Type_function_type * _function_type(Type _x_) { return (Type_function_type *)_x_; }
   inline friend Type_tuple_type * _tuple_type(Type _x_) { return (Type_tuple_type *)_x_; }
   inline friend Type_record_type * _record_type(Type _x_) { return (Type_record_type *)_x_; }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::primitive_type Id'
///////////////////////////////////////////////////////////////////////////////
class Type_primitive_type : public a_Type {
public:
   Id primitive_type; 
   inline Type_primitive_type (Id _xprimitive_type)
      : a_Type(a_Type::tag_primitive_type), primitive_type(_xprimitive_type) {}
   inline friend a_Type * primitive_type (Id _xprimitive_type)
      { return new Type_primitive_type (_xprimitive_type); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::pointer_type Type'
///////////////////////////////////////////////////////////////////////////////
class Type_pointer_type : public a_Type {
public:
   Type pointer_type; 
   inline Type_pointer_type (Type _xpointer_type)
      : a_Type(a_Type::tag_pointer_type), pointer_type(_xpointer_type) {}
   inline friend a_Type * pointer_type (Type _xpointer_type)
      { return new Type_pointer_type (_xpointer_type); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::array_type { element : Type, bound : Exp }'
///////////////////////////////////////////////////////////////////////////////
class Type_array_type : public a_Type {
public:
   Type element; Exp bound; 
   inline Type_array_type (Type _xelement, Exp _xbound)
      : a_Type(a_Type::tag_array_type), element(_xelement), bound(_xbound) {}
   inline friend a_Type * array_type (Type _xelement, Exp _xbound)
      { return new Type_array_type (_xelement, _xbound); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::function_type { arg : Type, ret : Type }'
///////////////////////////////////////////////////////////////////////////////
class Type_function_type : public a_Type {
public:
   Type arg; Type ret; 
   inline Type_function_type (Type _xarg, Type _xret)
      : a_Type(a_Type::tag_function_type), arg(_xarg), ret(_xret) {}
   inline friend a_Type * function_type (Type _xarg, Type _xret)
      { return new Type_function_type (_xarg, _xret); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::tuple_type List<Type> '
///////////////////////////////////////////////////////////////////////////////
class Type_tuple_type : public a_Type {
public:
   a_List<Type> *  tuple_type; 
   inline Type_tuple_type (a_List<Type> *  _xtuple_type)
      : a_Type(a_Type::tag_tuple_type), tuple_type(_xtuple_type) {}
   inline friend a_Type * tuple_type (a_List<Type> *  _xtuple_type)
      { return new Type_tuple_type (_xtuple_type); }
};

///////////////////////////////////////////////////////////////////////////////
// class for constructor 'Type::record_type List<LabeledType> '
///////////////////////////////////////////////////////////////////////////////
class Type_record_type : public a_Type {
public:
   a_List<LabeledType> *  record_type; 
   inline Type_record_type (a_List<LabeledType> *  _xrecord_type)
      : a_Type(a_Type::tag_record_type), record_type(_xrecord_type) {}
   inline friend a_Type * record_type (a_List<LabeledType> *  _xrecord_type)
      { return new Type_record_type (_xrecord_type); }
};

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Decl'
///////////////////////////////////////////////////////////////////////////////
class a_Decl : public TermObj {
public:
   inline friend int boxed(const a_Decl * x) { return 1; }
   inline friend int untag(const a_Decl * x) { return 0; }
   Id name; Type typ; 
   inline a_Decl (Id _xname, Type _xtyp)
      : name(_xname), typ(_xtyp) {}
   inline friend a_Decl * decl (Id _xname, Type _xtyp)
      { return new a_Decl (_xname, _xtyp); }
};

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

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'LabeledType'
///////////////////////////////////////////////////////////////////////////////
class a_LabeledType : public TermObj {
public:
   inline friend int boxed(const a_LabeledType * x) { return 1; }
   inline friend int untag(const a_LabeledType * x) { return 0; }
   Id _1; Type _2; 
   inline a_LabeledType (Id _x1, Type _x2)
      : _1(_x1), _2(_x2) {}
   inline friend a_LabeledType * labeled_type (Id _x1, Type _x2)
      { return new a_LabeledType (_x1, _x2); }
};

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

   

/////////////////////////////////////////////////////////////////////////////
//  Refine the implementation of the datatypes.
//  The qualifiers may be also declared in the datatype definition.
//  We qualify the datatypes here so that they won't clutter up
//  the equations above.
//
//  All types are declared to be printable by 
//  the printer method and rewritable.
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//  Generate the interfaces to instantiated polymorphic datatypes.
//  These are not strictly necessary since the instantiation is in the
//  same file below.  However, in general the 'instantiate extern' declaration
//  must be placed in the .h files for each instance of a polymorphic
//  datatype.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Type> 
///////////////////////////////////////////////////////////////////////////////
ostream& operator << (ostream&, List(Type) );
ostream& pretty_print(ostream&, List(Type) , int = 0, int = 0);

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Stmt> 
///////////////////////////////////////////////////////////////////////////////
ostream& operator << (ostream&, List(Stmt) );
ostream& pretty_print(ostream&, List(Stmt) , int = 0, int = 0);

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<LabeledType> 
///////////////////////////////////////////////////////////////////////////////
ostream& operator << (ostream&, List(LabeledType) );
ostream& pretty_print(ostream&, List(LabeledType) , int = 0, int = 0);

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Decl> 
///////////////////////////////////////////////////////////////////////////////
ostream& operator << (ostream&, List(Decl) );
ostream& pretty_print(ostream&, List(Decl) , int = 0, int = 0);



/////////////////////////////////////////////////////////////////////////////
//  Now instantiate all the datatypes.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type Exp
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, Exp _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case a_Exp::tag_integer: 
         _f_ << _integer(_x_)->integer;
         break;
      case a_Exp::tag_real: 
         _f_ << _real(_x_)->real;
         break;
      case a_Exp::tag_string: 
         _f_ << "\"";
         _f_ << _string(_x_)->string;
         _f_ << "\"";
         break;
      case a_Exp::tag_boolean: 
         pretty_print(_f_, _boolean(_x_)->boolean, _tab_, _prec_);
         break;
      case a_Exp::tag_binop: 
         _f_ << "(";
         pretty_print(_f_, _binop(_x_)->_2, _tab_, _prec_);
         pretty_print(_f_, _binop(_x_)->_1, _tab_, _prec_);
         pretty_print(_f_, _binop(_x_)->_3, _tab_, _prec_);
         _f_ << ")";
         break;
      case a_Exp::tag_unaryop: 
         _f_ << "(";
         pretty_print(_f_, _unaryop(_x_)->_1, _tab_, _prec_);
         pretty_print(_f_, _unaryop(_x_)->_2, _tab_, _prec_);
         _f_ << ")";
         break;
      case a_Exp::tag_var: 
         _f_ << _var(_x_)->var;
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type BOOL
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, BOOL _x_, int _tab_, int _prec_)
{
   switch ((_x_)) {
      case False: 
         _f_ << "false";
         break;
      case True: 
         _f_ << "true";
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type BinOp
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, BinOp _x_, int _tab_, int _prec_)
{
   switch ((_x_)) {
      case add: 
         _f_ << " + ";
         break;
      case sub: 
         _f_ << " - ";
         break;
      case mul: 
         _f_ << " * ";
         break;
      case divide: 
         _f_ << " / ";
         break;
      case mod: 
         _f_ << " mod ";
         break;
      case logical_and: 
         _f_ << " and ";
         break;
      case logical_or: 
         _f_ << " or ";
         break;
      case eq: 
         _f_ << " = ";
         break;
      case ge: 
         _f_ << " >= ";
         break;
      case le: 
         _f_ << " <= ";
         break;
      case lt: 
         _f_ << " < ";
         break;
      case gt: 
         _f_ << " > ";
         break;
      case ne: 
         _f_ << " <> ";
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type UnaryOp
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, UnaryOp _x_, int _tab_, int _prec_)
{
   switch ((_x_)) {
      case uminus: 
         _f_ << "- ";
         break;
      case logical_not: 
         _f_ << "not ";
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type Stmt
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, Stmt _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case a_Stmt::tag_assign_stmt: 
         _f_ << _assign_stmt(_x_)->_1;
         _f_ << " := ";
         pretty_print(_f_, _assign_stmt(_x_)->_2, _tab_, _prec_);
         _f_ << ";";
         break;
      case a_Stmt::tag_while_stmt: 
         _f_ << "while ";
         pretty_print(_f_, _while_stmt(_x_)->_1, _tab_, _prec_);
         _f_ << " do";
         _tab_ += 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _while_stmt(_x_)->_2, _tab_, _prec_);
         _tab_ -= 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         _f_ << "end while;";
         break;
      case a_Stmt::tag_if_stmt: 
         _f_ << "if ";
         pretty_print(_f_, _if_stmt(_x_)->_1, _tab_, _prec_);
         _f_ << " then";
         _tab_ += 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _if_stmt(_x_)->_2, _tab_, _prec_);
         _tab_ -= 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         _f_ << " else";
         _tab_ += 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _if_stmt(_x_)->_3, _tab_, _prec_);
         _tab_ -= 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         _f_ << "endif;";
         break;
      case a_Stmt::tag_print_stmt: 
         _f_ << "print ";
         pretty_print(_f_, _print_stmt(_x_)->print_stmt, _tab_, _prec_);
         _f_ << ";";
         break;
      case a_Stmt::tag_block_stmt: 
         _f_ << "begin ";
         _tab_ += 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _block_stmt(_x_)->_1, _tab_, _prec_);
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _block_stmt(_x_)->_2, _tab_, _prec_);
         _tab_ -= 3;
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         _f_ << "end";
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type Type
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, Type _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case a_Type::tag_primitive_type: 
         _f_ << _primitive_type(_x_)->primitive_type;
         break;
      case a_Type::tag_pointer_type: 
         pretty_print(_f_, _pointer_type(_x_)->pointer_type, _tab_, _prec_);
         _f_ << "^";
         break;
      case a_Type::tag_array_type: 
         _f_ << "array ";
         pretty_print(_f_, _array_type(_x_)->bound, _tab_, _prec_);
         _f_ << " of ";
         pretty_print(_f_, _array_type(_x_)->element, _tab_, _prec_);
         break;
      case a_Type::tag_function_type: 
         pretty_print(_f_, _function_type(_x_)->arg, _tab_, _prec_);
         _f_ << " -> ";
         pretty_print(_f_, _function_type(_x_)->ret, _tab_, _prec_);
         break;
      case a_Type::tag_tuple_type: 
         _f_ << "tuple_type";
         _f_ << '(';
         pretty_print(_f_, _tuple_type(_x_)->tuple_type, _tab_, _prec_);
         _f_ << ')';
         break;
      case a_Type::tag_record_type: 
         _f_ << "record_type";
         _f_ << '(';
         pretty_print(_f_, _record_type(_x_)->record_type, _tab_, _prec_);
         _f_ << ')';
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type Decl
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, Decl _x_, int _tab_, int _prec_)
{
   _f_ << "var ";
   _f_ << _x_->name;
   _f_ << " : ";
   pretty_print(_f_, _x_->typ, _tab_, _prec_);
   _f_ << ";";
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type LabeledType
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, LabeledType _x_, int _tab_, int _prec_)
{
   _f_ << _x_->_1;
   _f_ << " : ";
   pretty_print(_f_, _x_->_2, _tab_, _prec_);
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Type> 
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, List(Type) _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case (int)nil_1_: 
         _f_ << "";
         break;
      case 1: 
         pretty_print(_f_, _x_->_1, _tab_, _prec_);
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _x_->_2, _tab_, _prec_);
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Stmt> 
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, List(Stmt) _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case (int)nil_1_: 
         _f_ << "";
         break;
      case 1: 
         pretty_print(_f_, _x_->_1, _tab_, _prec_);
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _x_->_2, _tab_, _prec_);
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<LabeledType> 
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, List(LabeledType) _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case (int)nil_1_: 
         _f_ << "";
         break;
      case 1: 
         pretty_print(_f_, _x_->_1, _tab_, _prec_);
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _x_->_2, _tab_, _prec_);
         break;
   }
   return _f_;
}

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

///////////////////////////////////////////////////////////////////////////////
// Pretty printer for type List<Decl> 
///////////////////////////////////////////////////////////////////////////////
ostream& pretty_print(ostream& _f_, List(Decl) _x_, int _tab_, int _prec_)
{
   switch (untag(_x_)) {
      case (int)nil_1_: 
         _f_ << "";
         break;
      case 1: 
         pretty_print(_f_, _x_->_1, _tab_, _prec_);
         _f_ << '\n';
         PrettyPrinter::print_tabs(_f_,_tab_);
         pretty_print(_f_, _x_->_2, _tab_, _prec_);
         break;
   }
   return _f_;
}

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



/////////////////////////////////////////////////////////////////////////////
//  Defines the interface of a rewrite class Simplify.
//  All types that are referenced (directly or indirectly) should be
//  declared in the interface.
/////////////////////////////////////////////////////////////////////////////
class Simplify : public BURS {
private:
   Simplify(const Simplify&);               // no copy constructor
   void operator = (const Simplify&); // no assignment
public:
   struct Simplify_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); }
          void  labeler(BOOL & redex, int&, int);
   inline virtual void  operator () (BOOL & redex) { int s; labeler(redex,s,0); }
          void  labeler(BinOp & redex, int&, int);
   inline virtual void  operator () (BinOp & redex) { int s; labeler(redex,s,0); }
          void  labeler(UnaryOp & redex, int&, int);
   inline virtual void  operator () (UnaryOp & redex) { int s; labeler(redex,s,0); }
          void  labeler(Stmt & redex, int&, int);
   inline virtual void  operator () (Stmt & redex) { int s; labeler(redex,s,0); }
          void  labeler(Type & redex, int&, int);
   inline virtual void  operator () (Type & redex) { int s; labeler(redex,s,0); }
          void  labeler(Decl & redex, int&, int);
   inline virtual void  operator () (Decl & redex) { int s; labeler(redex,s,0); }
          void  labeler(LabeledType & redex, int&, int);
   inline virtual void  operator () (LabeledType & redex) { int s; labeler(redex,s,0); }
          void  labeler(a_List<Decl> *  & redex, int&, int);
   inline virtual void  operator () (a_List<Decl> *  & redex) { int s; labeler(redex,s,0); }
          void  labeler(a_List<Stmt> *  & redex, int&, int);
   inline virtual void  operator () (a_List<Stmt> *  & redex) { int s; labeler(redex,s,0); }
          void  labeler(a_List<Type> *  & redex, int&, int);
   inline virtual void  operator () (a_List<Type> *  & redex) { int s; labeler(redex,s,0); }
          void  labeler(a_List<LabeledType> *  & redex, int&, int);
   inline virtual void  operator () (a_List<LabeledType> *  & redex) { int s; labeler(redex,s,0); }
private: 
   public:
      Simplify() {}
      // Method to print an error message 
      void error(const char message[]) { cerr << message << '\n'; }
};


/////////////////////////////////////////////////////////////////////////////
//  Now defines the rewrite rules.  These rules will be compiled into 
//  efficient pattern matching code by the translator.  A real life 
//  system will probably have many more rules than presented here.
//  (A machine code generator usually needs a few hundred rules)
//  Currently there are about 60 rules in this class.
/////////////////////////////////////////////////////////////////////////////
static const TreeTables::Offset Simplify_accept_base [ 99 ] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 16, 18, 
   22, 26, 34, 36, 39, 41, 45, 49, 51, 53, 55, 57, 59, 61, 63, 65, 
   67, 69, 73, 76, 79, 85, 92, 94, 97, 100, 102, 106, 110, 112, 115, 118, 
   125, 128, 130, 134, 136, 138, 140, 142, 144, 148, 151, 153, 157, 160, 162, 165, 
   167, 169, 170, 172, 174, 178, 182, 185, 187, 191, 195, 198, 200, 204, 207, 209, 
   213, 216, 218
};
static const TreeTables::Rule Simplify_accept_vector [ 220 ] = {
   -1, 17, -1, 18, -1, 19, -1, 21, -1, 20, -1, 16, -1, 7, 8, -1, 
   38, -1, 38, 5, 6, -1, 35, 37, 48, -1, 34, 35, 36, 37, 47, 48, 
   4, -1, 33, -1, 33, 3, -1, 32, -1, 32, 2, 31, -1, 34, 36, 47, 
   -1, 31, -1, 14, -1, 0, -1, 23, -1, 24, -1, 25, -1, 27, -1, 26, 
   -1, 22, -1, 46, -1, 46, 12, 13, -1, 46, 0, -1, 43, 45, -1, 42, 
   43, 44, 45, 11, -1, 34, 36, 43, 45, 47, 0, -1, 41, -1, 41, 10, 
   -1, 41, 0, -1, 40, -1, 39, 40, 9, -1, 40, 0, 31, -1, 1, -1, 
   38, 1, -1, 42, 44, -1, 35, 37, 42, 44, 48, 1, -1, 33, 1, -1, 
   39, -1, 32, 39, 1, -1, 15, -1, 29, -1, 28, -1, 30, -1, 56, -1, 
   54, 56, 29, -1, 56, 29, -1, 51, -1, 49, 51, 28, -1, 51, 28, -1, 
   54, -1, 54, 29, -1, 49, -1, 49, 28, -1, 58, -1, 55, -1, 53, 55, 
   29, -1, 54, 55, 29, -1, 55, 29, -1, 52, -1, 50, 52, 28, -1, 49, 
   52, 28, -1, 52, 28, -1, 53, -1, 53, 56, 29, -1, 53, 29, -1, 50, 
   -1, 50, 51, 28, -1, 50, 28, -1, 57, -1, 59, -1
};
static const TreeTables::State Simplify_theta_3[3] = {
   20, 21, 22
};


static const TreeTables::State Simplify_theta_4[14][6][6] = {
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 41, 0, 0, 0 },
   { 0, 60, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 36, 57, 0, 0, 0 },
   { 39, 37, 59, 39, 39, 39 },
   { 65, 66, 58, 65, 65, 65 },
   { 0, 36, 57, 0, 0, 0 },
   { 0, 36, 57, 0, 0, 0 },
   { 0, 36, 57, 0, 0, 0 } },
   { { 0, 34, 54, 0, 0, 0 },
   { 0, 35, 56, 0, 0, 0 },
   { 0, 64, 55, 0, 0, 0 },
   { 0, 34, 54, 0, 0, 0 },
   { 0, 34, 54, 0, 0, 0 },
   { 0, 34, 54, 0, 0, 0 } },
   { { 0, 32, 51, 0, 0, 0 },
   { 38, 33, 53, 38, 38, 38 },
   { 62, 63, 52, 62, 62, 62 },
   { 0, 32, 51, 0, 0, 0 },
   { 0, 32, 51, 0, 0, 0 },
   { 0, 32, 51, 0, 0, 0 } },
   { { 0, 30, 48, 0, 0, 0 },
   { 0, 31, 50, 0, 0, 0 },
   { 0, 61, 49, 0, 0, 0 },
   { 0, 30, 48, 0, 0, 0 },
   { 0, 30, 48, 0, 0, 0 },
   { 0, 30, 48, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 29, 41, 0, 0, 0 },
   { 0, 60, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 74, 87 },
   { 0, 0, 41, 0, 74, 87 },
   { 0, 60, 0, 0, 74, 87 },
   { 0, 0, 0, 69, 76, 90 },
   { 79, 79, 79, 80, 75, 89 },
   { 94, 94, 94, 96, 95, 88 } },
   { { 0, 0, 0, 0, 71, 83 },
   { 0, 0, 41, 0, 71, 83 },
   { 0, 60, 0, 0, 71, 83 },
   { 0, 0, 0, 68, 73, 86 },
   { 77, 77, 77, 78, 72, 85 },
   { 91, 91, 91, 93, 92, 84 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 28, 41, 0, 0, 0 },
   { 0, 60, 47, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 27, 41, 0, 0, 0 },
   { 0, 60, 46, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 26, 41, 0, 0, 0 },
   { 0, 60, 45, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 25, 41, 0, 0, 0 },
   { 0, 60, 44, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 24, 41, 0, 0, 0 },
   { 0, 60, 43, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } },
   { { 0, 0, 0, 0, 0, 0 },
   { 0, 23, 41, 0, 0, 0 },
   { 0, 60, 42, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0 } }
};


static const TreeTables::State Simplify_theta_5[3][4] = {
   { 0, 0, 0, 0 },
   { 0, 40, 67, 0 },
   { 0, 0, 0, 70 }
};


static const TreeTables::State Simplify_theta_25[2][1] = {
   { 0 },
   { 81 }
};


static const TreeTables::State Simplify_theta_26[3][1][1] = {
   { { 0 } },
   { { 82 } },
   { { 97 } }
};


static const TreeTables::State Simplify_theta_40[2][1] = {
   { 0 },
   { 98 }
};


static const DFATables::State Simplify_check [ 113 ] = {
   0, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
   7, 7, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 8, 8, 8, 8, 
   8, 11, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0
};
static const DFATables::State Simplify_next [ 113 ] = {
   0, 1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
   1, 2, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 3, 
   3, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
   0
};
inline void  Simplify::labeler(char const * redex,int& s__,int)
{
   {
s__ = 0;
   }
}

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

void  Simplify::labeler (UnaryOp & redex, int& s__, int r__)
{
replacement__:
   s__ = redex + 16;
   
}

void  Simplify::labeler (List(Decl) & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   if ((redex)) {
      int s0__;
      int s1__;
      labeler(redex->_1, s0__, r__);
      labeler(redex->_2, s1__, r__);
      s__ = 0;
   } else {s__ = 0;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (Exp & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   switch(redex->untag()) {
      case a_Exp::tag_integer: { 
         int s0__;
         s0__ = 0; // int
         s__ = 18;} break;
      case a_Exp::tag_real: { 
         int s0__;
         s0__ = 0; // double
         s__ = 19;} break;
      case a_Exp::tag_string: { 
         int s0__;
         labeler(_string(redex)->string, s0__, r__);
         s__ = 0;} break;
      case a_Exp::tag_boolean: { 
         int s0__;
         labeler(_boolean(redex)->boolean, s0__, r__);
         s__ = Simplify_theta_3[Simplify_check[0 + s0__] == 3 ? Simplify_next[0 + s0__] : 0]; } break;
      case a_Exp::tag_binop: { 
         int s0__;
         int s1__;
         int s2__;
         labeler(_binop(redex)->_1, s0__, r__);
         labeler(_binop(redex)->_2, s1__, r__);
         labeler(_binop(redex)->_3, s2__, r__);
         s__ = Simplify_theta_4[Simplify_check[0 + s0__] == 4 ? Simplify_next[0 + s0__] : 0][Simplify_check[0 + s1__] == 5 ? Simplify_next[0 + s1__] : 0][Simplify_check[5 + s2__] == 6 ? Simplify_next[5 + s2__] : 0]; } break;
      case a_Exp::tag_unaryop: { 
         int s0__;
         int s1__;
         labeler(_unaryop(redex)->_1, s0__, r__);
         labeler(_unaryop(redex)->_2, s1__, r__);
         s__ = Simplify_theta_5[Simplify_check[0 + s0__] == 7 ? Simplify_next[0 + s0__] : 0][Simplify_check[10 + s1__] == 8 ? Simplify_next[10 + s1__] : 0]; } break;
      default: { 
         int s0__;
         labeler(_var(redex)->var, s0__, r__);
         s__ = 0;} break;
   }
   const TreeTables::Rule * o__ = Simplify_accept_vector + Simplify_accept_base[s__];
accept__:
   switch (*o__) {
      case 56: {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }} break;
      case 55: {
         { redex = boolean(True); r__ = 1; goto replacement__; }} break;
      case 54: {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }} break;
      case 53: {
         { redex = boolean(True); r__ = 1; goto replacement__; }} break;
      case 52: {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }} break;
      case 51: {
         { redex = boolean(False); r__ = 1; goto replacement__; }} break;
      case 50: {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }} break;
      case 49: {
         { redex = boolean(False); r__ = 1; goto replacement__; }} break;
      case 48: if ((_integer(_binop(redex)->_3)->integer == 2))
      {
         { redex = binop(add,_binop(redex)->_2,_binop(redex)->_2); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 47: if ((_integer(_binop(redex)->_2)->integer == 2))
      {
         { redex = binop(add,_binop(redex)->_3,_binop(redex)->_3); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 46: if ((_real(_binop(redex)->_3)->real == 1.000000))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 45: if ((_real(_binop(redex)->_3)->real == 1.000000))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 44: if ((_real(_binop(redex)->_2)->real == 1.000000))
      {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 43: if ((_real(_binop(redex)->_3)->real == 0.000000))
      {
         { redex = real(0.000000); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 42: if ((_real(_binop(redex)->_2)->real == 0.000000))
      {
         { redex = real(0.000000); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 41: if ((_real(_binop(redex)->_3)->real == 0.000000))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 40: if ((_real(_binop(redex)->_3)->real == 0.000000))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 39: if ((_real(_binop(redex)->_2)->real == 0.000000))
      {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 38: if ((_integer(_binop(redex)->_3)->integer == 1))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 37: if ((_integer(_binop(redex)->_3)->integer == 1))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 36: if ((_integer(_binop(redex)->_2)->integer == 1))
      {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 35: if ((_integer(_binop(redex)->_3)->integer == 0))
      {
         { redex = integer(0); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 34: if ((_integer(_binop(redex)->_2)->integer == 0))
      {
         { redex = integer(0); r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 33: if ((_integer(_binop(redex)->_3)->integer == 0))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 32: if ((_integer(_binop(redex)->_3)->integer == 0))
      {
         { redex = _binop(redex)->_2; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 31: if ((_integer(_binop(redex)->_2)->integer == 0))
      {
         { redex = _binop(redex)->_3; r__ = 1; goto replacement__; }}
      else { ++o__; goto accept__; } break;
      case 30: {
         { redex = boolean(BOOL((! _boolean(_unaryop(redex)->_2)->boolean))); r__ = 1; goto replacement__; }} break;
      case 29: {
         { redex = boolean(BOOL((_boolean(_binop(redex)->_2)->boolean || _boolean(_binop(redex)->_3)->boolean))); r__ = 1; goto replacement__; }} break;
      case 28: {
         { redex = boolean(BOOL((_boolean(_binop(redex)->_2)->boolean && _boolean(_binop(redex)->_3)->boolean))); r__ = 1; goto replacement__; }} break;
      case 27: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real <= _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 26: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real >= _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 25: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real < _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 24: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real > _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 23: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real != _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 22: {
         { redex = boolean(BOOL((_real(_binop(redex)->_2)->real == _real(_binop(redex)->_3)->real))); r__ = 1; goto replacement__; }} break;
      case 21: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer <= _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 20: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer >= _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 19: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer < _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 18: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer > _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 17: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer != _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 16: {
         { redex = boolean(BOOL((_integer(_binop(redex)->_2)->integer == _integer(_binop(redex)->_3)->integer))); r__ = 1; goto replacement__; }} break;
      case 15: {
         { redex = real((- _real(_unaryop(redex)->_2)->real)); r__ = 1; goto replacement__; }} break;
      case 14: {
         { redex = integer((- _integer(_unaryop(redex)->_2)->integer)); r__ = 1; goto replacement__; }} break;
      case 13: {
         { redex = real((_real(_binop(redex)->_2)->real / _real(_binop(redex)->_3)->real)); r__ = 1; goto replacement__; }} break;
      case 12: if ((_real(_binop(redex)->_3)->real == 0.000000))
      { error("division by zero"); }
      else { ++o__; goto accept__; } break;
      case 11: {
         { redex = real((_real(_binop(redex)->_2)->real * _real(_binop(redex)->_3)->real)); r__ = 1; goto replacement__; }} break;
      case 10: {
         { redex = real((_real(_binop(redex)->_2)->real - _real(_binop(redex)->_3)->real)); r__ = 1; goto replacement__; }} break;
      case 9: {
         { redex = real((_real(_binop(redex)->_2)->real + _real(_binop(redex)->_3)->real)); r__ = 1; goto replacement__; }} break;
      case 8: {
         { redex = integer((_integer(_binop(redex)->_2)->integer % _integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 7: if ((_integer(_binop(redex)->_3)->integer == 0))
      { error("modulo by zero"); }
      else { ++o__; goto accept__; } break;
      case 6: {
         { redex = integer((_integer(_binop(redex)->_2)->integer / _integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 5: if ((_integer(_binop(redex)->_3)->integer == 0))
      { error("division by zero"); }
      else { ++o__; goto accept__; } break;
      case 4: {
         { redex = integer((_integer(_binop(redex)->_2)->integer * _integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 3: {
         { redex = integer((_integer(_binop(redex)->_2)->integer - _integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 2: {
         { redex = integer((_integer(_binop(redex)->_2)->integer + _integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 1: {
         { redex = binop(_binop(redex)->_1,real(_real(_binop(redex)->_2)->real),real(_integer(_binop(redex)->_3)->integer)); r__ = 1; goto replacement__; }} break;
      case 0: {
         { redex = binop(_binop(redex)->_1,real(_integer(_binop(redex)->_2)->integer),real(_real(_binop(redex)->_3)->real)); r__ = 1; goto replacement__; }} break;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (BOOL & redex, int& s__, int r__)
{
replacement__:
   s__ = redex + 1;
   
}

void  Simplify::labeler (Stmt & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   switch(redex->untag()) {
      case a_Stmt::tag_assign_stmt: { 
         int s0__;
         int s1__;
         labeler(_assign_stmt(redex)->_1, s0__, r__);
         labeler(_assign_stmt(redex)->_2, s1__, r__);
         s__ = 0;} break;
      case a_Stmt::tag_while_stmt: { 
         int s0__;
         int s1__;
         labeler(_while_stmt(redex)->_1, s0__, r__);
         labeler(_while_stmt(redex)->_2, s1__, r__);
         s__ = Simplify_theta_25[Simplify_check[14 + s0__] == 9 ? Simplify_next[14 + s0__] : 0][0]; } break;
      case a_Stmt::tag_if_stmt: { 
         int s0__;
         int s1__;
         int s2__;
         labeler(_if_stmt(redex)->_1, s0__, r__);
         labeler(_if_stmt(redex)->_2, s1__, r__);
         labeler(_if_stmt(redex)->_3, s2__, r__);
         s__ = Simplify_theta_26[Simplify_check[12 + s0__] == 11 ? Simplify_next[12 + s0__] : 0][0][0]; } break;
      case a_Stmt::tag_print_stmt: { 
         int s0__;
         labeler(_print_stmt(redex)->print_stmt, s0__, r__);
         s__ = 0;} break;
      default: { 
         int s0__;
         int s1__;
         labeler(_block_stmt(redex)->_1, s0__, r__);
         labeler(_block_stmt(redex)->_2, s1__, r__);
         s__ = 0;} break;
   }
   switch (s__) {
      case 82: {
         { redex = _if_stmt(redex)->_3; r__ = 1; goto replacement__; }} break;
      case 97: {
         { redex = _if_stmt(redex)->_2; r__ = 1; goto replacement__; }} break;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (List(Type) & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   if ((redex)) {
      int s0__;
      int s1__;
      labeler(redex->_1, s0__, r__);
      labeler(redex->_2, s1__, r__);
      s__ = 0;
   } else {s__ = 0;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (List(LabeledType) & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   if ((redex)) {
      int s0__;
      int s1__;
      labeler(redex->_1, s0__, r__);
      labeler(redex->_2, s1__, r__);
      s__ = 0;
   } else {s__ = 0;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (List(Stmt) & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   if ((redex)) {
      int s0__;
      int s1__;
      labeler(redex->_1, s0__, r__);
      labeler(redex->_2, s1__, r__);
      s__ = Simplify_theta_40[Simplify_check[0 + s0__] == 14 ? Simplify_next[0 + s0__] : 0][0]; 
   } else {s__ = 0;
   }
   switch (s__) {
      case 98: {
         { redex = redex->_2; r__ = 1; goto replacement__; }} break;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (Decl & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   int s0__;
   int s1__;
   labeler(redex->name,s0__,r__);
   labeler(redex->typ,s1__,r__);
   s__ = 0;
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (Type & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   switch(redex->untag()) {
      case a_Type::tag_primitive_type: { 
         int s0__;
         labeler(_primitive_type(redex)->primitive_type, s0__, r__);
         s__ = 0;} break;
      case a_Type::tag_pointer_type: { 
         int s0__;
         labeler(_pointer_type(redex)->pointer_type, s0__, r__);
         s__ = 0;} break;
      case a_Type::tag_array_type: { 
         int s0__;
         int s1__;
         labeler(_array_type(redex)->element,s0__,r__);
         labeler(_array_type(redex)->bound,s1__,r__);
         s__ = 0;} break;
      case a_Type::tag_function_type: { 
         int s0__;
         int s1__;
         labeler(_function_type(redex)->arg,s0__,r__);
         labeler(_function_type(redex)->ret,s1__,r__);
         s__ = 0;} break;
      case a_Type::tag_tuple_type: { 
         int s0__;
         labeler(_tuple_type(redex)->tuple_type, s0__, r__);
         s__ = 0;} break;
      default: { 
         int s0__;
         labeler(_record_type(redex)->record_type, s0__, r__);
         s__ = 0;} break;
   }
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (LabeledType & redex, int& s__, int r__)
{
replacement__:
   if (r__ && boxed(redex) && redex->has_rewrite_state())
   { s__ = redex->get_rewrite_state(); return; }
   int s0__;
   int s1__;
   labeler(redex->_1, s0__, r__);
   labeler(redex->_2, s1__, r__);
   s__ = 0;
   if (boxed(redex)) {
      redex->set_rewrite_state(s__);
   }
   
}

void  Simplify::labeler (BinOp & redex, int& s__, int r__)
{
replacement__:
   s__ = redex + 3;
   
}



/////////////////////////////////////////////////////////////////////////////
//  The main program.
//  We'll test it with a simple program.
/////////////////////////////////////////////////////////////////////////////
int main()
{  
   // Instantiate a rewriting object.
   Simplify simplify;

   // The input is the following block:
   //
   //  var x : int;
   //  var y : int;
   //  var z : array [10 * 30] of int;
   //  begin
   //     x = 0 + y * 1;
   //     while (1 <> 1) y := y + 1;
   //     print (not false);
   //  end
   //
   Stmt prog = 
      block_stmt( 
list_1_(decl("x",primitive_type("integer")),list_1_(decl("y",primitive_type("integer")),list_1_(decl("z",array_type(primitive_type("integer"),binop(mul,integer(10),integer(30)))),nil_1_))) ,
                  
list_1_(assign_stmt("x",binop(add,integer(0),binop(mul,var("y"),integer(1)))),list_1_(while_stmt(binop(ne,integer(1),integer(1)),assign_stmt("y",binop(add,var("y"),integer(1)))),list_1_(print_stmt(unaryop(logical_not,boolean(False))),nil_1_))) 
                );
   cout << "Before:\n" << prog << "\n\n";
   simplify(prog);
   cout << "After:\n"  << prog << "\n";
   return 0;
}
/*
------------------------------- Statistics -------------------------------
Merge matching rules         = yes
Number of DFA nodes merged   = 0
Number of ifs generated      = 0
Number of switches generated = 0
Number of labels             = 0
Number of gotos              = 0
Adaptive matching            = disabled
Fast string matching         = disabled
Inline downcasts             = disabled
--------------------------------------------------------------------------
*/

