/*
 * ExprItems.C - methods for all the ExprItem's.
 *
 * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
 *                     University of Berne, Switzerland
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 */

#include <iostream.h>
#include "ExprItems.h"

//___________________________________________________________ Variable

Variable::Variable(const Name& n, Value* val)
: varname(n), theValue(val)
{}
void Variable::process(ValueStack* theStack)
{
  theStack->push(*theValue); 
}
Variable::~Variable(){}
void Variable::print(ValueStack* theStack)
{
  theStack->push(Value((const char*)varname));
}
// there's no way to simplify a variable
int Variable::params() { return -1; } 
ExprItem* Variable::copy() { return new Variable(varname, theValue); }

//___________________________________________________________ Uminus

Uminus::Uminus(){}
Uminus::~Uminus(){}
void Uminus::process(ValueStack* theStack)
{ 
  theStack->push(- theStack->pop()); 
}
void Uminus::print(ValueStack* theStack)
{ 
  theStack->push(Value("-(" + (rcString)theStack->pop() + ")")); 
}
int Uminus::params() { return 1; }
ExprItem* Uminus::copy() { return new Uminus; }

//___________________________________________________________ Not

Not::Not(){}
Not::~Not(){}
void Not::process(ValueStack* theStack)
{
  theStack->push(!theStack->pop());
}
void Not::print(ValueStack* theStack)
{ 
  theStack->push(Value("!(" + (rcString)theStack->pop() + ")")); 
}
int Not::params() { return 1; }
ExprItem* Not::copy() { return new Not; }

//___________________________________________________________ Or

Or::Or(){}
Or::~Or(){}
void Or::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() || theStack->pop());
}
void Or::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " || " +
		             (rcString)theStack->pop() + ")"));
}
int Or::params() { return 2; }
ExprItem* Or::copy() { return new Or; }

//___________________________________________________________ And
 
And::And(){}
And::~And(){}
void And::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() && theStack->pop());
}
void And::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " && " +
		             (rcString)theStack->pop() + ")"));
}
int And::params() { return 2; }
ExprItem* And::copy() { return new And; }

//___________________________________________________________ Neq

Neq::Neq(){}
Neq::~Neq(){}
void Neq::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() != theStack->pop());
}
void Neq::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " != " +
		             (rcString)theStack->pop() + ")"));
}
int Neq::params() { return 2; }
ExprItem* Neq::copy() { return new Neq; }

//___________________________________________________________ Eq

Eq::Eq(){}
Eq::~Eq(){}
void Eq::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() == theStack->pop());
}
void Eq::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " == " +
		             (rcString)theStack->pop() + ")"));
}
int Eq::params() { return 2; }
ExprItem* Eq::copy() { return new Eq; }

//___________________________________________________________ Lt

Lt::Lt(){}
Lt::~Lt(){}
void Lt::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() < theStack->pop());
}
void Lt::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " < " +
		             (rcString)theStack->pop() + ")"));
}
int Lt::params() { return 2; }
ExprItem* Lt::copy() { return new Lt; }

//___________________________________________________________ Leq

Leq::Leq(){}
Leq::~Leq(){}
void Leq::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() <= theStack->pop());
}
void Leq::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " <= " +
		             (rcString)theStack->pop() + ")"));
}
int Leq::params() { return 2; }
ExprItem* Leq::copy() { return new Leq; }

//___________________________________________________________ Gt

Gt::Gt(){}
Gt::~Gt(){}
void Gt::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() > theStack->pop());
}
void Gt::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " > " +
		             (rcString)theStack->pop() + ")"));
}
int Gt::params() { return 2; }
ExprItem* Gt::copy() { return new Gt; }

//___________________________________________________________ Geq

Geq::Geq(){}
Geq::~Geq(){}
void Geq::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() >= theStack->pop());
}
void Geq::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " >= " +
		             (rcString)theStack->pop() + ")"));
}
int Geq::params() { return 2; }
ExprItem* Geq::copy() { return new Geq; }

//___________________________________________________________ Add

Add::Add(){}
Add::~Add(){}
void Add::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() + theStack->pop());
}
void Add::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " + " +
		             (rcString)theStack->pop() + ")"));
}
int Add::params() { return 2; }
ExprItem* Add::copy() { return new Add; }

