/**
 * A super quick and dirty implementation of a simple stack machine.  
 * Supports only four operations, but should be easy to extend to more. 
 * I hacked this together in about half an hour, so expectations should 
 * be lowered accordingly.
 *
 * This could falls into the do-whatever-you-want-with-it category.
 * 
 * Cheers,
 *     Niek Sanders
 *     http://www.cis.rit.edu/~njs8030/
 * 
 **/
#include <stack>
#include <vector>
#include <iostream>

/*
 * Text parser converts functions commands into following tokens.
 */
enum FunctionToken { AddToken, MultiplyToken, DivideToken, SubtractToken };

/*
 * The semantics behind each token.
 */
inline double operatorAdd( double lhs, double rhs ) {
    return lhs + rhs;
}
 
inline double operatorMultiply( double lhs, double rhs ) {
    return lhs * rhs;
}

inline double operatorDivide( double lhs, double rhs ) {
    return lhs / rhs;
}

inline double operatorSubtract( double lhs, double rhs ) {
    return lhs - rhs;
}


/*
 * Typedefs used by interpreter and helper functions.
 */
typedef std::stack< FunctionToken, std::vector< FunctionToken > > FunctionStack;
typedef std::stack< double, std::vector< double > > ValueStack;


/*
 * Interpreter helper functions.
 */
inline void arityTwo( double& arg1, double& arg2, ValueStack& values ) {

    if ( values.size() < 2 ) { 
       std::cerr << "Not enough values left" << std::endl; 
       exit( 1 );
    }
    arg2 = values.top();
    values.pop();
    arg1 = values.top();
    values.pop();

}


/*
 * The interpreter.  Links tokens to their semantics.
 */

double parser( FunctionStack& functions, ValueStack& values ) {

    while ( !functions.empty() ) {
        FunctionToken curToken = functions.top();

        double arg1 = 666;
        double arg2 = 666;
        
        switch( curToken ) {
            case AddToken:
                arityTwo( arg1, arg2, values );
                values.push( operatorAdd( arg1, arg2 ) );
                break;

            case MultiplyToken:
                arityTwo( arg1, arg2, values );
                values.push( operatorMultiply( arg1, arg2 ) );
                break;

            case DivideToken:
                arityTwo( arg1, arg2, values );
                values.push( operatorDivide( arg1, arg2 ) );
                break;

            case SubtractToken:
                arityTwo( arg1, arg2, values );
                values.push( operatorSubtract( arg1, arg2 ) );
                break;

            default:
                std::cerr << "Unknown function token." << std::endl;
                break;
        }

        functions.pop();
    }

    if ( values.size() != 1 ) {
        std::cerr << "Incorrect number of values provided." << std::endl;
        exit( 1 );
    }

    double result = values.top();
    values.pop();

    return result;

}

int main( int argc, char* argv[] ) {

    FunctionStack functionStack;
    ValueStack valueStack;

    functionStack.push( AddToken );
    functionStack.push( MultiplyToken );

    valueStack.push( 3 );
    valueStack.push( 2 );
    valueStack.push( 9 );

    // Computation stack:
    //     (+ 3 (* 2 9)) = 21

    std::cout << parser( functionStack, valueStack ) << std::endl;

    return 0;

}
