/** \defgroup Computation Mathematical computations */

/** @addtogroup Computation
    @{
*/

/** @file compute.cpp
    \brief This file contains the implementation of the classes that will
    be used to compute a mathematical expression.

    The base class is CValue, from which other classes are derived.
    First, the COperation class, from which the classes that represent
    different mathematical operations are derived.  Next, the
    classes CVariable and CNumber are derived from the base class.

    Each class contains the Compute() function that returns the value
    of the object.  For operations, it returns the value of the
    operation (addition, for example), on its operands (represented
    by the two pointers.  For numbers or variables, the returned value
    is simply the number itself or the value of x, y or z.
*/

#include <cmath>
#include <iostream>
#include <vector>

#include "popassert.h"
#include "CVector3f.h"
#include "compute.h"





/*****************************************\
 *                                       *
 *  Beginning of the creator functions.  *
 *                                       *
\*****************************************/


/**
   This function returns a newly allocated pointer to an object
   representing the addition of the two value passed as parameters.

   It simplifies constants and additions to 0.
*/
CValue* CValue::GetNewAddition(CValue* pLeftOperand, CValue* pRightOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(pRightOperand != NULL, "Using a NULL pointer");

  float Number1, Number2;
  if (pLeftOperand->IsConstant(&Number1) &&
      pRightOperand->IsConstant(&Number2))
    {
      Number1 += Number2;
      delete pLeftOperand;
      delete pRightOperand;
      return new CNumber(Number1);
    }

  // One bit for left value and the other one for right value
  switch ( (pLeftOperand->IsAddNeutralElem() << 1) +
           (pRightOperand->IsAddNeutralElem() << 0) )
    {
    case ( (0 << 1) + (0 << 0) ):
      return (new CAddition(pLeftOperand, pRightOperand));
      break;
    case ( (1 << 1) + (0 << 0) ):
      delete pLeftOperand;
      return pRightOperand;
      break;
    case ( (0 << 1) + (1 << 0) ):
      delete pRightOperand;
      return pLeftOperand;
      break;
    default:
      // Should not happen
      POP_ILLEGAL("Should not get here");
      return NULL;
      break;
    }
}


/**
   This function returns a newly allocated pointer to an object
   representing the substraction of the two value passed as parameters.

   it simplifies constants and 0 substractions.
*/
CValue* CValue::GetNewSubstraction(CValue* pLeftOperand, CValue* pRightOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(pRightOperand != NULL, "Using a NULL pointer");

  float Number1, Number2;
  if (pLeftOperand->IsConstant(&Number1) &&
      pRightOperand->IsConstant(&Number2))
    {
      Number1 -= Number2;
      delete pLeftOperand;
      delete pRightOperand;
      return (new CNumber(Number1));
    }

  // One bit for left value and the other one for right value
  switch ( (pLeftOperand->IsAddNeutralElem() << 1) +
           (pRightOperand->IsAddNeutralElem() << 0) )
    {
    case ( (0 << 1) + (0 << 0) ):
      return (new CSubstraction(pLeftOperand, pRightOperand));
      break;
    case ( (1 << 1) + (0 << 0) ):
      delete pLeftOperand;
      return (new COpposite(pRightOperand));
      break;
    case ( (0 << 1) + (1 << 0) ):
      delete pRightOperand;
      return pLeftOperand;
      break;
    default:
      // Should not happen
      POP_ILLEGAL("Should not get here");
      return NULL;
      break;
    }
}


