panthema / 2007 / flex-bison-cpp-example / flex-bison-cpp-example-0.1.4 / src / expression.h (Download File)
// $Id: expression.h 48 2009-09-05 08:07:10Z tb $
/** \file expression.h Implements an example calculator class group. */

#ifndef EXPRESSION_H
#define EXPRESSION_H

#include <map>
#include <vector>
#include <ostream>
#include <stdexcept>
#include <cmath>

/** CalcNode is the abstract base class for calculation nodes. From it the
 * different nullary, unary and binary nodes are derived. */
class CalcNode
{
public:
    /// required for virtual functions. in the derived classes the operands are
    /// deleted.
    virtual ~CalcNode()
    {
    }

    /// evaluate the complete calculation tree and return the floating point
    /// result value
    virtual double	evaluate() const = 0;

    /// output the calculation tree to the given stream. tries to format the
    /// output to make tree levels visible.
    virtual void	print(std::ostream &os, unsigned int depth=0) const = 0;

    /// helper function for print() which makes the indention string
    static inline std::string indent(unsigned int d)
    {
	return std::string(d * 2, ' ');
    }
};

/** Calculation node always returning a constant value. */
class CNConstant : public CalcNode
{
    /// the constant value returned
    double	value;
    
public:
    /// construct a constant calculation node from a value
    explicit CNConstant(double _value)
	: CalcNode(), value(_value)
    {
    }

    virtual double evaluate() const
    {
	return value;
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << value << std::endl;
    }
};

/** Calculation node negating the value of the operand subtree. */
class CNNegate : public CalcNode
{
    /// calculation subtree
    CalcNode* 	node;

public:
    explicit CNNegate(CalcNode* _node)
	: CalcNode(), node(_node)
    {
    }

    virtual ~CNNegate()
    {
	delete node;
    }

    virtual double evaluate() const
    {
	return - node->evaluate();
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "- negate" << std::endl;
	node->print(os, depth+1);
    }
};

/** Calculation node adding two operand nodes. */
class CNAdd : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNAdd(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNAdd()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return left->evaluate() + right->evaluate();
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "+ add" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculation node subtracting two operand nodes. */
class CNSubtract : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNSubtract(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNSubtract()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return left->evaluate() - right->evaluate();
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "- subtract" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculation node multiplying two operand nodes. */
class CNMultiply : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNMultiply(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNMultiply()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return left->evaluate() * right->evaluate();
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "* multiply" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculation node dividing two operand nodes. */
class CNDivide : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNDivide(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNDivide()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return left->evaluate() / right->evaluate();
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "/ divide" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculation node calculating the remainder of an integer division of two
 * operand nodes. */
class CNModulo : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNModulo(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNModulo()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return std::fmod(left->evaluate(), right->evaluate());
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "% modulo" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculation node raising one operand to the power of the second. */
class CNPower : public CalcNode
{
    /// left calculation operand
    CalcNode* 	left;

    /// right calculation operand
    CalcNode* 	right;
    
public:
    explicit CNPower(CalcNode* _left, CalcNode* _right)
	: CalcNode(), left(_left), right(_right)
    {
    }

    virtual ~CNPower()
    {
	delete left;
	delete right;
    }

    virtual double evaluate() const
    {
	return std::pow(left->evaluate(), right->evaluate());
    }

    virtual void print(std::ostream &os, unsigned int depth) const
    {
	os << indent(depth) << "^ power" << std::endl;
	left->print(os, depth+1);
	right->print(os, depth+1);
    }
};

/** Calculator context used to save the parsed expressions. This context is
 * passed along to the example::Driver class and fill during parsing via bison
 * actions. */
class CalcContext
{
public:

    /// type of the variable storage
    typedef std::map<std::string, double> variablemap_type;

    /// variable storage. maps variable string to doubles
    variablemap_type		variables;

    /// array of unassigned expressions found by the parser. these are then
    /// outputted to the user.
    std::vector<CalcNode*>	expressions;

    /// free the saved expression trees
    ~CalcContext()
    {
	clearExpressions();
    }

    /// free all saved expression trees
    void	clearExpressions()
    {
	for(unsigned int i = 0; i < expressions.size(); ++i)
	{
	    delete expressions[i];
	}
	expressions.clear();
    }

    /// check if the given variable name exists in the storage
    bool	existsVariable(const std::string &varname) const
    {
	return variables.find(varname) != variables.end();
    }
    
    /// return the given variable from the storage. throws an exception if it
    /// does not exist.
    double	getVariable(const std::string &varname) const
    {
	variablemap_type::const_iterator vi = variables.find(varname);
	if (vi == variables.end())
	    throw(std::runtime_error("Unknown variable."));
	else
	    return vi->second;
    }
};

#endif // EXPRESSION_H