#include <rpnfunc.h>

#include <algorithm>
#include <iostream>
#include <deque>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

#include <rpn.h>
#include <pathstuff.h>

#ifndef NDEBUG
// Toggle Debug.
#define DEBUG_RPNFUNC_H
#endif


// Implementation
// ------------------------------------------------------------
//


void rpnprogset::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (ds.size()<2)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  bool restore(true);
  if (x1->isprogram())
  {
    rpnprogram * p = (rpnprogram*)x1;
    if ((n.num>=0)&&(n.num<4))
    { 
      restore=false;
      p->state = n.num;
      x0->dec();
    }
  }

  if (restore)
    ds.push_front(x0);
}


void rpnprogset::visit(deque<rpnbase*>& ds,rpnprogram& p)
{
  new rpninteger(ds,p.state);
}


rpnprogset::rpnprogset
(
  deque<rpnbase*>& ds, 
  bool const evaluate
)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnprogset::copy() const
{
  return new rpnprogset(); 
}

void rpnprogset::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}









rpnpush::rpnpush(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnpush::copy() const
{
  return new rpnpush(); 
}

void rpnpush::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
  {
    rpnprogramstackstate().ds2.push_front(ds.front());
    ds.pop_front();
  }

  dec();
}


rpnpop::rpnpop(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnpop::copy() const
{
  return new rpnpop(); 
}

void rpnpop::eval( deque<rpnbase*>& ds )
{
//cout << "rpnpop::eval" << endl;
  if (!rpnprogramstackstate().ds2.empty())
  {
    ds.push_front( rpnprogramstackstate().ds2.front() );
    rpnprogramstackstate().ds2.pop_front();
  }

  dec();
}


rpnpushn::rpnpushn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnpushn::copy() const
{
  return new rpnpushn(); 
}

void rpnpushn::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnpushn::visit(deque<rpnbase*>& ds,rpninteger& k)
{
  if (k.num<0)
    return;

  unsigned int n = (unsigned int)(k.num);

  if (ds.size()<=n)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();

  if (n==0)
    return;

  for (unsigned int i=0, imax=k.num; i<imax; ++i)
  {
    rpnprogramstackstate().ds2.push_front(ds.front());
    ds.pop_front();
  }

  x0->dec();
}


rpnpopn::rpnpopn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnpopn::copy() const
{
  return new rpnpopn(); 
}

void rpnpopn::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnpopn::visit(deque<rpnbase*>& ds,rpninteger& k)
{
  if (k.num<0)
    return;

  unsigned int n = (unsigned int)(k.num);

  if (rpnprogramstackstate().ds2.size()<n)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();

  if (n==0)
    return;

  for (unsigned int i=0, imax=n; i<imax; ++i)
  {
    ds.push_front( rpnprogramstackstate().ds2.front() );
    rpnprogramstackstate().ds2.pop_front();
  }

  x0->dec();
}


dssize2::dssize2(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* dssize2::copy() const
{
  return new dssize2();
}

void dssize2::eval( deque<rpnbase*>& ds )
{
  new rpninteger(ds,rpnprogramstackstate().ds2.size());

  dec();
}


rpneval::rpneval(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpneval::copy() const
{
  return new rpneval(); 
}

void rpneval::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
  {
    rpnbase* x0 = ds.front();
    ds.pop_front();
    x0->eval(ds);
  }

  dec();
}


rpnclear::rpnclear(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnclear::copy() const
{
  return new rpnclear(); 
}

void rpnclear::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
  {
    for (unsigned int i=0, imax=ds.size(); i<imax; ++i)
      ds[i]->dec();

    ds.clear();
  }

  dec();
}


rpnclearvar::rpnclearvar(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnclearvar::copy() const
{
  return new rpnclearvar(); 
}

void rpnclearvar::eval( deque<rpnbase*>& ds )
{
  deque<rpnvar*>& var = rpnprogramstackstate().vs();
  if (!var.empty())
  {
    for (unsigned int i=0, imax=var.size(); i<imax; ++i)
      var[i]->dec();

    var.clear();
  }

  dec();
}


rpnclearboth::rpnclearboth(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnclearboth::copy() const
{
  return new rpnclearboth(); 
}

void rpnclearboth::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
  {
    for (unsigned int i=0, imax=ds.size(); i<imax; ++i)
      ds[i]->dec();

    ds.clear();
  }

  deque<rpnvar*>& var = rpnprogramstackstate().vs();
  if (!var.empty())
  {
    for (unsigned int i=0, imax=var.size(); i<imax; ++i)
      var[i]->dec();

    var.clear();
  }

  dec();
}


rpndup::rpndup(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpndup::copy() const
{
  return new rpndup(); 
}

void rpndup::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds.push_front( ds[0]->copy() );

  dec();
}


rpndupn::rpndupn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpndupn::copy() const
{
  return new rpndupn(); 
}

void rpndupn::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpndupn::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  unsigned int const k(n.num);
  x0->dec();

  if (n.num<=0)
    return;

  if (ds.size()<k)
    return;

  for (unsigned int i=0; i<k; ++i)
    ds.push_front( ds[k-1]->copy() );

}


dssize::dssize(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* dssize::copy() const
{
  return new dssize();
}

void dssize::eval( deque<rpnbase*>& ds )
{
  new rpninteger(ds,ds.size());

  dec();
}


rev::rev(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rev::copy() const
{
  return new rev();
}

void rev::eval( deque<rpnbase*>& ds )
{
  reverse(ds.begin(),ds.end());

  dec();
}


rot::rot(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rot::copy() const
{
  return new rot();
}

void rot::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>2)
    rotate(ds.begin(),ds.begin()+1,ds.begin()+3);

  dec();
}


rotn::rotn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rotn::copy() const
{
  return new rotn();
}

void rotn::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rotn::visit(deque<rpnbase*>& ds,rpninteger& k)
{
  if (k.num==0) //no rotation
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (x1->isinteger())
  {
    int n = ((rpninteger*)x1)->num;

    // Valid state to rotate data. 
    if ((n>0)&&(ds.size()>=(unsigned int)n))
    {
//       STL defines rotation in a minimalistic sense - a positive
//       integer mapping an element maps it back to the start.
//       While this is mathematical, for operational use a +ve and
//       -ve direction is easier. +k rotates it k times, -k is in 
//       the other direction.   

      unsigned int k2 = (n-k.num)%n;
      rotate(ds.begin(),ds.begin()+k2,ds.begin()+n);

      x0->dec();
      x1->dec();

      return;
        
    }
  }

  // Error: restore the stack. 
  ds.push_front(x1);
  ds.push_front(x0);
}

rpnswap::rpnswap(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnswap::copy() const
{
  return new rpnswap();
}

void rpnswap::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
  {
    rpnbase* p = ds[0];
    ds[0] = ds[1];
    ds[1] = p;
  }

  dec();
}


rpnswap2::rpnswap2(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnswap2::copy() const
{
  return new rpnswap2();
}

void rpnswap2::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
  {
    rpnbase* p = ds[0];
    ds[0] = ds[1];
    ds[1] = p;
  }

  dec();
}



dropi::dropi(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* dropi::copy() const
{
  return new dropi();
}

void dropi::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void dropi::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (n.num<0)
    return;

  unsigned int const k = n.num;
  if (ds.size()>(k+1))
  {
    rpnbase* x0 = ds.front();
    ds.pop_front();

    ds.erase(ds.begin()+k);
    x0->dec();
  } 
}


drop::drop(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* drop::copy() const
{
  return new drop();
}

void drop::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
  {
    rpnbase* x0 = ds.front();
    ds.pop_front();
    x0->dec();
  }

  dec();
}

dropsymb::dropsymb(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}


dropn::dropn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* dropn::copy() const
{
  return new dropn();
}

void dropn::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void dropn::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (n.num<0)
    return;

  unsigned int val = n.num;
  if (ds.size()>val)
  {
    rpnbase* x0 = ds.front();
    ds.pop_front();

    ds.erase(ds.begin(),ds.begin()+val);
    x0->dec();
  } 
}


ifthen::ifthen(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* ifthen::copy() const
{
  return new ifthen();
}

void ifthen::eval( deque<rpnbase*>& ds )
{
  if( ds.size()>1)
    ds[1]->accept(ds,*this);
  
  dec();
}

void ifthen::visit(deque<rpnbase*>& ds,rpnreal& n)
{

  rpnbase* x0 = ds.front();
  ds.pop_front();
  // x1 is a pointer to n 
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x1->dec();
    x0->eval(ds);
  }
  else
  {
    x1->dec();
    x0->dec();
  }
}

void ifthen::visit(deque<rpnbase*>& ds,rpninteger& n)
{

  rpnbase* x0 = ds.front();
  ds.pop_front();
  // x1 is a pointer to n 
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x1->dec();
    x0->eval(ds);
  }
  else
  {
    x1->dec();
    x0->dec();
  }
}


thenif::thenif(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* thenif::copy() const
{
  return new thenif();
}

void thenif::eval( deque<rpnbase*>& ds )
{
  if( ds.size()>1)
    ds[0]->accept(ds,*this);
  
  dec();
}

void thenif::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  // x0 is a pointer to n 
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (n.num != 0)
    x1->eval(ds);
  else
    x1->dec();

  x0->dec();
}

void thenif::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  // x0 is a pointer to n 
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (n.num != 0)
    x1->eval(ds);
  else
    x1->dec();

  x0->dec();
}