//___________________________________________________________ Sub

Sub::Sub(){}
Sub::~Sub(){}
void Sub::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() - theStack->pop());
}
void Sub::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " - " +
		             (rcString)theStack->pop() + ")"));
}
int Sub::params() { return 2; }
ExprItem* Sub::copy() { return new Sub; }

//___________________________________________________________ Mul

Mul::Mul(){}
Mul::~Mul(){}
void Mul::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() * theStack->pop());
}
void Mul::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " * " +
		             (rcString)theStack->pop() + ")"));
}
int Mul::params() { return 2; }
ExprItem* Mul::copy() { return new Mul; }

//___________________________________________________________ Div

Div::Div(){}
Div::~Div(){}
void Div::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() / theStack->pop());
}
void Div::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " / " +
		             (rcString)theStack->pop() + ")"));
}
int Div::params() { return 2; }
ExprItem* Div::copy() { return new Div; }

//___________________________________________________________ Mod

Mod::Mod(){}
Mod::~Mod(){}
void Mod::process(ValueStack* theStack)
{
  theStack->push(theStack->pop() % theStack->pop());
}
void Mod::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " % " +
		             (rcString)theStack->pop() + ")"));
}
int Mod::params() { return 2; }
ExprItem* Mod::copy() { return new Mod; }

//___________________________________________________________ Sin

Sin::Sin(){}
Sin::~Sin(){}
void Sin::process(ValueStack* theStack)
{ 
  theStack->push( sin(dtor(real(theStack->pop()))) ); 
}
void Sin::print(ValueStack* theStack)
{ 
  theStack->push(Value("sin " + (rcString)theStack->pop()));
}
int Sin::params() { return 1; }
ExprItem* Sin::copy() { return new Sin; }

//___________________________________________________________  Cos

Cos::Cos(){}
Cos::~Cos(){}
void Cos::process(ValueStack* theStack)
{ 
  theStack->push(cos(dtor(real(theStack->pop()))) ); 
}
void Cos::print(ValueStack* theStack)
{ 
  theStack->push(Value("cos " + (rcString)theStack->pop()));
}
int Cos::params() { return 1; }
ExprItem* Cos::copy() { return new Cos; }

//___________________________________________________________ Tan

Tan::Tan(){}
Tan::~Tan(){}
void Tan::process(ValueStack* theStack)
{ 
  theStack->push( tan(dtor(real(theStack->pop()))) ); 
}
void Tan::print(ValueStack* theStack)
{ 
  theStack->push(Value("tan " + (rcString)theStack->pop()));
}
int Tan::params() { return 1; }
ExprItem* Tan::copy() { return new Tan; }

//___________________________________________________________ Asin

Asin::Asin(){}
Asin::~Asin(){}
void Asin::process(ValueStack* theStack)
{ 
  theStack->push( rtod(asin(real(theStack->pop()))) ); 
}
void Asin::print(ValueStack* theStack)
{ 
  theStack->push(Value("asin " + (rcString)theStack->pop()));
}
int Asin::params() { return 1; }
ExprItem* Asin::copy() { return new Asin; }

//___________________________________________________________ Acos

Acos::Acos(){}
Acos::~Acos(){}
void Acos::process(ValueStack* theStack)
{ 
  theStack->push( rtod(acos(real(theStack->pop()))) ); 
}
void Acos::print(ValueStack* theStack)
{ 
  theStack->push(Value("acos " + (rcString)theStack->pop()));
}
int Acos::params() { return 1; }
ExprItem* Acos::copy() { return new Acos; }

//___________________________________________________________ Atan

Atan::Atan(){}
Atan::~Atan(){}
void Atan::process(ValueStack* theStack)
{ 
  theStack->push( rtod(atan(real(theStack->pop()))) ); 
}
void Atan::print(ValueStack* theStack)
{ 
  theStack->push(Value("atan " + (rcString)theStack->pop()));
}
int Atan::params() { return 1; }
ExprItem* Atan::copy() { return new Atan; }

//___________________________________________________________ Abs

Abs::Abs(){}
Abs::~Abs(){}
void Abs::process(ValueStack* theStack)
{ 
  theStack->push(fabs(real(theStack->pop())) ); 
}
void Abs::print(ValueStack* theStack)
{ 
  theStack->push(Value("abs " + (rcString)theStack->pop()));
}
int Abs::params() { return 1; }
ExprItem* Abs::copy() { return new Abs; }