/**
   This function returns a newly allocated pointer to an object
   representing the product of the two value passed as parameters.

   It simplifies multiplication by 0 and by 1.
*/
CValue* CValue::GetNewProduct(CValue* pLeftOperand, CValue* pRightOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(pRightOperand != NULL, "Using a NULL pointer");

  float Number1, Number2;
  if (pLeftOperand->IsConstant(&Number1)
      && pRightOperand->IsConstant(&Number2))
    {
      Number1 *= Number2;
      delete pLeftOperand;
      delete pRightOperand;
      return (new CNumber(Number1));
    }

  // One bit for left value and the other one for right value
  switch ( (pLeftOperand->IsConstant() << 1) +
           (pRightOperand->IsConstant() << 0) )
    {
    case ( (0 << 1) + (0 << 1) ):
      return (new CProduct(pLeftOperand, pRightOperand));
      break;
    case ( (1 << 1) + (0 << 0) ):
      if ( pLeftOperand->IsMultAbsorbElem() )
        {
          delete pLeftOperand;
          delete pRightOperand;
          return (new CNumber(0));
        }
      else if (pLeftOperand->IsMultNeutralElem())
        {
          delete pLeftOperand;
          return pRightOperand;
        }
      else
        {
          return (new CProduct(pLeftOperand, pRightOperand));
        }
      break;
    case ( (0 << 1) + (1 << 0) ):
      if ( pRightOperand->IsMultAbsorbElem() )
        {
          delete pLeftOperand;
          delete pRightOperand;
          return (new CNumber(0));
        }
      else if (pRightOperand->IsMultNeutralElem())
        {
          delete pRightOperand;
          return pLeftOperand;
        }
      else
        {
          return (new CProduct(pLeftOperand, pRightOperand));
        }
      break;
    default:
      // Should not happen
      POP_ILLEGAL("Should not get here");
      return NULL;
      break;
    }
}


/**
   This function returns a newly allocated pointer to an object
   representing the division of the two value passed as parameters.

   It simplifies constants numerator equals 0 and denominator equals 1.
*/
CValue* CValue::GetNewDivision(CValue* pLeftOperand, CValue* pRightOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(pRightOperand != NULL, "Using a NULL pointer");

  float Number1, Number2;
  if (pLeftOperand->IsConstant(&Number1) &&
      pRightOperand->IsConstant(&Number2))
    {
      if (Number2 == 0)
        throw;

      Number1 /= Number2;
      delete pLeftOperand;
      delete pRightOperand;
      return (new CNumber(Number1));
    }

  // One bit for left value and the other one for right value
  switch ( (pLeftOperand->IsConstant() << 1) +
           (pRightOperand->IsConstant() << 0) )
    {
    case ( (0 << 1) + (0 << 1) ):
      return (new CDivision(pLeftOperand, pRightOperand));
      break;
    case ( (1 << 1) + (0 << 0) ):
      if ( pLeftOperand->IsMultAbsorbElem() )
        {
          delete pLeftOperand;
          delete pRightOperand;
          return (new CNumber(0));
        }
      else
        {
          return (new CDivision(pLeftOperand, pRightOperand));
        }
      break;
    case ( (0 << 1) + (1 << 0) ):
      if ( pRightOperand->IsMultAbsorbElem() )
        {
          throw;
        }
      else if (pRightOperand->IsMultNeutralElem())
        {
          delete pRightOperand;
          return pLeftOperand;
        }
      else
        {
          return (new CDivision(pLeftOperand, pRightOperand));
        }
      break;
    default:
      // Should not happen
      POP_ILLEGAL("Should not get here");
      return NULL;
      break;
    }
}


/**
   This function returns a newly allocated pointer to an object
   representing the opposite of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewOpposite(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(-Number));
    }
  else
    {
      return (new COpposite(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the square root of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewSqrt(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;

      if (Number < 0)
        throw;

      return (new CNumber(sqrtf(Number)));
    }
  else
    {
      return (new CSqrt(pLeftOperand));
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the sine of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewSin(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(sinf(Number)));
    }
  else
    {
      return (new CSin(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the cosine of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewCos(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(cosf(Number)));
    }
  else
    {
      return (new CCos(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the tangent of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewTan(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(tanf(Number)));
    }
  else
    {
      return (new CTan(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the exponential of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewExp(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(expf(Number)));
    }
  else
    {
      return (new CExp(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the natural logarithm of the left value.

   It simplifies constants.
*/
CValue* CValue::GetNewLn(CValue* pLeftOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");

  float Number;
  if (pLeftOperand->IsConstant(&Number))
    {
      delete pLeftOperand;
      return (new CNumber(logf(Number)));
    }
  else
    {
      return (new CLn(pLeftOperand) );
    }
}