ifthenelse::ifthenelse(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* ifthenelse::copy() const
{
  return new ifthenelse();
}

void ifthenelse::eval( deque<rpnbase*>& ds )
{
  if( ds.size()>2)
    ds[2]->accept(ds,*this);

  dec();
}

void ifthenelse::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  rpnbase* x2 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x2->dec();
    x0->dec();
    x1->eval(ds);
  }
  else
  {
    x2->dec();
    x1->dec();
    x0->eval(ds);
  }
}

void ifthenelse::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  rpnbase* x2 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x2->dec();
    x0->dec();
    x1->eval(ds);
  }
  else
  {
    x2->dec();
    x1->dec();
    x0->eval(ds);
  }
}


thenelseif::thenelseif(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* thenelseif::copy() const
{
  return new thenelseif();
}

void thenelseif::eval( deque<rpnbase*>& ds )
{
  if( ds.size()>2)
    ds[0]->accept(ds,*this);

  dec();
}

void thenelseif::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  rpnbase* x2 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x1->dec();
    x2->eval(ds);
  }
  else
  {
    x2->dec();
    x1->eval(ds);
  }
  x0->dec();
}

void thenelseif::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  rpnbase* x2 = ds.front();
  ds.pop_front();

  if (n.num != 0)
  {
    x1->dec();
    x2->eval(ds);
  }
  else
  {
    x2->dec();
    x1->eval(ds);
  }
  x0->dec();
}


rpnnot::rpnnot(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnnot::copy() const
{
  return new rpnnot();
}

void rpnnot::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnnot::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  if (n.num==0)
    n.num = 1;
  else
    n.num = 0;
}

void rpnnot::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (n.num==0)
    n.num = 1;
  else
    n.num = 0;
}


rpnneg::rpnneg(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnneg::copy() const
{
  return new rpnneg();
}

void rpnneg::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnneg::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  n.num *= -1;
}

void rpnneg::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  n.num *= -1;
}

void rpnneg::visit(deque<rpnbase*>& ds,rpncomplex& n)
{
  n.num *= -1;
}


var::var(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* var::copy() const
{
  return new var();
}

void var::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void var::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().add(x1,s.str);
  x0->dec();
}


vardel::vardel(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* vardel::copy() const
{
  return new vardel();
}

void vardel::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void vardel::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().erase(s.str);

  x0->dec();
}


vareval::vareval(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* vareval::copy() const
{
  return new vareval();
}

void vareval::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void vareval::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().evaluate(ds,s.str);

  x0->dec();
}

void vareval::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  if (n.num>=0)
  {
    unsigned int const n2 = (unsigned int)(n.num); 
    if (n2<ds.size())
    {
      rpnbase * x = ds[n.num]->copy();
      x->eval(ds);
    }
  }

  x0->dec();
}



void vareval::visit(deque<rpnbase*>& ds,rpnprogram& p)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  x0->eval(ds);
}


varpushd::varpushd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varpushd::copy() const
{
  return new varpushd();
}

void varpushd::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void varpushd::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  bool found(false);
  rpnprogram* p;
  vector<string> v;
  pathstuff().convert(v,s.str);

//for (unsigned int i=0; i<v.size(); ++i)
//{
//  cout << "*" << v[i] << "*" << endl;
//}

  pathstuff().findpath(found,p,v); 

//cout << "varpushd::visit(ds," << s.str << ")" << endl;
//cout << "  found=" << found << endl;

  if (found)
  {
    rpnprogramstackstate().push(p);
    x0->dec();
  }
  else
    ds.push_front(x0); // Restore the stack. 
}