//___________________________________________________________ Sqrt

Sqrt::Sqrt(){}
Sqrt::~Sqrt(){}
void Sqrt::process(ValueStack* theStack)
{ 
  theStack->push(sqrt(real(theStack->pop())) ); 
}
void Sqrt::print(ValueStack* theStack)
{ 
  theStack->push(Value("sqrt " + (rcString)theStack->pop()));
}
int Sqrt::params() { return 1; }
ExprItem* Sqrt::copy() { return new Sqrt; }

//___________________________________________________________ Pow

Pow::Pow(){}
Pow::~Pow(){}
void Pow::process(ValueStack* theStack)
{ 
  theStack->push( pow(real(theStack->pop()), real(theStack->pop())) );
}
void Pow::print(ValueStack* theStack)
{
  theStack->push(Value("(" + (rcString)theStack->pop() + " ** " +
		             (rcString)theStack->pop() + ")"));
}
int Pow::params() { return 2; }
ExprItem* Pow::copy() { return new Pow; }

//___________________________________________________________ Exp

Exp::Exp(){}
Exp::~Exp(){}
void Exp::process(ValueStack* theStack)
{ 
  theStack->push( exp(real(theStack->pop())) ); 
}
void Exp::print(ValueStack* theStack)
{ 
  theStack->push(Value("exp " + (rcString)theStack->pop()));
}
int Exp::params() { return 1; }
ExprItem* Exp::copy() { return new Exp; }

//___________________________________________________________ Log

Log::Log(){}
Log::~Log(){}
void Log::process(ValueStack* theStack)
{ 
  theStack->push( log(real(theStack->pop())) ); 
}
void Log::print(ValueStack* theStack)
{ 
  theStack->push(Value("log " + (rcString)theStack->pop()));
}
int Log::params() { return 1; }
ExprItem* Log::copy() { return new Log; }

//___________________________________________________________ Log10

Log10::Log10(){}
Log10::~Log10(){}
void Log10::process(ValueStack* theStack)
{ 
  theStack->push( log10(real(theStack->pop())) ); 
}
void Log10::print(ValueStack* theStack)
{ 
  theStack->push(Value("log10 " + (rcString)theStack->pop()));
}
int Log10::params() { return 1; }
ExprItem* Log10::copy() { return new Log10; }

//___________________________________________________________ Rand

Rand::Rand(){}
Rand::~Rand(){}
void Rand::process(ValueStack* theStack)
{ 
  theStack->push(real(drand48())); 
}
void Rand::print(ValueStack* theStack)
{ 
  theStack->push(Value("Rand() "));
}
int Rand::params() { return -1; }
ExprItem* Rand::copy() { return new Rand; }

/*___________________________________________________________ Gauss
 *
 * Gaussian random number generator.
 */

Gauss::Gauss()
{
  Nrand = 4;
  GaussAdd = sqrt(3*Nrand);
  GaussFac = 2*GaussAdd/Nrand;
}
Gauss::~Gauss(){}
void Gauss::process(ValueStack* theStack)
{ 
  real sum = 0;
  for (int i=0; i<Nrand; i++)
    sum += drand48();
  theStack->push(real(GaussFac*sum-GaussAdd)); 
}
void Gauss::print(ValueStack* theStack)
{ 
  theStack->push(Value("Gauss() "));
}
int Gauss::params() { return -1; }
ExprItem* Gauss::copy() { return new Gauss; }

//___________________________________________________________ If

If::If(){}
If::~If(){}
void If::process(ValueStack* theStack)
{ 
  if (theStack->pop()) {
    Value result = theStack->pop();
    theStack->pop();
    theStack->push(result);
  }
  else {
    theStack->pop();
    // theStack->push(theStack->pop());
  }
}
void If::print(ValueStack* theStack)
{ 
  theStack->push(Value("If(" + (rcString)theStack->pop() + ", " 
		            + (rcString)theStack->pop() + ", " 
		            + (rcString)theStack->pop() + ")")); 
}
int If::params() { return 3; }
ExprItem* If::copy() { return new If; }