/**
   This function returns a newly allocated pointer to an object
   representing the left value to the power of the right value

   It simplifies constants and 0 or 1 as operands.
*/
CValue* CValue::GetNewPow(CValue* pLeftOperand, CValue* pRightOperand)
{
  POP_ASSERT(pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(pRightOperand != NULL, "Using a NULL pointer");

  float Number1, Number2;
  if (pLeftOperand->IsConstant(&Number1) &&
      pRightOperand->IsConstant(&Number2))
    {
      if (Number1 == 0 && Number2 == 0)
        {
          throw;
        }

      Number1 = pow(Number1, Number2);
      delete pLeftOperand;
      delete pRightOperand;
      // Check for NaN
      if ( Number1 == Number1 )
        {
          return (new CNumber(Number1));
        }
      else
        {
          throw;
          return NULL;
        }
    }

  // One bit for left value and the other one for right value
  switch ( (pLeftOperand->IsConstant() << 1) +
           (pRightOperand->IsConstant() << 0) )
    {
    case ( (0 << 1) + (0 << 1) ):
      return (new CPow(pLeftOperand, pRightOperand));
      break;
    case ( (1 << 1) + (0 << 0) ):
      if ( pLeftOperand->IsMultAbsorbElem() )
        {
          delete pLeftOperand;
          delete pRightOperand;
          return new CNumber(0);
        }
      else if ( pLeftOperand->IsMultNeutralElem() )
        {
          delete pLeftOperand;
          delete pRightOperand;
          return (new CNumber(1));
        }
      else
        {
          return (new CPow(pLeftOperand, pRightOperand));
        }
      break;
    case ( (0 << 1) + (1 << 0) ):
      if ( pRightOperand->IsMultAbsorbElem() )
        {
          delete pRightOperand;
          return pLeftOperand;
          return (new CNumber(1));
        }
      else if ( pRightOperand->IsMultNeutralElem() )
        {
          delete pRightOperand;
          return (pLeftOperand);
        }
      else
        {
          return (new CPow(pLeftOperand, pRightOperand));
        }
      break;
    default:
      // Should not happen
      POP_ILLEGAL("Should not get here");
      return NULL;
      break;
    }
}





/***********************************\
 *                                 *
 *  Beginning of the constructors  *
 *                                 *
\***********************************/

/**
   CAddition simple contructor.
*/
CAddition::CAddition(CValue* pLeftOperand, CValue* pRightOperand)
  : COperation(pLeftOperand, pRightOperand)
{
}

/**
   CSubstraction simple constructor.
*/
CSubstraction::CSubstraction(CValue* pLeftOperand, CValue* pRightOperand)
  : COperation(pLeftOperand, pRightOperand)
{
}

/**
   CProduct simple constructor.
*/
CProduct::CProduct(CValue* pLeftOperand, CValue* pRightOperand)
  : COperation(pLeftOperand, pRightOperand)
{
}

/**
   CDivision simple constructor.
*/
CDivision::CDivision(CValue* pLeftOperand, CValue* pRightOperand)
  : COperation(pLeftOperand, pRightOperand)
{
}

/**
  COpposite simple constructor.
*/
COpposite::COpposite(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CSqrt simple constructor.
*/
CSqrt::CSqrt(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CSin simple constructor.
*/
CSin::CSin(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CCos simple constructor.
*/
CCos::CCos(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CTan simple constructor.
*/
CTan::CTan(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CExp simple constructor.
*/
CExp::CExp(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CLn simple constructor.
*/
CLn::CLn(CValue* pLeftOperand)
  : COperation(pLeftOperand, NULL)
{
}

/**
   CPow simple constructor.
*/
CPow::CPow(CValue* pLeftOperand, CValue* pRightOperand)
  : COperation(pLeftOperand, pRightOperand)
{
}

/**
   CVariable simple constructor.
*/
CVariable::CVariable(TYPE_VARIABLE Type)
{
  m_Type = Type;
}

/**
   CNumber simple constructor.
*/
CNumber::CNumber(float Number)
{
  m_Number = Number;
}




/******************************************\
 *                                        *
 *  Beginning of the GetCopy() functions  *
 *                                        *
\******************************************/

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CAddition::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return new CAddition(m_pLeftOperand->GetCopy(), m_pRightOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CSubstraction::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return new CSubstraction(m_pLeftOperand->GetCopy(),
                           m_pRightOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CProduct::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return new CProduct(m_pLeftOperand->GetCopy(), m_pRightOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CDivision::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return new CDivision(m_pLeftOperand->GetCopy(), m_pRightOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* COpposite::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new COpposite(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CSqrt::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CSqrt(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CSin::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CSin(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CCos::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CCos(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CTan::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CTan(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CExp::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CExp(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CLn::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return new CLn(m_pLeftOperand->GetCopy());
}

/**
   This function returns a copy of the tree
   represented by this object.
*/
CValue* CPow::GetCopy() const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return new CPow(m_pLeftOperand->GetCopy(), m_pRightOperand->GetCopy());
}

/**
   This function returns a copy of this object.
*/
CValue* CVariable::GetCopy() const
{
  return new CVariable(m_Type);
}

/**
   This function returns a copy of this object.
*/
CValue* CNumber::GetCopy() const
{
  return new CNumber(m_Number);
}




/******************************************\
 *                                        *
 *  Beginning of the Compute() functions  *
 *                                        *
\******************************************/

/**
   This function returns the sum of the left and right values.
*/
float CAddition::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return (m_pLeftOperand->Compute(Point) + m_pRightOperand->Compute(Point));
}

/**
   This function returns the difference between the left and right values.
*/
float CSubstraction::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return (m_pLeftOperand->Compute(Point) - m_pRightOperand->Compute(Point));
}

/**
   This function returns the product of the left and right values.
*/
float CProduct::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return (m_pLeftOperand->Compute(Point) * m_pRightOperand->Compute(Point));
}

/**
   This function returns the quotient of the left and right values.
*/
float CDivision::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return (m_pLeftOperand->Compute(Point) / m_pRightOperand->Compute(Point));
}

/**
   This function returns the opposite of the left value.
*/
float COpposite::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (-(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the square root of the left value.
*/
float CSqrt::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (sqrtf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the sine of the left value.
*/
float CSin::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (sinf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the cosine of the left value.
*/
float CCos::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (cosf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the tangent of the left value.
*/
float CTan::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (tanf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the exponential of the left value.
*/
float CExp::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (expf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the natural logarithm of the left value.
*/
float CLn::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return (logf(m_pLeftOperand->Compute(Point)));
}

/**
   This function returns the left value to the power of the right value.
*/
float CPow::Compute(const CVector3f& Point) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return (powf(m_pLeftOperand->Compute(Point), m_pRightOperand->Compute(Point)));
}

/**
   This function returns the value of the corresponding coordinate in 
   the point.
*/
float CVariable::Compute(const CVector3f& Point) const
{
  switch (m_Type)
    {
    case (TYPE_X): return Point.x; break;
    case (TYPE_Y): return Point.y; break;
    case (TYPE_Z): return Point.z; break;
    default: POP_ILLEGAL("Should not get here"); return 0; break;
    }
}

/**
   This function returns the sum of the left and right values.
*/
float CNumber::Compute(const CVector3f& Point) const
{
  return m_Number;
}





/*****************************************\
 *                                       *
 *  Beginning of the Derive() functions  *
 *                                       *
\*****************************************/

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the addition.

   \f$ \left ( f(x)+g(x) \right ) ' = f'(x) + g'(x) \f$
*/
CValue* CAddition::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return GetNewAddition(m_pLeftOperand->Derive(Type),
                        m_pRightOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the substraction.

   \f$ \left ( f(x)-g(x) \right ) ' = f'(x) - g'(x) \f$
*/
CValue* CSubstraction::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return GetNewSubstraction(m_pLeftOperand->Derive(Type),
                            m_pRightOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the product.

   \f$ \left ( f(x)g(x) \right ) ' = f'(x) g(x) + f(x) g'(x) \f$
*/
CValue* CProduct::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  return GetNewAddition(GetNewProduct(m_pLeftOperand->Derive(Type),
                                      m_pRightOperand->GetCopy()),
                        GetNewProduct(m_pLeftOperand->GetCopy(),
                                      m_pRightOperand->Derive(Type)));
}

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the division.

   \f$ \left ( \frac{f(x)}{g(x)} \right ) '
     = \frac{f'(x) g(x) - f(x) g'(x)}{g(x)^2} \f$
*/
CValue* CDivision::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  CValue* Numerator =
    GetNewSubstraction(
                       GetNewProduct(m_pLeftOperand->Derive(Type),
                                     m_pRightOperand->GetCopy()),
                       GetNewProduct(m_pLeftOperand->GetCopy(),
                                     m_pRightOperand->Derive(Type))
                       );

  CValue* Denominator = GetNewPow(m_pRightOperand->GetCopy(), new CNumber(2));

  return GetNewDivision(Numerator, Denominator);
}

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the opposite.

   \f$ \left ( -f(x) \right ) ' = -f'(x) \f$

*/
CValue* COpposite::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewOpposite(m_pLeftOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue 
   object representing the derivative of the square root.

   \f$ \left ( \sqrt{f(x)} \right ) ' = \frac{f'(x)}{2 \sqrt{f(x)}} \f$

*/
CValue* CSqrt::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewDivision( m_pLeftOperand->Derive(Type),
                         GetNewProduct(new CNumber(2),
                                       GetNewSqrt(m_pLeftOperand->GetCopy())));
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of the sine.

   \f$ \left ( \sin{f(x)} \right ) ' = \cos{\left ( f(x) \right )} f'(x) \f$
*/
CValue* CSin::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewProduct(GetNewCos(m_pLeftOperand->GetCopy()),
                       m_pLeftOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of the cosine.

   \f$ \left ( \cos{f(x)} \right ) ' = - \sin{\left ( f(x) \right )} f'(x) \f$
*/
CValue* CCos::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewProduct(GetNewOpposite(GetNewSin(m_pLeftOperand->GetCopy())),
                       m_pLeftOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of the tangent.

   \f$ \left ( \tan{f(x)} \right ) '
   = \left ( \sec {\left ( f(x) \right )} \right ) ^ 2 f'(x)
   = \frac{f'(x)}{\left ( \cos{ \left ( f(x) \right )} \right ) ^ 2}\f$
*/
CValue* CTan::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewDivision(m_pLeftOperand->Derive(Type),
                        GetNewPow(GetNewCos(m_pLeftOperand->GetCopy()),
                                  new CNumber(2)));
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of the exponential.

   \f$ \left ( e^{f(x)} \right ) ' = e^{f(x)} f'(x) \f$
*/
CValue* CExp::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewProduct(GetNewExp(m_pLeftOperand->GetCopy()),
                       m_pLeftOperand->Derive(Type));
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of a function to the power
   of another.

   \f$ \left ( f(x)^{g(x)} \right ) '
   = f(x)^{g(x)} \left ( g'(x) \ln \left ( f(x) \right ) +
                         \frac{g(x)f'(x)}{f(x)} \right ) \f$ 
*/
CValue* CPow::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  float Number;
  if (m_pRightOperand->IsConstant(&Number))
    {
      return GetNewProduct(GetNewProduct(new CNumber(Number), 
                                         m_pLeftOperand->Derive(Type)),
                           GetNewPow(m_pLeftOperand->GetCopy(),
                                     new CNumber(Number - 1)));
    }
  else
    {
      // Left part of the parenthesis
      CValue* pLeftOperand =
        GetNewProduct(m_pRightOperand->Derive(Type),
                      GetNewLn(m_pLeftOperand->GetCopy()));

      // Right part of the parenthesis
      CValue* pRightOperand =
        GetNewDivision(GetNewProduct(m_pRightOperand->GetCopy(),
                                     m_pLeftOperand->Derive(Type)),
                       m_pLeftOperand->GetCopy());

      return GetNewProduct(this->GetCopy(),
                           GetNewAddition(pLeftOperand, pRightOperand));
    }
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of the natural logarithm.

   \f$ \left ( \ln \left ( f(x) \right ) \right ) ' =
   \frac{f'(x)}{f(x)} \f$
*/
CValue* CLn::Derive(TYPE_VARIABLE Type) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  return GetNewDivision(m_pLeftOperand->Derive(Type), m_pLeftOperand->GetCopy());
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of a variable.

   \f$ \frac{dx}{dx} = 1 \f$ , \f$ \frac{dy}{dx} = 0 \f$
*/
CValue* CVariable::Derive(TYPE_VARIABLE Type) const
{
  if (Type == m_Type)
    return new CNumber(1);
  else
    return new CNumber(0);
}

/**
   This function returns a newly allocated pointer to the CValue
   object representing the derivative of a number.

   \f$ \frac{dC}{dx} = 0 \f$, where \f$ C \f$ is constant.
*/
CValue* CNumber::Derive(TYPE_VARIABLE Type) const
{
  return new CNumber(0);
}





/****************************************\
 *                                      *
 *  Beginning of the Print() functions  *
 *                                      *
\****************************************/

/**
   This function fills the stream with the expression of
   the left value plus the right value, in parenthesis.
*/
void CAddition::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  o << '(';
  m_pLeftOperand->Print(o);
  o << '+';
  m_pRightOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the left value minus the right value, in parenthesis.
*/
void CSubstraction::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  o << '(';
  m_pLeftOperand->Print(o);
  o << '-';
  m_pRightOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the left value times the right value, in parenthesis.
*/
void CProduct::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  o << '(';
  m_pLeftOperand->Print(o);
  o << '*';
  m_pRightOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the left value on the right value, in parenthesis.
*/
void CDivision::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  o << '(';
  m_pLeftOperand->Print(o);
  o << '/';
  m_pRightOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the opposite of the left value.
*/
void COpposite::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "(-";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the square root of the left value.
*/
void CSqrt::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "sqrt(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the sine of the left value.
*/
void CSin::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "sin(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the cosine of the left value.
*/
void CCos::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "cos(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the tangent of the left value.
*/
void CTan::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "tan(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the exponential of the left value.
*/
void CExp::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "exp(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the natural logarithm of the left value.
*/
void CLn::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  o << "ln(";
  m_pLeftOperand->Print(o);
  o << ')';
}

/**
   This function fills the stream with the expression of
   the of the left value to the power of the right value.
*/
void CPow::Print(std::ostream& o) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Print(o);
  o << '^';
  m_pRightOperand->Print(o);
}

/**
   This function fills the stream with the expression of
   the variable it represents.
*/
void CVariable::Print(std::ostream& o) const
{
  switch (m_Type)
    {
    case (TYPE_X): o << 'x'; break;
    case (TYPE_Y): o << 'y'; break;
    case (TYPE_Z): o << 'z'; break;
    default: POP_ILLEGAL("Should not get here"); break;
    }
}

/**
   This function fills the stream with the expression of
   the number it represents.
*/
void CNumber::Print(std::ostream& o) const
{
  o << m_Number;
}





inline void BEFORE_PUSH(std::vector<char>& v, int& i)
{
  ++i;

  if (i > 8)
    {
      v.push_back('\xd9');
      v.push_back('\xf6'); // fdecstp

      v.push_back('\x83');
      v.push_back('\xec');
      v.push_back('\x04'); // subl   $4,%esp

      v.push_back('\xd9');
      v.push_back('\x14');
      v.push_back('\x24'); // fsts   (%esp)

      v.push_back('\xdd');
      v.push_back('\xc0'); // ffree  %st(0)

      v.push_back('\xd9');
      v.push_back('\xf7'); // fincstp
    }
}

inline void AFTER_POP(std::vector<char>& v, int& i)
{
  if (i > 8)
    {
      v.push_back('\xd9');
      v.push_back('\x04');
      v.push_back('\x24'); // flds   (%esp)

      v.push_back('\xd9');
      v.push_back('\xf7'); // fincstp

      v.push_back('\x83');
      v.push_back('\xc4');
      v.push_back('\x04'); // addl   $4,%esp
    }

  --i;
}

/******************************************\
 *                                        *
 *  Beginning of the Compile() functions  *
 *                                        *
\******************************************/

void CAddition::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);
  m_pRightOperand->Compile(v, i);

  v.push_back('\xde');
  v.push_back('\xc1'); // faddp

  AFTER_POP(v, i);
}


void CSubstraction::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);
  m_pRightOperand->Compile(v, i);

  v.push_back('\xde');
  v.push_back('\xe9'); // fsubrp

  AFTER_POP(v, i);
}

void CProduct::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);
  m_pRightOperand->Compile(v, i);

  v.push_back('\xde');
  v.push_back('\xc9'); // fmulp

  AFTER_POP(v, i);
}

void CDivision::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);
  m_pRightOperand->Compile(v, i);

  v.push_back('\xde');
  v.push_back('\xf9'); // fdivrp

  AFTER_POP(v, i);
}

void COpposite::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  v.push_back('\xd9');
  v.push_back('\xe0'); // fdivrp
}

void CSqrt::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  v.push_back('\xd9');
  v.push_back('\xfa'); // fsqrt
}

void CSin::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  v.push_back('\xd9');
  v.push_back('\xfe'); // fsin
}

void CCos::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  v.push_back('\xd9');
  v.push_back('\xff'); // fcos
}

void CTan::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\xf2'); // fptan

  v.push_back('\xdd');
  v.push_back('\xc0'); // ffree  %st(0)

  v.push_back('\xd9');
  v.push_back('\xf7'); // fincstp

  AFTER_POP(v, i);
}

void CExp::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  // compute e^b
  // on stack => b

  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\xea'); // fldl2e
  // on stack => log2(e) : b

  v.push_back('\xde');
  v.push_back('\xc9'); // fmulp
  // on stack => b*log2(e)

  v.push_back('\xd9');
  v.push_back('\xe8'); // fld1
  // on stack => 1 : b*log2(e)

  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\xc1'); // fld     %st(1)
  // on stack => b*log2(e) : 1 : b*log2(e)

  v.push_back('\xd9');
  v.push_back('\xfc'); // frndint
  // on stack => int(b*log2(e)) : 1 : b*log2(e)

  v.push_back('\xd9');
  v.push_back('\xca'); // fxch    %st(2)
  // on stack => b*log2(e) : 1 : int(b*log2(e))

  v.push_back('\xd8');
  v.push_back('\xe2'); // fsub    %st(2),%st
  // on stack => frac(b*log2(e)) : 1 : int(b*log2(e))

  v.push_back('\xd9');
  v.push_back('\xf0'); // f2xm1
  // on stack => 2^frac(b*log2(e))-1 : 1 : int(b*log2(e))

  v.push_back('\xde');
  v.push_back('\xc1'); // faddp   %st,%st(1)
  // on stack => 2^frac(b*log2(e)) : int(b*log2(e))

  AFTER_POP(v, i);

  // 2^frac(b*log2(e))*2^int(b*log2(e))=2^(b*log2(e))=e^b

  v.push_back('\xd9');
  v.push_back('\xfd'); // fscale
  // on stack => e^b : int(b*log2(e))

  v.push_back('\xd9');
  v.push_back('\xc9'); // fxch
  // on stack => int(b*log2(e)) : e^b


  v.push_back('\xdd');
  v.push_back('\xc0'); // ffree  %st(0)

  v.push_back('\xd9');
  v.push_back('\xf7'); // fincstp
  // on stack => e^b

  AFTER_POP(v, i);
}

void CLn::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);

  // compute ln(x)
  // on stack => x

  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\xe8'); // fld1
  // on stack => 1 : x

  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\xea'); // fldl2e
  // on stack => log2(e) : 1 : x

  v.push_back('\xd9');
  v.push_back('\xca'); // fxch    %st(2)
  // on stack => x : 1 : log2(e)

  v.push_back('\xd9');
  v.push_back('\xf1'); // fyl2x
  // on stack => 1*log2(x) : log2(e)

  AFTER_POP(v, i);

  v.push_back('\xde');
  v.push_back('\xf1'); // fdivp
  // on stack => log2(x) / log2(e) = ln(x)

  AFTER_POP(v, i);
}

void CPow::Compile(std::vector<char>& v, int& i) const
{
  POP_ASSERT(m_pLeftOperand != NULL, "Using a NULL pointer");
  POP_ASSERT(m_pRightOperand != NULL, "Using a NULL pointer");

  m_pLeftOperand->Compile(v, i);
  m_pRightOperand->Compile(v, i);

  // compute a^b
  // on stack => b : a

  bool entier = false;
  float exponent = 0;
  if (m_pRightOperand->IsConstant(&exponent))
    entier = (exponent == (int) exponent);

  if (entier)
    {
      v.push_back('\xdb');
      v.push_back('\x54');
      v.push_back('\x24');
      v.push_back('\xfc'); // fistl   -4(%esp)

      v.push_back('\xdd');
      v.push_back('\xc0'); // ffree   %st(0)

      v.push_back('\xd9');
      v.push_back('\xf7'); // fincstp

      v.push_back('\xd9');
      v.push_back('\xe8'); // fld1

      v.push_back('\xd9');
      v.push_back('\xc9'); // fxch

      v.push_back('\x8b');
      v.push_back('\x54');
      v.push_back('\x24');
      v.push_back('\xfc'); // movl    -4(%esp),%edx

      v.push_back('\x83');
      v.push_back('\xfa');
      v.push_back('\x00'); // cmpl    $0,%edx

      v.push_back('\x7f');
      v.push_back('\x04'); // jg      27

      v.push_back('\xf7');
      v.push_back('\xda'); // negl    %edx

      v.push_back('\xd8');
      v.push_back('\xf9'); // fdivr   %st(1),%st

      v.push_back('\xd1');
      v.push_back('\xea'); // shrl    $1,%edx

      v.push_back('\x73');
      v.push_back('\x02'); // jnc     38

      v.push_back('\xdc');
      v.push_back('\xc9'); // fmul    %st,%st(1)

      v.push_back('\x83');
      v.push_back('\xfa');
      v.push_back('\x00'); // cmpl    $0,%edx

      v.push_back('\x74');
      v.push_back('\x04'); // je      41

      v.push_back('\xd8');
      v.push_back('\xc8'); // fmul    %st(0),%st

      v.push_back('\xeb');
      v.push_back('\xf1'); // jmp     32

      v.push_back('\xdd');
      v.push_back('\xc0'); // ffree   %st(0)

      v.push_back('\xd9');
      v.push_back('\xf7'); // fincstp
    }
  else
    {
      v.push_back('\xd9');
      v.push_back('\xc9'); // fxch
      // on stack => a : b

      v.push_back('\xd9');
      v.push_back('\xf1'); // fyl2x
      // on stack => b*log2(a)

      v.push_back('\xd9');
      v.push_back('\xe8'); // fld1
      // on stack => 1 : b*log2(a)

      BEFORE_PUSH(v, i);

      v.push_back('\xd9');
      v.push_back('\xc1'); // fld     %st(1)
      // on stack => b*log2(a) : 1 : b*log2(a)

      v.push_back('\xd9');
      v.push_back('\xfc'); // frndint
      // on stack => int(b*log2(a)) : 1 : b*log2(a)

      v.push_back('\xd9');
      v.push_back('\xca'); // fxch    %st(2)
      // on stack => b*log2(a) : 1 : int(b*log2(a))

      v.push_back('\xd8');
      v.push_back('\xe2'); // fsub    %st(2),%st
      // on stack => frac(b*log2(a)) : 1 : int(b*log2(a))

      v.push_back('\xd9');
      v.push_back('\xf0'); // f2xm1
      // on stack => 2^frac(b*log2(a))-1 : 1 : int(b*log2(a))

      v.push_back('\xde');
      v.push_back('\xc1'); // faddp   %st,%st(1)
      // on stack => 2^frac(b*log2(a)) : int(b*log2(a))

      AFTER_POP(v, i);

      // 2^frac(b*log2(a))*2^int(b*log2(a))=2^(b*log2(a))=a^b

      v.push_back('\xd9');
      v.push_back('\xfd'); // fscale
      // on stack => a^b : int(b*log2(a))

      v.push_back('\xd9');
      v.push_back('\xc9'); // fxch
      // on stack => int(b*log2(a)) : a^b


      v.push_back('\xdd');
      v.push_back('\xc0'); // ffree  %st(0)

      v.push_back('\xd9');
      v.push_back('\xf7'); // fincstp
      // on stack => a^b
    }

  AFTER_POP(v, i);
}

void CVariable::Compile(std::vector<char>& v, int& i) const
{
  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\x40');
  v.push_back(m_Type*4); // flds 4*m_Type(%eax)
}

void CNumber::Compile(std::vector<char>& v, int& i) const
{
  BEFORE_PUSH(v, i);

  v.push_back('\xd9');
  v.push_back('\x05');

  v.push_back((char)((int)&m_Number));
  v.push_back((char)((int)&m_Number >> 8));
  v.push_back((char)((int)&m_Number >> 16));
  v.push_back((char)((int)&m_Number >> 24)); // flds   &m_Number
}


/** @} */