void varpushd::visit(deque<rpnbase*>& ds,rpnprogram& p)
{
  rpnprogramstackstate().push(&p);
}


varpopd::varpopd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varpopd::copy() const
{
  return new varpopd();
}

void varpopd::eval( deque<rpnbase*>& ds )
{
  rpnprogramstackstate().pop();

  dec();
}


depthd::depthd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* depthd::copy() const
{
  return new depthd();
}

void depthd::eval( deque<rpnbase*>& ds )
{
  new rpninteger
  (
    ds,
    rpnprogramstackstate().ps->size() 
  );

  dec();
}


varls::varls(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varls::copy() const
{
  return new varls();
}

void varls::eval( deque<rpnbase*>& ds )
{
  deque<rpnvar*>& v = rpnprogramstackstate().vs();
  if (!v.empty())
  {
    cout << "{ " << endl;
    for (unsigned int i=0, imax=v.size(); i<imax; ++i)
    {
      cout << "  " <<  v[i]->varname << "=";
      cout << v[i]->x << endl; 
    }
    cout << "}" << endl;
  }

  dec();
}


vartree::vartree(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* vartree::copy() const
{
  return new vartree();
}

void vartree::draw(rpnprogram* p, unsigned int const depth)
{
  if(p->variables.empty())
    return;

  string space;
  for (unsigned int i=0; i<depth; ++i)
    space += "  ";

  for (unsigned int i=0, imax=p->variables.size(); i<imax; ++i)
  {
    if (p->variables[i]->x->isprogram())
    {
      cout << space << p->variables[i]->varname << endl;
      draw((rpnprogram*)(p->variables[i]->x),depth+1);
    }
  }
}

void vartree::eval( deque<rpnbase*>& ds )
{
  cout << "." << endl;
  draw(rpnprogramstackstate().ps->front(),1);

  dec();
}


varpwd::varpwd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varpwd::copy() const
{
  return new varpwd();
}

void varpwd::eval( deque<rpnbase*>& ds )
{
  string path;
  bool found(false);
  
//  rpnprogramstackstate().findprogram(
//    found,path,rpnprogramstackstate().ps->front() );

  deque<rpnprogram*> & ps( * rpnprogramstackstate().ps );
  for ( unsigned int i=0; (i<ps.size())&&(!found); ++i )
  {
    rpnprogramstackstate().findprogram(
      found,path,ps[i] );
  }

  if (!found)
    path = "";

  new rpnstring(ds,path);

  dec();
}


pathtoggle::pathtoggle(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* pathtoggle::copy() const
{
  return new pathtoggle();
}

void pathtoggle::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void pathtoggle::visit(deque<rpnbase*>& ds,rpnstring& path)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  if (path.str.empty())
  {
    x0->dec();
    return;
  }
  
  rpnprogram* p = new rpnprogram();

  vector<string> v;
  pathstuff().convert(v,path.str);
  pathstuff().convert(*p,v);

  ds.push_front(p);

  x0->dec();
}

void pathtoggle::visit(deque<rpnbase*>& ds,rpnprogram& path)
{
  rpnbase* x0 = ds.front();

  rpnstring* s = new rpnstring();

  vector<string> v;
  pathstuff().convert(v,path);
  pathstuff().convert(s->str,v);

  ds.pop_front();

  ds.push_front(s);

  x0->dec();
}


varinc::varinc(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varinc::copy() const
{
  return new varinc();
}

void varinc::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}


void varinc::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  n.num += 1;
}

void varinc::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  n.num += 1;
}

void varinc::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  
  bool res;
  unsigned int i,k;
  rpnvar* x;

  rpnprogramstackstate().find(res,i,k,x,s.str);
  if (res)
  {
    bool foundtype(false);

    rpnbase* w = x->x;
    if (w->isinteger())
    {
      ((rpninteger*)w)->num += 1;
      foundtype=true;
    }
    else
    if (w->isreal())
    {
      ((rpnreal*)w)->num += 1;
      foundtype=true;
    }

    if (foundtype)
    {
      w->inc();
      ds.push_front(w);
    }
  }

  x0->dec();
}

vardec::vardec(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* vardec::copy() const
{
  return new vardec();
}

void vardec::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void vardec::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  n.num -= 1;
}

void vardec::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  n.num -= 1;
}

void vardec::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  bool res;
  unsigned int i,k;
  rpnvar* x;

  rpnprogramstackstate().find(res,i,k,x,s.str);
  if (res)
  {
    bool foundtype(false);

    rpnbase* w = x->x;
    if (w->isinteger())
    {
      ((rpninteger*)w)->num -= 1;
      foundtype=true;
    }
    else
    if (w->isreal())
    {
      ((rpnreal*)w)->num -= 1;
      foundtype=true;
    }

    if (foundtype)
    {
      w->inc();
      ds.push_front(w);
    }
  }

  x0->dec();
}




varexists::varexists(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varexists::copy() const
{
  return new varexists();
}

void varexists::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void varexists::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  bool res;
  rpnprogramstackstate().exists(res,s.str);
  new rpninteger(ds,res);
}


varreplace::varreplace(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varreplace::copy() const
{
  return new varreplace();
}

void varreplace::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void varreplace::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().replace(x1,s.str);

  x0->dec();
}

void varreplace::visit(deque<rpnbase*>& ds,rpninteger& k)
{
  if (ds.size()<=3)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  bool restore(false);

  int const sz = ds.size();

  int a;
  int b = k.num;
  if (! x1->isinteger() )
    restore=true;
  else
  {
    a = ((rpninteger*)x1)->num;
    if ( (a<0) || (b<0) || (a>=sz) || (b>=sz) || (a==b) )
      restore=true;
  }

  if (restore)
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  x0->dec();
  x1->dec();

  ds[a]->dec();
  ds[a]=ds[b];
  ds[b]->inc();
}


varrecall::varrecall(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varrecall::copy() const
{
  return new varrecall();
}

void varrecall::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void varrecall::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().recall(ds,s.str);

  x0->dec();
}

void varrecall::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  if (n.num>=0)
  {
    unsigned int const n2 = (unsigned int)(n.num); 
    if (n2<ds.size())
      ds.push_front( ds[n.num]->copy() );
  }

  x0->dec();
}


rpnadd::rpnadd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnadd::copy() const
{
  return new rpnadd();
}

