// rpimpl_oper.h
// Copyright (c) Menno Rubingh 2016.  Web: [http://rubinghsoftware.de]
// 
// MR Mar 2016.
//
// OperationXxx classes:
// Used internally by the RPInterpreter implementation.
// Instance executes a specific operation (changing stack and variables)
// during the evaluation of a RP expression.
//
//---
// Implementation notes:
// - All member variables are constants, set via the constructors.
// - All member functions are 'const', since they do not change the member variables.
// - Member variable cm_cxt: 
//     This is common to all classes (therefore in Base class).  
//     It is passed to the exception thrown on execution error.
//     It is stored not as a pointer but as a whole instance of the class struct, since
//     we must store the contents of this struct. So the constructor makes a COPY if the
//     struct passed as an input parameter.
// - The different binary operations are all coded out as individual OperationBinXxx
//   subclasses, instead of one combined OperationBinary subclass parameterized by an
//   instance of another pure virtual class hierarchy implementing the various low-level 
//   oerations.  The rationale for coding each binary operation out as an individual 
//   OperationBinXxx subclass is to achieve the fastest possible processing speed.
//


#ifndef _RPIMPL_OPER_H_
#define _RPIMPL_OPER_H_


#include "rpimpl_ex.h"     //SContext, Ex.
#include "rpimpl_stack.h"  //StackDbl.
#include "rpimpl_var.h"    //VarTable.

#include <stdio.h>         //FILE.

#include <math.h>          //pow().




//--------------------------------------------------------------------------------
// The OperationXxx classes.
//--------------------------------------------------------------------------------

class OperationBase
{
protected:
	SContext const cm_cxt;  //Character nr in input string where this lexical element begins.

public:
	OperationBase( SContext const * iCxt ) 
		:
		cm_cxt( *iCxt ) //Copy struct contents.
		{ }

	virtual ~OperationBase( void ) { }

	virtual void print( FILE * oF ) const = 0;

	virtual void execute( 
		StackDbl *   uStack,
		VarTable *   uVars )
		const = 0;
};



// 
// The ';' operator:
// Check that stacksize == 0, and do nothing else.
// 
class OperationSemicolon : public OperationBase
{
public:
	OperationSemicolon( SContext const * iCxt ) :
		OperationBase( iCxt ) { }
		
	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};


//
// Push the value of a variable onto stack.
//
class OperationPushVar : public OperationBase
{
	int const cm_varIndex; //Index in VarTable of the variable to push.

public:
	OperationPushVar( SContext const * iCxt, int iVarIndex ) : 
		OperationBase( iCxt ), cm_varIndex( iVarIndex ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};


//
// Pop a value off stack, copy it into a variable.
//
class OperationPopVar : public OperationBase
{
	int const cm_varIndex; //Index in VarTable of the variable to push.

public:
	OperationPopVar( SContext const * iCxt, int iVarIndex ) : 
		OperationBase( iCxt ), cm_varIndex( iVarIndex ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};



//
// Push a constant value onto stack.
//
class OperationPushConst : public OperationBase
{
	double const cm_value; 

public:
	OperationPushConst( SContext const * iCxt, double iVal ) : 
		OperationBase( iCxt ), cm_value(iVal) { }
	
	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};



//
// Binary operations:
// Pop two operands, execute binary operation, push result.
//

class OperationBinAdd : public OperationBase
{
public:
	OperationBinAdd( SContext const * iCxt ) : OperationBase( iCxt ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};
class OperationBinSub : public OperationBase
{
public:
	OperationBinSub( SContext const * iCxt ) : OperationBase( iCxt ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};
class OperationBinMul : public OperationBase
{
public:
	OperationBinMul( SContext const * iCxt ) : OperationBase( iCxt ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};
class OperationBinDiv : public OperationBase
{
public:
	OperationBinDiv( SContext const * iCxt ) : OperationBase( iCxt ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};
class OperationBinPow : public OperationBase
{
public:
	OperationBinPow( SContext const * iCxt ) : OperationBase( iCxt ) { }

	void print  ( FILE * oF )                           const;
	void execute( StackDbl * uStack, VarTable * uVars ) const;
};




#endif //_RPIMPL_OPER_H_