/*
 * Expression.C - methods to evaluate and handle arithmetic expressions.
 *
 * 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 "Expression.h"

//___________________________________________________________ ExprItem

implementList(ExprItemList, ExprItemPtr);
ExprItem::ExprItem(){}
ExprItem::~ExprItem(){}

//___________________________________________________________ ValueItem

ValueItem::ValueItem(const Value& val) : v(val){}
ValueItem::ValueItem(Value* val) : v(*val){}
ValueItem::~ValueItem(){}
void ValueItem::process(ValueStack* theStack) { theStack->push(v); }
void ValueItem::print(ValueStack* theStack) { theStack->push(v); }
int ValueItem::params() { return 0; }
ExprItem* ValueItem::copy() { return new ValueItem(v); }

//___________________________________________________________ Expression

Expression::Expression()
: theExpression(new ExprItemList),
  theStack(new ValueStack)
{}

Expression::Expression(ExprItem* oneItem)
: theExpression(new ExprItemList(1)),
  theStack(new ValueStack)
{
  theExpression->append(oneItem);
}

Expression::Expression(const Expression& expr)
:theExpression(new ExprItemList(expr.theExpression->count())),
 theStack(new ValueStack)
{  
  for (register long i=0; i<expr.theExpression->count(); i++)
    theExpression->append(expr.theExpression->item(i)->copy());
}

// constructor for functions and unary operators 
//  expression op will be deleted
Expression::Expression(ExprItem* oper, Expression* op)
:theExpression(new ExprItemList(op->theExpression->count()+1)),
 theStack(new ValueStack)
{
  for (register long i=0; i<op->theExpression->count();i++)
    theExpression->append(op->theExpression->item(i)->copy());
  theExpression->append(oper);

  delete op;
}

// constructors for binary operators, changes the order of the arguments!
//  expressions op1, op2 will be deleted
Expression::Expression(ExprItem* oper, Expression* op1, Expression* op2)
:theExpression(new ExprItemList(100)),
 theStack(new ValueStack)
{
  register long i;

  // 'op2 op1 oper' will be the resulting expression list
#ifdef AMIGA_GCC
  for (i=0; i<op1->theExpression->count(); i++)
    theExpression->append(op1->theExpression->item(i)->copy());
  for (i=0; i<op2->theExpression->count(); i++)
    theExpression->append(op2->theExpression->item(i)->copy());
  theExpression->append(oper);
#else
  for (i=0; i<op2->theExpression->count(); i++)
    theExpression->append(op2->theExpression->item(i)->copy());
  for (i=0; i<op1->theExpression->count(); i++)
    theExpression->append(op1->theExpression->item(i)->copy());
  theExpression->append(oper);
#endif

  delete op1;  delete op2;
}

// constructors for ternary operators, changes the order of the arguments!
//  expressions op1, op2, op3 will be deleted
Expression::Expression(ExprItem* oper, 
		       Expression* op1, Expression* op2, Expression* op3)
:theExpression(new ExprItemList(100)),
 theStack(new ValueStack)
{
  register long i;

  // 'op3 op2 op1 oper' will be the resulting expression list
#ifdef AMIGA_GCC
  for (i=0; i<op1->theExpression->count(); i++)
    theExpression->append(op1->theExpression->item(i)->copy());
  for (i=0; i<op2->theExpression->count(); i++)
    theExpression->append(op2->theExpression->item(i)->copy());
  for (i=0; i<op3->theExpression->count(); i++)
    theExpression->append(op3->theExpression->item(i)->copy());
  theExpression->append(oper);
#else
  for (i=0; i<op3->theExpression->count(); i++)
    theExpression->append(op3->theExpression->item(i)->copy());
  for (i=0; i<op2->theExpression->count(); i++)
    theExpression->append(op2->theExpression->item(i)->copy());
  for (i=0; i<op1->theExpression->count(); i++)
    theExpression->append(op1->theExpression->item(i)->copy());
  theExpression->append(oper);
#endif

  delete op1;  delete op2; delete op3;
}

Expression::~Expression()
{
#ifndef OLD_STYLE_CPP
  for (register long i=0; i<theExpression->count(); i++)
    delete theExpression->item(i);
#endif
  delete theExpression;

  delete theStack;
}

// evaluating an expression is simple, cause each ExprItem knows 
//  what to do
Value& Expression::evaluate()
{
  theStack->clear();
  for (register long i=0; i<theExpression->count(); i++)
    theExpression->item(i)->process(theStack);
 
  return theStack->pop();
}

// simplify the constant subexpressions of the expression
//  e.g. 2 3 + a * -> 5 a *
Expression* Expression::simplify()
{
  int paraminrow = 0;  // number of constant parameters in row

  for (register long i=0; i<theExpression->count(); i++) {
    int num = theExpression->item(i)->params();

    // no simplification is possible, i.e. a variable
    if (num < 0) 
      paraminrow = 0;
    // the current ExprItem needs more constant arguments than present
    else if (num > paraminrow)
      paraminrow = 0;
    // simplification is possible
    else {
      Expression tmpExpr;

      paraminrow = paraminrow-num+1;

      // build up the subexpression an replace it by its result
      for (int j=0; j <= num; j++) {
	tmpExpr.theExpression->prepend(theExpression->item(i));
	theExpression->remove(i--);
      }
      theExpression->insert(++i, new ValueItem(tmpExpr.evaluate()));
    }
  }

  return this;
}

// Construct a string by executing the print member function of each 
//  ExprItem. The result is a infix notation of the expression.
ostream& operator<< (ostream& os, const Expression& expr)
{
  expr.theStack->clear();
  for (register long i=0; i<expr.theExpression->count(); i++)
    expr.theExpression->item(i)->print(expr.theStack);

  return os << (rcString)expr.theStack->pop();
}