void rpnadd::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnadd::visit(deque<rpnbase*>& ds,rpncomplex& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num += n.num;
    x0->dec();
    return;
  }
  else if (x1->isreal())
  {
    ds.pop_front();
    ds.push_front(x0);
    n.num += ((rpnreal*)x1)->num;
    x1->dec();
    return;
  }
  else if (x1->isinteger())
  {
    ds.pop_front();
    ds.push_front(x0);
    n.num += ((rpninteger*)x1)->num;
    x1->dec();
    return;
  }

  //Restor the stack.
  ds.push_front(x0);
}

void rpnadd::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->isreal())
  {
    ((rpnreal*)(x1))->num += n.num;
    x0->dec();
    return;
  }
  else if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num += n.num;
    x0->dec();
    return;
  }
  else if (x1->isinteger())
  {
    ds.pop_front();
    n.num += ((rpninteger*)x1)->num;
    ds.push_front(x0);
    x1->dec();
    return;
  }

  // Restore the stack.
  ds.push_front(x0);
}

void rpnadd::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpninteger* x0 = (rpninteger*)(ds.front());
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->isinteger())
  {
    ((rpninteger*)(x1))->num += n.num;
    x0->dec(); 
    return;
  }
  else if (x1->isreal())
  {
    ((rpnreal*)(x1))->num += n.num;
    x0->dec();
    return;
  }
  else if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num += n.num;
    x0->dec();
    return;
  }

  // Restor the stack.
  ds.push_front(x0);
}


rpnmultiply::rpnmultiply(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnmultiply::copy() const
{
  return new rpnmultiply();
}

void rpnmultiply::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnmultiply::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->isreal())
  {
    ((rpnreal*)(x1))->num *= n.num;
    x0->dec();
    return;
  }
  else if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num *= n.num;
    x0->dec();
    return;
  }
  else if (x1->isinteger())
  {
    ds.pop_front();
    n.num *= ((rpninteger*)x1)->num;
    ds.push_front(x0);
    x1->dec();
    return;
  }

  // Restore the stack.
  ds.push_front(x0);
}

void rpnmultiply::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpninteger* x0 = (rpninteger*)(ds.front());
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->isinteger())
  {
    ((rpninteger*)(x1))->num *= n.num;
    x0->dec(); 
    return;
  }
  else if (x1->isreal())
  {
    ((rpnreal*)(x1))->num *= n.num;
    x0->dec();
    return;
  }
  else if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num *= n.num;
    x0->dec();
    return;
  }

  // Restor the stack.
  ds.push_front(x0);
}

void rpnmultiply::visit(deque<rpnbase*>& ds,rpncomplex& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpnbase* x1 = ds.front();
  if (x1->iscomplex())
  {
    ((rpncomplex*)(x1))->num *= n.num;
    x0->dec();
    return;
  }
  else if (x1->isreal())
  {
    ds.pop_front();
    ds.push_front(x0);
    n.num *= ((rpnreal*)x1)->num;
    x1->dec();
    return;
  }
  else if (x1->isinteger())
  {
    ds.pop_front();
    ds.push_front(x0);
    n.num *= ((rpninteger*)x1)->num;
    x1->dec();
    return;
  }

  //Restor the stack.
  ds.push_front(x0);
}



rpnlessthan::rpnlessthan(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnlessthan::copy() const
{
  return new rpnlessthan();
}

void rpnlessthan::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnlessthan::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num < n.num );
  }
  else
  if (x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num < n.num );
  }

  x0->dec();
  x1->dec();
}

void rpnlessthan::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num < n.num );
  }
  else
  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num < n.num );
  }

  x0->dec();
  x1->dec();
}


rpnlessthanequal::rpnlessthanequal(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnlessthanequal::copy() const
{
  return new rpnlessthanequal();
}

void rpnlessthanequal::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnlessthanequal::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num <= n.num );
  }
  else
  if (x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num <= n.num );
  }

  x0->dec();
  x1->dec();
}

void rpnlessthanequal::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num <= n.num );
  }
  else
  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num <= n.num );
  }

  x0->dec();
  x1->dec();
}


rpngreaterthanequal::rpngreaterthanequal(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpngreaterthanequal::copy() const
{
  return new rpngreaterthanequal();
}

void rpngreaterthanequal::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpngreaterthanequal::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num >= n.num );
  }
  else
  if (x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num >= n.num );
  }

  x0->dec();
  x1->dec();
}

void rpngreaterthanequal::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num >= n.num );
  }
  else
  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num >= n.num );
  }

  x0->dec();
  x1->dec();
}


rpngreaterthan::rpngreaterthan(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpngreaterthan::copy() const
{
  return new rpngreaterthan();
}

void rpngreaterthan::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpngreaterthan::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num > n.num );
  }
  else
  if (x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num > n.num );
  }

  x0->dec();
  x1->dec();
}

void rpngreaterthan::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num > n.num );
  }
  else
  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num > n.num );
  }

  x0->dec();
  x1->dec();
}


rpnequal::rpnequal(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnequal::copy() const
{
  return new rpnequal();
}

void rpnequal::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnequal::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num == n.num );
  }
  else
  if (x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num == n.num );
  }

  x0->dec();
  x1->dec();
}

void rpnequal::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if ( x1->isreal())
  {
    new rpninteger(ds, ((rpnreal*)x1)->num == n.num );
  }
  else
  if ( x1->isinteger())
  {
    new rpninteger(ds, ((rpninteger*)x1)->num == n.num );
  }

  x0->dec();
  x1->dec();
}


rpnfor::rpnfor(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnfor::copy() const
{
  return new rpnfor();
}

void rpnfor::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}


/*

Weird for loop crap



  if ( x1->isprogram())
  {

    bool flag;
    rpnbase* x3;

    for ( ; flag; )
    {
      x0->copy()->eval(ds);
      x1->copy()->eval(ds);
      x3 = ds.front();
      ds.pop_front();
      if (x3->isinteger())
      {
        flag=((rpninteger*)x3)->num;
        x3->dec();
      }
      else
      {
        new rpnstring(ds,"error in for: test needs to return integer.");
        break;
      }
    }   




*/






void rpnfor::visit(deque<rpnbase*>& ds,rpnprogram& n)
{
  rpnbase* x0 = ds.front();  // body 
  ds.pop_front();
  rpnbase* x1 = ds.front();  // test 
  ds.pop_front();

//cout << "Entering rpnfor" << endl;

  if ( x1->isprogram())
  {

    bool flag(0);
    rpnbase* x3;

    x1->copy()->eval(ds);
    x3 = ds.front();
    ds.pop_front();
    if (x3->isinteger())
    {
      flag=((rpninteger*)x3)->num;
      x3->dec();
    }
    else
    {
      new rpnstring(ds,"error in for: test needs to return integer.");
    }

//
//  MAGIC NUMBER
//  MAGIC NUMBER
//  MAGIC NUMBER
//
//  Limit for loop computation. 
    long unsigned int loopcounter(100000);

    
    for ( ; flag; )
    {
      x0->copy()->eval(ds);

      x1->copy()->eval(ds);
      x3 = ds.front();
      ds.pop_front();
      if (x3->isinteger())
      {
        flag=((rpninteger*)x3)->num;
//cout << "num=" << ((rpninteger*)x3)->num << "  ";
//cout << "flag=" << flag << endl;
        x3->dec();
      }
      else
      {
        new rpnstring(ds,"error in for: test needs to return integer.");
        break;
      }

      --loopcounter;
      if (loopcounter==0)
      {
        new rpnstring(ds,"error:  for in infinite loop.");

        flag=false;
        break;
      }
    }   
 
  }
  else 
  { // Restore the stack and exit. 
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  x0->dec();
  x1->dec();

}




rpnforn::rpnforn(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnforn::copy() const
{
  return new rpnforn();
}

void rpnforn::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnforn::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  long int num = n.num;
  if (num<=0)
    return;

  if ( ! x1->isprogram() )
  {
    ds.push_front(x1);
    ds.push_front(x0);

    return;
  }

  for (long int i=0; i<num; ++i)
  {
    new rpninteger(ds,i); 
    x1->copy()->eval(ds);
  }

  x0->dec();
  x1->dec();
}

void rpnforn::visit(deque<rpnbase*>& ds,rpnprogram& n)
{
  rpnbase* x0 = ds.front();  // body
  ds.pop_front();
  rpnbase* x1 = ds.front();  // test
  ds.pop_front();

  if ( ! x1->isinteger() )
  {
    ds.push_front(x1);
    ds.push_front(x0);

    return;
  }

  long int num = ((rpninteger*)x1)->num;
  if (num<=0)
  {
    ds.push_front(x1);
    ds.push_front(x0);

    return;
  }

  for (long int i=0; i<num; ++i)
  {
    new rpninteger(ds,i); 
    x1->copy()->eval(ds);
  }

  x0->dec();
  x1->dec();
}





prognew::prognew(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* prognew::copy() const
{
  return new prognew();
}

void prognew::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void prognew::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();  
  ds.pop_front();

  if ( (n.num<0) || ((unsigned int) n.num > ds.size()) )
  {
    ds.push_front(x0);
    return;
  }

  rpnprogram* xp = new rpnprogram();

  if (n.num != 0)
  {
    for (unsigned int i=0, imax=n.num; i<imax; ++i)
    {
      xp->v.push_front(ds.front());
      ds.pop_front();
    }
  }

  ds.push_front(xp);

  x0->dec();
}


progdecompose::progdecompose(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* progdecompose::copy() const
{
  return new progdecompose();
}

void progdecompose::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void progdecompose::visit(deque<rpnbase*>& ds,rpnprogram& p)
{
  rpnbase* x0 = ds.front();  
  ds.pop_front();

  unsigned int n = p.v.size();

  if (n>0)
  {
    for (unsigned int i=0; i<n; ++i)
    {
      ds.push_front( p.v.front() );
      p.v.pop_front();
    }
  }

  new rpninteger(ds,n);

  x0->dec();
}






progrev::progrev(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* progrev::copy() const
{
  return new progrev();
}

void progrev::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void progrev::visit(deque<rpnbase*>& ds,rpnprogram& pr)
{
  reverse(pr.v.begin(),pr.v.end());
}


rpnsubtract::rpnsubtract(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnsubtract::copy() const
{
  return new rpnsubtract();
}

void rpnsubtract::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnsubtract::visit(deque<rpnbase*>& ds,rpncomplex& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (x1->iscomplex())
  {
    ((rpncomplex*)x1)->num -= n.num;
    ds.push_front(x1);
    x0->dec();
    return;
  }
  else
  if (x1->isreal())
  {
    n.num *= -1;
    n.num += ((rpnreal*)x1)->num;
    ds.push_front(x0);
    x1->dec();
    return;
  }
  else
  if (x1->isinteger())
  {
    n.num *= -1;
    n.num += ((rpninteger*)x1)->num;
    ds.push_front(x0);
    x1->dec();
    return;
  }

  // Error so restore stack 
  ds.push_front(x1);
  ds.push_front(x0);
}

void rpnsubtract::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (x1->isreal())
  {
    ((rpnreal*)x1)->num -= n.num;
    ds.push_front(x1);
    x0->dec();
    return;
  }
  else
  if (x1->iscomplex())
  {
    ((rpncomplex*)x1)->num -= n.num;
    ds.push_front(x1);
    x0->dec();
    return;
  }
  else
  if ( x1->isinteger())
  {
    n.num *= -1;
    n.num += ((rpninteger*)x1)->num;
    ds.push_front(x0);
    x1->dec();
    return;
  }

  // Error so restore stack 
  ds.push_front(x1);
  ds.push_front(x0);
}

void rpnsubtract::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();

  if ( x1->isreal() )
  {
    ((rpnreal*)x1)->num -= n.num;
    x0->dec();
    return;
  }
  else
  if ( x1->isinteger() )
  {
    ((rpninteger*)x1)->num -= n.num;
    x0->dec();
    return;
  }
  else
  if ( x1->iscomplex() )
  {
    ((rpncomplex*)x1)->num -= n.num;
    x0->dec();
    return;
  }

  // Restore the stack. 
  ds.push_front(x0);
}


rpndivide::rpndivide(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpndivide::copy() const
{
  return new rpndivide();
}

void rpndivide::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpndivide::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  if (x1->isreal())
  {
    ((rpnreal*)x1)->num /= n.num;
    ds.push_front(x1);
    x0->dec();
    return;
  }
  else
  if (x1->iscomplex())
  {
    ((rpncomplex*)x1)->num /= n.num;
    ds.push_front(x1);
    x0->dec();
    return;
  }
  else
  if ( x1->isinteger())
  {
    new rpnreal(ds,((rpninteger*)x1)->num / n.num);
    x0->dec();
    x1->dec();
    return;
  }

  // Error so restore stack 
  ds.push_front(x1);
  ds.push_front(x0);
}

void rpndivide::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();

  if ( x1->isinteger() )
  {
    if ( ((rpninteger*)x1)->num % n.num == 0 )
    {
      ((rpninteger*)x1)->num /= n.num;
      x0->dec();
      return;
    }
    else
    {
      long double w = ((rpninteger*)x1)->num;
      ds.pop_front();
      new rpnreal(ds,w/n.num);
      
      x0->dec();
      x1->dec();
      return;
    }
  }
  else
  if ( x1->isreal())
  {
    ((rpnreal*)x1)->num /= n.num;
    x0->dec();
    return;
  }
  else
  if ( x1->iscomplex())
  {
    ((rpncomplex*)x1)->num /= n.num;
    x0->dec();
    return;
  }

  // Restore the stack. 
  ds.push_front(x0);
}

void rpndivide::visit(deque<rpnbase*>& ds,rpncomplex& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();

  if ( x1->iscomplex())
  {
    ((rpncomplex*)x1)->num /= n.num;
    x0->dec();
    return;
  }
  else
  if ( x1->isreal())
  {
    n.num = ((rpnreal*)x1)->num / n.num;
    ds.pop_front();
    ds.push_front(x0);
    x1->dec();
    return;
  }
  else
  if ( x1->isinteger())
  {
    
    n.num = complex<long double>(1.0,0.0) / n.num;
    n.num *= ((rpninteger*)x1)->num;
    ds.pop_front();
    ds.push_front(x0);
    x1->dec();
    return;
  }
 
  // Restore the stack. 
  ds.push_front(x0);
}

  




isrpnstring::isrpnstring(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* isrpnstring::copy() const
{
  return new isrpnstring();
}

void isrpnstring::eval( deque<rpnbase*>& ds )
{
  if(ds.empty())
    return;

  ds[0]->accept(ds,*this);

  rpninteger* res = new rpninteger();
  res->num = 0;

  if( ds[0]->isstring() )
    res->num = 1;

  ds.push_front(res);

  dec();
}


isrpninteger::isrpninteger(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* isrpninteger::copy() const
{
  return new isrpninteger();
}

void isrpninteger::eval( deque<rpnbase*>& ds )
{
  if(ds.empty())
    return;

  ds[0]->accept(ds,*this);

  rpninteger* res = new rpninteger();
  res->num = 0;

  if( ds[0]->isinteger() )
    res->num = 1;

  ds.push_front(res);

  dec();
}


isrpnreal::isrpnreal(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* isrpnreal::copy() const
{
  return new isrpnreal();
}

void isrpnreal::eval( deque<rpnbase*>& ds )
{
  if(ds.empty())
    return;

  ds[0]->accept(ds,*this);

  rpninteger* res = new rpninteger();
  res->num = 0;

  if( ds[0]->isreal() )
    res->num = 1;

  ds.push_front(res);

  dec();
}




isrpncomplex::isrpncomplex(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* isrpncomplex::copy() const
{
  return new isrpncomplex();
}

void isrpncomplex::eval( deque<rpnbase*>& ds )
{
  if(ds.empty())
    return;

  ds[0]->accept(ds,*this);

  rpninteger* res = new rpninteger();
  res->num = 0;

  if( ds[0]->iscomplex() )
    res->num = 1;

  ds.push_front(res);

  dec();
}





isrpnprogram::isrpnprogram(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* isrpnprogram::copy() const
{
  return new isrpnprogram();
}

void isrpnprogram::eval( deque<rpnbase*>& ds )
{
  if(ds.empty())
    return;

  ds[0]->accept(ds,*this);

  rpninteger* res = new rpninteger();
  res->num = 0;

  if( ds[0]->isprogram() )
    res->num = 1;

  ds.push_front(res);

  dec();
}





pathcd::pathcd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* pathcd::copy() const
{
  return new pathcd();
}

void pathcd::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void pathcd::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  bool found;
  deque<rpnprogram*> programlist;
  vector<string> v;
  pathstuff().convert(v,s.str);

  pathstuff().findpath(found,programlist,v); 

  if (found)
  {  
    rpnprogramstackstate().ps->clear();
    if (!programlist.empty())
    {
      for (unsigned int i=0, imax=programlist.size(); i<imax; ++i)
        rpnprogramstackstate().push(programlist[i]);
    }

    x0->dec();
  }
  else
    ds.push_front(x0); // Restore the stack. 
}

void pathcd::visit(deque<rpnbase*>& ds,rpnprogram& p)
{
  rpnprogramstackstate().push(&p);
}


pathquery::pathquery(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* pathquery::copy() const
{
  return new pathquery();
}

void pathquery::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void pathquery::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  bool found;
  rpnprogram* p;
  vector<string> v;
  pathstuff().convert(v,s.str);

  pathstuff().findpath(found,p,v); 

  rpninteger* x = new rpninteger();
  x->num = 0;

  if (found)
    x->num = 1;

  ds.push_front(x);
}


varmv::varmv(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* varmv::copy() const
{
  return new varmv();
}

void varmv::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void varmv::visit(deque<rpnbase*>& ds,rpnstring& varname)
{
  if (ds.size()<2)
    return;
  
  if (!ds[1]->isstring())
    return;

  deque<rpnvar*>& vs = rpnprogramstackstate().vs();
  if (vs.empty())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  string nm(varname.str);
  bool found = false;
  unsigned int index;
  for (unsigned int i=0, imax=vs.size(); i<imax; ++i)
  {
    if (vs[i]->varname==nm)
    {
      found = true;
      index = i;
      i = imax;
    }
  }

  if (!found)
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  rpnstring* s = (rpnstring*)x1;

  rpnprogram* p;
  vector<string> v;
  pathstuff().convert(v,s->str);

  pathstuff().findpath(found,p,v);
  
  if (!found)
  {
    ds.push_front(x1);
    ds.push_front(x0);

    return;
  }

  p->variables.push_back( vs[index] );
  vs.erase(vs.begin()+index);

  x0->dec();
  x1->dec();
}


rpncp::rpncp(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpncp::copy() const
{
  return new rpncp();
}

void rpncp::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpncp::visit(deque<rpnbase*>& ds,rpnstring& varname)
{
  if (ds.size()<2)
    return;
  
  if (!ds[1]->isstring())
    return;

  deque<rpnvar*>& vs = rpnprogramstackstate().vs();
  if (vs.empty())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();

  string nm(varname.str);
  bool found = false;
  unsigned int index;
  for (unsigned int i=0, imax=vs.size(); i<imax; ++i)
  {
    if (vs[i]->varname==nm)
    {
      found = true;
      index = i;
      i = imax;
    }
  }

  if (!found)
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  rpnstring* s = (rpnstring*)x1;

  rpnprogram* p;
  vector<string> v;
  pathstuff().convert(v,s->str);

  pathstuff().findpath(found,p,v);
  
  if (!found)
  {
    ds.push_front(x1);
    ds.push_front(x0);

    return;
  }

  p->variables.push_back( (rpnvar*)(vs[index]->copy()) );

  x0->dec();
  x1->dec();
}


rpninsert::rpninsert(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpninsert::copy() const
{
  return new rpninsert(); 
}

void rpninsert::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpninsert::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (ds.size()<2)
    return;

  if (n.num<0)
    return;

  unsigned int k = (unsigned int)(n.num);

  if (k+2>ds.size())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  rpnbase* x1 = ds.front();
  ds.pop_front();
 
  ds.insert(ds.begin()+k,x1);

  x0->dec();
}


rpnerase::rpnerase(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnerase::copy() const
{
  return new rpnerase(); 
}

void rpnerase::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnerase::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (ds.size()<2)
    return;

  if (n.num<0)
    return;

  unsigned int k = (unsigned int)(n.num);

  if (k+1>=ds.size())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
 
  deque<rpnbase*>::iterator i = ds.begin()+k;
  (*i)->dec();
  ds.erase(i);

  x0->dec();
}


rpnpointermake::rpnpointermake(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnpointermake::copy() const
{
  return new rpnpointermake(); 
}

void rpnpointermake::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnpointermake::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (ds.size()<=2)
    return;

  if (n.num<0)
    return;

  unsigned int k = (unsigned int)(n.num);

  if (k+1>ds.size())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  x0->dec();
 
  rpnbase* xk = ds[k];
  xk->inc();
  ds.push_front( xk );
}

void rpnpointermake::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();
  
  rpnprogramstackstate().recallpointer(ds,s.str);

  x0->dec();
}


rpnvectormake::rpnvectormake(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnvectormake::copy() const
{
  return new rpnvectormake(); 
}

void rpnvectormake::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnvectormake::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  if (ds.size()<=2)
    return;

  if (n.num<0)
    return;

  unsigned int k = (unsigned int)(n.num);
  if (k+1>=ds.size())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  x0->dec();
 
  rpnbase* xk = new rpnvector(k);
  ds.push_front( xk );
}

void rpnvectormake::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  if (ds.size()<=3)
    return;

  rpnbase* x1 = ds[1];
  if (!x1->isinteger())
    return;

  int n = ((rpninteger*)x1)->num;
  if ( n<0 )
    return;

  unsigned int k = (unsigned int)n;
  if (k+2>=ds.size())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();
  ds.pop_front();

  new rpnvar
  ( 
    *(rpnprogramstackstate().ps->front()),
    new rpnvector(k),
    s.str
  );

  x0->dec();
  x1->dec();
}



rpnvectorpointermake::rpnvectorpointermake
  (deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnvectorpointermake::copy() const
{
  return new rpnvectorpointermake(); 
}

void rpnvectorpointermake::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnvectorpointermake::visit(deque<rpnbase*>& ds,rpnvector& v)
{
  if (ds.size()<=2)
    return;

  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  long int n = ((rpninteger*)x1)->num;

  ds.pop_front();
  ds.pop_front();


  int n2 = v.index();
  n += n2;

  if ( (n<0) || !(n<(int)ds.size()) )
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  x0->dec();
  x1->dec();

  rpnbase* w = ds[n];
  w->inc();
  ds.push_front(w);
}



void rpnvectorpointermake::visit(deque<rpnbase*>& ds,rpninteger& k)
{
  if (ds.size()<=2)
    return;

  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isvector())
    return;

//  int n = ((rpninteger*)x1)->num;

  long int n(k.num);

  ds.pop_front();
  ds.pop_front();


  int n2 = ((rpnvector*)x1)->index();
  n += n2;


  if ( (n<0) || !(n<(int)ds.size()) )
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  x0->dec();
  x1->dec();

  rpnbase* w = ds[n];
  w->inc();
  ds.push_front(w);
}



void rpnvectorpointermake::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  if (ds.size()<=2)
    return;

  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  int n = ((rpninteger*)x1)->num;

  unsigned int sz0 = ds.size();
  rpnprogramstackstate().recallpointer(ds,s.str);
  unsigned int sz1 = ds.size();
  if (sz0==sz1)
    return;

  rpnbase* x2 = ds.front();

  if( ! x2->isvector() )
  {
    x2->dec();
    ds.pop_front();
    return;
  }

  rpnvector& v = *((rpnvector*)x2);

  ds.pop_front();
  ds.pop_front();
  ds.pop_front();

  int n2 = v.index();
  x2->dec();
  n += n2;

  if ( (n<0) || !(n<(int)ds.size()) )
  {
    ds.push_front(x1);
    ds.push_front(x0);
    return;
  }

  x0->dec();
  x1->dec();

  rpnbase* w = ds[n];
  w->inc();
  ds.push_front(w);
}


pstream::pstream(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* pstream::copy() const
{
  return new pstream(); 
}

void pstream::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}


void pstream::visit(deque<rpnbase*>& ds,rpnprogram& p0)
{
  if (ds.size()<2)
    return;

  rpnbase* x1 = ds[1];
  if (! x1->isprogram() )
    return;

  rpnprogram& p1 = *( (rpnprogram*) x1 );

  rpnprogram& p = * new rpnprogram(ds);

  rpnprogramstackstate().push(&p);

  if (!p1.v.empty())
  {
    rpnbase* w;
    for (unsigned int i=0, imax = p1.v.size(); i<imax; ++i)
    {
      w = p1.v[i];
      w->inc();
      p.v.push_front(w);

cout << "*";
p0.print(cout);
cout << endl;

      p0.inc();
      p0.eval( p.v );
    }
  }

  if (!p.v.empty())
    reverse(p.v.begin(),p.v.end());

  rpnprogramstackstate().pop();
}


rpnintegerhex::rpnintegerhex(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnintegerhex::copy() const
{
  return new rpnintegerhex(); 
}

void rpnintegerhex::eval( deque<rpnbase*>& ds )
{
  rpninteger::displaybase=16;

  dec();
}




rpnintegeroct::rpnintegeroct(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnintegeroct::copy() const
{
  return new rpnintegeroct(); 
}

void rpnintegeroct::eval( deque<rpnbase*>& ds )
{
  rpninteger::displaybase=8;

  dec();
}



rpnintegerdec::rpnintegerdec(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnintegerdec::copy() const
{
  return new rpnintegerdec(); 
}

void rpnintegerdec::eval( deque<rpnbase*>& ds )
{
  rpninteger::displaybase=10;

  dec();
}




rpnintegerbin::rpnintegerbin(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnintegerbin::copy() const
{
  return new rpnintegerbin(); 
}

void rpnintegerbin::eval( deque<rpnbase*>& ds )
{
  rpninteger::displaybase=2;

  dec();
}


rpnbitnot::rpnbitnot(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitnot::copy() const
{
  return new rpnbitnot();
}

void rpnbitnot::eval( deque<rpnbase*>& ds )
{
  if (!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitnot::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  n.num = ~n.num;
}


rpnbitxor::rpnbitxor(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitxor::copy() const
{
  return new rpnbitxor();
}

void rpnbitxor::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitxor::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  ds.pop_front();

  ((rpninteger*)x1)->num ^= n.num;
  
  x0->dec();
}


rpnbitand::rpnbitand(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitand::copy() const
{
  return new rpnbitand();
}

void rpnbitand::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitand::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  ds.pop_front();

  ((rpninteger*)x1)->num &= n.num;
  
  x0->dec();
}


rpnbitor::rpnbitor(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitor::copy() const
{
  return new rpnbitor();
}

void rpnbitor::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitor::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  ds.pop_front();

  ((rpninteger*)x1)->num |= n.num;
  
  x0->dec();
}



rpnbitshiftleft::rpnbitshiftleft(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitshiftleft::copy() const
{
  return new rpnbitshiftleft();
}

void rpnbitshiftleft::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitshiftleft::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  ds.pop_front();

  ((rpninteger*)x1)->num = (((rpninteger*)x1)->num << n.num);
  
  x0->dec();
}





rpnbitshiftright::rpnbitshiftright(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnbitshiftright::copy() const
{
  return new rpnbitshiftright();
}

void rpnbitshiftright::eval( deque<rpnbase*>& ds )
{
  if (ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnbitshiftright::visit(deque<rpnbase*>& ds,rpninteger& n)
{
  rpnbase* x0 = ds.front();
  rpnbase* x1 = ds[1];

  if (!x1->isinteger())
    return;

  ds.pop_front();

  ((rpninteger*)x1)->num = (((rpninteger*)x1)->num >> n.num);
  
  x0->dec();
}


rpnintegerconvert::rpnintegerconvert(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnintegerconvert::copy() const
{
  return new rpnintegerconvert();
}

void rpnintegerconvert::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnintegerconvert::visit(deque<rpnbase*>& ds,rpnreal& n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  long int num = (long int)(n.num);

  new rpninteger(ds,num);

  x0->dec();
}


void rpnintegerconvert::visit(deque<rpnbase*>& ds,rpnstring & s)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  long int n;
  stringstream ss(s.str.c_str());
  ss >> n;
  new rpninteger(ds,n);

  x0->dec();
}
rpnstringconvert::rpnstringconvert(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnstringconvert::copy() const
{
  return new rpnstringconvert();
}

void rpnstringconvert::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnstringconvert::visit(deque<rpnbase*>& ds,rpninteger & n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  stringstream ss;
  ss << n.num;

  new rpnstring(ds,ss.str());

  x0->dec();
}

void rpnstringconvert::visit(deque<rpnbase*>& ds,rpnreal & n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  stringstream ss;
  ss << n.num;

  new rpnstring(ds,ss.str());

  x0->dec();
}


rpnfactorial::rpnfactorial(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnfactorial::copy() const
{
  return new rpnfactorial();
}

void rpnfactorial::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnfactorial::visit(deque<rpnbase*>& ds,rpninteger & n)
{
  if (n.num<0)
    return;

  long int num(1);
  for (long int i=1; i<=n.num; ++i)
    num *= i;

  n.num = num;
}


rpnmod::rpnmod(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnmod::copy() const
{
  return new rpnmod();
}

void rpnmod::eval( deque<rpnbase*>& ds )
{
  if(ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpnmod::visit(deque<rpnbase*>& ds,rpninteger & n)
{
  if (!ds[1]->isinteger())
    return;
  if (n.num<1)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpninteger* x1 = (rpninteger *)(ds.front());
  x1->num %= n.num;

  x0->dec();
}


rpnascii::rpnascii(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpnascii::copy() const
{
  return new rpnascii();
}

void rpnascii::eval( deque<rpnbase*>& ds )
{
  if(!ds.empty())
    ds[0]->accept(ds,*this);

  dec();
}

void rpnascii::visit(deque<rpnbase*>& ds,rpninteger & n)
{
  rpnbase* x0 = ds.front();
  ds.pop_front();

  char ch = (char)(n.num);
  string s; s+= ch;
  
  new rpnstring(ds,s);

  x0->dec();
}

void rpnascii::visit(deque<rpnbase*>& ds,rpnstring& s)
{
  if (s.str.empty())
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();

  long int num = s.str[0];
  
  new rpninteger(ds,num);

  x0->dec();
}


rpngcd::rpngcd(deque<rpnbase*>& ds, bool const evaluate)
{
  if (evaluate)
    eval(ds);
  else
    ds.push_front(this);
}

rpnbase* rpngcd::copy() const
{
  return new rpngcd();
}

void rpngcd::eval( deque<rpnbase*>& ds )
{
  if(ds.size()>1)
    ds[0]->accept(ds,*this);

  dec();
}

void rpngcd::visit(deque<rpnbase*>& ds,rpninteger & n)
{
  if (!ds[1]->isinteger())
    return;
  if (n.num<1)
    return;

  rpnbase* x0 = ds.front();
  ds.pop_front();

  rpninteger* x1 = (rpninteger *)(ds.front());

  long int a = x1->num;
  if (a<1)
  {
    ds.push_front(x0);
    return;
  }

  long int b = n.num;

  if (a<b)
  {
    long int c = a;
    a = b;
    b = c;
  }

  if (a!=b)
  {
    for (long int c=a%b;c!=0;)
    {
      a = b;
      b = c;
      c = a%b;
    }

  }
  
  x1->num = b;

  x0->dec();
}






