panthema / 2007 / stx-exparser / stx-exparser-0.7 / libstx-exparser / ExpressionParser.cc (Download File)
// $Id: ExpressionParser.cc 59 2007-07-17 14:43:23Z tb $

/*
 * STX Expression Parser C++ Framework v0.7
 * Copyright (C) 2007 Timo Bingmann
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/** \file ExpressionParser.cc
 * Implementation of the parser using a boost::spirit grammar and a different
 * specializations of ParseNode.
 */

#include "ExpressionParser.h"

#include <boost/spirit/core.hpp>

#include <boost/spirit/tree/ast.hpp>
#include <boost/spirit/tree/tree_to_xml.hpp>

#include <boost/spirit/utility/lists.hpp>
#include <boost/spirit/utility/distinct.hpp>
#include <boost/spirit/utility/escape_char.hpp>
#include <boost/spirit/utility/grammar_def.hpp> 

#include <iostream>
#include <sstream>
#include <cmath>

// #define STX_DEBUG_PARSER

namespace stx {

/// Enclosure for the spirit parser grammar and hidden parse node
/// implementation classes.
namespace Grammar {

using namespace boost::spirit;

/// This enum specifies ids for the parse tree nodes created for each rule.
enum parser_ids
{
    boolean_const_id = 1,
    integer_const_id,
    long_const_id,
    double_const_id,
    string_const_id,
    constant_id,

    function_call_id,
    function_identifier_id,

    varname_id,

    atom_expr_id,

    unary_expr_id,
    mul_expr_id,
    add_expr_id,

    cast_expr_id,
    cast_spec_id,

    comp_expr_id,
    and_expr_id,
    or_expr_id,

    expr_id,
    exprlist_id,
};

/// Keyword parser used for matching words with () and spaces as separators.
distinct_parser<> keyword_p("a-zA-Z0-9_");

/// The boost::spirit expression parser grammar
struct ExpressionGrammar : public grammar<ExpressionGrammar>
{
    /// The boost::spirit expression parser grammar definition (for a specific
    /// scanner) with two entry points.
    template <typename ScannerT>
    struct definition : public grammar_def<rule<ScannerT, parser_context<>, parser_tag<expr_id> >,
					   rule<ScannerT, parser_context<>, parser_tag<exprlist_id> > >
    {
	/// Real definition function of the grammar.
	definition(ExpressionGrammar const& /*self*/)
	{
	    // *** Constants

	    constant
		= double_const
		| integer_const
		| long_const
		| boolean_const
		| string_const
		;
	    
	    boolean_const
		= as_lower_d[keyword_p("true") | keyword_p("false")]
		;

	    integer_const
		= int_p
		;

	    // this is needed because spirit's int_parsers don't work with
	    // these long numbers
	    long_const
		= token_node_d[ lexeme_d[ !( ch_p('+') | ch_p('-' ) ) >> +( range_p('0','9') ) ] ]
		;

	    double_const
		= strict_real_p
		;

            string_const
                = lexeme_d[
		    token_node_d[ '"' >> *(c_escape_ch_p - '"') >> '"' ]
                    ]
                ;

	    // *** Function call and function identifier

            function_call
                = root_node_d[function_identifier]
		>> discard_node_d[ ch_p('(') ] >> exprlist >> discard_node_d[ ch_p(')') ]
                ;

            function_identifier
                = lexeme_d[ 
		    token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
                    ]
                ;

	    // *** Expression names

            varname
                = lexeme_d[ 
		    token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
                    ]
                ;

	    // *** Valid Expressions, from small to large

            atom_expr
                = constant
                | inner_node_d[ ch_p('(') >> expr >> ch_p(')') ]
                | function_call
		| varname
                ;

            unary_expr
                = !( root_node_d[ as_lower_d[ch_p('+') | ch_p('-') | ch_p('!') | str_p("not")] ] )
		>> atom_expr
                ;

	    cast_spec
		= discard_node_d[ ch_p('(') ]
		>> (
		    keyword_p("bool") |
		    keyword_p("char") | keyword_p("short") | keyword_p("int") | keyword_p("integer") | keyword_p("long") |
		    keyword_p("byte") | keyword_p("word") | keyword_p("dword") | keyword_p("qword") |
		    keyword_p("float") | keyword_p("double") |
		    keyword_p("string")
		    )
		>> discard_node_d[ ch_p(')') ]
		;

            cast_expr
		= root_node_d[ !cast_spec ] >> unary_expr
		;

            mul_expr
                = cast_expr
		>> *( root_node_d[ch_p('*') | ch_p('/')] >> cast_expr )
                ;

	    add_expr
		= mul_expr
		>> *( root_node_d[ch_p('+') | ch_p('-')] >> mul_expr )
		;

	    comp_expr
		= add_expr
		>> *( root_node_d[( str_p("==") | str_p("!=") |
				    str_p("<=") | str_p(">=") | str_p("=<") | str_p("=>") |
				    ch_p('=') | ch_p('<') | ch_p('>') )] >> add_expr )
		;

	    and_expr
		= comp_expr
		>> *( root_node_d[ as_lower_d[str_p("and") | str_p("&&")] ] >> comp_expr )
		;

	    or_expr
		= and_expr
		>> *( root_node_d[ as_lower_d[str_p("or") | str_p("||")] ] >> and_expr )
		;

	    // *** Base Expression and List

	    expr
		= or_expr
		;

	    exprlist
		= infix_node_d[ !list_p(expr, ch_p(',')) ]
		;

	    // Special spirit feature to declare multiple grammar entry points
	    this->start_parsers(expr, exprlist); 

#ifdef STX_DEBUG_PARSER
	    BOOST_SPIRIT_DEBUG_RULE(constant);

	    BOOST_SPIRIT_DEBUG_RULE(boolean_const);
	    BOOST_SPIRIT_DEBUG_RULE(integer_const);
	    BOOST_SPIRIT_DEBUG_RULE(long_const);
	    BOOST_SPIRIT_DEBUG_RULE(double_const);
	    BOOST_SPIRIT_DEBUG_RULE(string_const);

	    BOOST_SPIRIT_DEBUG_RULE(function_call);
	    BOOST_SPIRIT_DEBUG_RULE(function_identifier);
	    
	    BOOST_SPIRIT_DEBUG_RULE(varname);

	    BOOST_SPIRIT_DEBUG_RULE(atom_expr);

	    BOOST_SPIRIT_DEBUG_RULE(unary_expr);
	    BOOST_SPIRIT_DEBUG_RULE(mul_expr);
	    BOOST_SPIRIT_DEBUG_RULE(add_expr);

	    BOOST_SPIRIT_DEBUG_RULE(cast_spec);
	    BOOST_SPIRIT_DEBUG_RULE(cast_expr);

	    BOOST_SPIRIT_DEBUG_RULE(comp_expr);
	    BOOST_SPIRIT_DEBUG_RULE(and_expr);
	    BOOST_SPIRIT_DEBUG_RULE(or_expr);

	    BOOST_SPIRIT_DEBUG_RULE(expr);
	    BOOST_SPIRIT_DEBUG_RULE(exprlist);
#endif
	}

	/// Rule for a constant: one of the three scalar types integer_const,
	/// double_const or string_const
        rule<ScannerT, parser_context<>, parser_tag<constant_id> > 		constant;

	/// Boolean value constant rule: "true" or "false"
        rule<ScannerT, parser_context<>, parser_tag<boolean_const_id> > 	boolean_const;
	/// Integer constant rule: "1234"
        rule<ScannerT, parser_context<>, parser_tag<integer_const_id> > 	integer_const;
	/// Long integer constant rule: "12345452154"
        rule<ScannerT, parser_context<>, parser_tag<long_const_id> > 		long_const;
	/// Float constant rule: "1234.3"
        rule<ScannerT, parser_context<>, parser_tag<double_const_id> > 		double_const;
	/// String constant rule: with quotes "abc"
        rule<ScannerT, parser_context<>, parser_tag<string_const_id> > 		string_const;

	/// Function call rule: func1(a,b,c) where a,b,c is a list of exprs
        rule<ScannerT, parser_context<>, parser_tag<function_call_id> > 	function_call;
	/// Function rule to match a function identifier: alphanumeric and _
	/// are allowed.
        rule<ScannerT, parser_context<>, parser_tag<function_identifier_id> > 	function_identifier;

	/// Rule to match a variable name: alphanumeric with _
        rule<ScannerT, parser_context<>, parser_tag<varname_id> > 		varname;

	/// Helper rule which implements () bracket grouping.
        rule<ScannerT, parser_context<>, parser_tag<atom_expr_id> > 		atom_expr;

	/// Unary operator rule: recognizes + - ! and "not".
        rule<ScannerT, parser_context<>, parser_tag<unary_expr_id> > 		unary_expr;
	/// Binary operator rule taking precedent before add_expr:
	/// recognizes * and /
        rule<ScannerT, parser_context<>, parser_tag<mul_expr_id> > 		mul_expr;
	/// Binary operator rule: recognizes + and -
        rule<ScannerT, parser_context<>, parser_tag<add_expr_id> > 		add_expr;

	/// Match all the allowed cast types: short, double, etc.
        rule<ScannerT, parser_context<>, parser_tag<cast_spec_id> >        	cast_spec;
	/// Cast operator written like in C: (short)
        rule<ScannerT, parser_context<>, parser_tag<cast_expr_id> >        	cast_expr;

	/// Comparison operator: recognizes == = != <= >= < > => =<
        rule<ScannerT, parser_context<>, parser_tag<comp_expr_id> >        	comp_expr;
	/// Boolean operator: recognizes && and "and" and works only on boolean
	/// values
        rule<ScannerT, parser_context<>, parser_tag<and_expr_id> >        	and_expr;
	/// Boolean operator: recognizes || and "or" and works only on boolean
	/// values
        rule<ScannerT, parser_context<>, parser_tag<or_expr_id> >        	or_expr;

	/// Base rule to match an expression 
        rule<ScannerT, parser_context<>, parser_tag<expr_id> >        		expr;
	/// Base rule to match a comma-separated list of expressions (used for
	/// function arguments and lists of expressions)
        rule<ScannerT, parser_context<>, parser_tag<exprlist_id> >    		exprlist;
    };
};

// *** Classes representing the nodes in the resulting parse tree, these need
// *** not be publicly available via the header file.

/// Constant value nodes of the parse tree. This class holds any of the three
/// constant types in the enclosed AnyScalar object.
class PNConstant : public ParseNode
{
private:
    /// The constant parsed value.
    class AnyScalar	value;

public:
    /// Assignment from the string received from the parser.
    PNConstant(AnyScalar::attrtype_t type, std::string strvalue)
	: ParseNode(), value(type)
    {
	// check whether to dequote the incoming string.
	if (type == AnyScalar::ATTRTYPE_STRING)
	    value.setStringQuoted(strvalue);
	else
	    value.setString(strvalue); // not a string, but an integer or double or boolean value
    }

    /// constructor for folded constant values.
    PNConstant(const AnyScalar &_value)
	: value(_value)
    {
    }

    /// Easiest evaluation: return the constant.
    virtual AnyScalar evaluate(const class SymbolTable &) const
    {
	return value;
    }

    /// Returns true, because value is constant
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (dest) *dest = value;
	return true;
    }

    /// String representation of the constant AnyScalar value.
    virtual std::string toString() const
    {
	if (value.getType() == AnyScalar::ATTRTYPE_STRING) {
	    return value.getStringQuoted();
	}
	return value.getString();
    }
};

/// Parse tree node representing a variable place-holder. It is filled when
/// parameterized by a symbol table.
class PNVariable : public ParseNode
{
private:
    /// String name of the variable
    std::string		varname;

public:
    /// Constructor from the string received from the parser.
    PNVariable(std::string _varname)
	: ParseNode(), varname(_varname)
    {
    }

    /// Check the given symbol table for the actual value of this variable.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	return st.lookupVariable(varname);
    }

    /// Returns false, because value isn't constant.
    virtual bool evaluate_const(AnyScalar *) const
    {
	return false;
    }

    /// Nothing but the variable name.
    virtual std::string toString() const
    {
	return varname;
    }
};

/// Parse tree node representing a function place-holder. It is filled when
/// parameterized by a symbol table.
class PNFunction : public ParseNode
{
public:
    /// Type of sequence of subtrees to evaluate as function parameters.
    typedef std::vector<const class ParseNode*> paramlist_type;

private:
    /// String name of the function
    std::string		funcname;

    /// The array of function parameter subtrees
    paramlist_type	paramlist;

public:
    /// Constructor from the string received from the parser.
    PNFunction(std::string _funcname, const paramlist_type& _paramlist)
	: ParseNode(), funcname(_funcname), paramlist(_paramlist)
    {
    }

    /// Delete the paramlist
    ~PNFunction()
    {
	for(unsigned int i = 0; i < paramlist.size(); ++i)
	    delete paramlist[i];
    }

    /// Check the given symbol table for the actual value of this variable.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	std::vector<AnyScalar> paramvalues;

	for(unsigned int i = 0; i < paramlist.size(); ++i)
	{
	    paramvalues.push_back( paramlist[i]->evaluate(st) );
	}

	return st.processFunction(funcname, paramvalues);
    }

    /// Returns false, because value isn't constant.
    virtual bool evaluate_const(AnyScalar *) const
    {
	return false;
    }

    /// Nothing but the function and its parameters
    virtual std::string toString() const
    {
	std::string str = funcname + "(";
	for(unsigned int i = 0; i < paramlist.size(); ++i)
	{
	    if (i != 0) str += ",";
	    str += paramlist[i]->toString();
	}
	return str + ")";
    }
};

/// Parse tree node representing an unary operator: '+', '-', '!' or
/// "not". This node has one child.
class PNUnaryArithmExpr : public ParseNode
{
private:
    /// Pointer to the single operand
    const ParseNode 	*operand;

    /// Arithmetic operation to perform: either '+', '-' or '!'. Further
    /// optimization would be to create an extra class for each op
    char	op;

public:
    /// Constructor from the parser: operand subnode and operator id.
    PNUnaryArithmExpr(const ParseNode* _operand, char _op)
	: ParseNode(), operand(_operand), op(_op)
    {
	if (op == 'n' || op == 'N') op = '!';
    }

    /// Recursively delete the parse tree.
    virtual ~PNUnaryArithmExpr()
    {
	delete operand;
    }

    /// Applies the operator to the recursively calculated value.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	AnyScalar dest = operand->evaluate(st);

	if (op == '-') {
	    dest = -dest;	    
	}
	else if (op == '!')
	{
	    // This should not happend, as types are constant in the parse tree
	    if (dest.getType() != AnyScalar::ATTRTYPE_BOOL)
		throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));

	    dest = -dest;
 	}
	else {
	    assert(op == '+');
	}

	return dest;
    }

    /// Calculates subnodes and returns result if the operator can be applied.
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (!dest) return false;

	bool b = operand->evaluate_const(dest);

	if (op == '-') {
	    *dest = -(*dest);
	}
	else if (op == '!')
	{
	    if (dest->getType() != AnyScalar::ATTRTYPE_BOOL)
		throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));

	    *dest = -(*dest);
	}
	else {
	    assert(op == '+');
	}
	
	return b;
    }

    /// Return the subnode's string with this operator prepended.
    virtual std::string toString() const
    {
	return std::string("(") + op + " " + operand->toString() + ")";
    }
};

/// Parse tree node representing a binary operators: +, -, * and / for numeric
/// values. This node has two children.
class PNBinaryArithmExpr : public ParseNode
{
private:
    /// Pointers to the left of the two child parse trees.
    const ParseNode 	*left;

    /// Pointers to the right of the two child parse trees.
    const ParseNode	*right;

    /// Arithmetic operation to perform: left op right.
    /// Further optimization would be to create an extra class for each op
    char	op;

public:
    /// Constructor from the parser: both operand subnodes and the operator id.
    PNBinaryArithmExpr(const ParseNode* _left,
		       const ParseNode* _right,
		       char _op)
	: ParseNode(),
	  left(_left), right(_right), op(_op)
    { }

    /// Recursively delete parse tree.
    virtual ~PNBinaryArithmExpr()
    {
	delete left;
	delete right;
    }

    /// Applies the operator to the two recursive calculated values. The actual
    /// switching between types is handled by AnyScalar's operators.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	AnyScalar vl = left->evaluate(st);
	AnyScalar vr = right->evaluate(st);

	if (op == '+') {
	    return (vl + vr);
	}
	else if (op == '-') {
	    return (vl - vr);
	}
	else if (op == '*') {
	    return (vl * vr);
	}
	else if (op == '/') {
	    return (vl / vr);
	}

	assert(0);
	return 0;
    }

    /// Returns false because this node isn't always constant. Tries to
    /// calculate a constant subtree's value.
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (!dest) return false;

	AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
	
	bool bl = left->evaluate_const(&vl);
	bool br = right->evaluate_const(&vr);

	if (op == '+') {
	    *dest = vl + vr;
	}
	else if (op == '-') {
	    *dest = vl - vr;
	}
	else if (op == '*') {
	    *dest = vl * vr;
	}
	else if (op == '/') {
	    *dest = vl / vr;
	}

	return (bl && br);
    }

    /// String representing (operandA op operandB)
    virtual std::string toString() const
    {
	return std::string("(") + left->toString() + " " + op + " " + right->toString() + ")";
    }
};

/// Parse tree node handling type conversions within the tree.
class PNCastExpr : public ParseNode
{
private:
    /// Child tree of which the return value should be casted.
    const ParseNode*	operand;

    /// AnyScalar type to cast the value to.
    AnyScalar::attrtype_t	type;

public:
    /// Constructor from the parser: operand subnode and the cast type as
    /// recognized by AnyScalar.
    PNCastExpr(const ParseNode* _operand, AnyScalar::attrtype_t _type)
	: ParseNode(),
	  operand(_operand), type(_type)
    { }

    /// Recursively delete parse tree.
    virtual ~PNCastExpr()
    {
	delete operand;
    }

    /// Recursive calculation of the value and subsequent casting via
    /// AnyScalar's convertType method.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	AnyScalar val = operand->evaluate(st);
	val.convertType(type);
	return val;
    }

    /// Returns false because this node isn't always constant.
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (!dest) return false;

	bool b = operand->evaluate_const(dest);
	dest->convertType(type);
	return b;
    }

    /// c-like representation of the cast
    virtual std::string toString() const
    {
	return std::string("((") + AnyScalar::getTypeString(type) + ")" + operand->toString() + ")";
    }
};

/// Parse tree node representing a binary comparison operator: ==, =, !=, <, >,
/// >=, <=, =>, =<. This node has two children.
class PNBinaryComparisonExpr : public ParseNode
{
private:
    /// Pointers to the left of the two child parse trees.
    const ParseNode 	*left;

    /// Pointers to the right of the two child parse trees.
    const ParseNode	*right;

    /// Comparison operation to perform: left op right
    enum { EQUAL, NOTEQUAL, LESS, GREATER, LESSEQUAL, GREATEREQUAL } op;

    /// String saved for toString()
    std::string		opstr;

public:
    /// Constructor from the parser: both operand subnodes and the operator id.
    PNBinaryComparisonExpr(const ParseNode* _left,
			   const ParseNode* _right,
			   std::string _op)
	: ParseNode(),
	  left(_left), right(_right), opstr(_op)
    {
	if (_op == "==" || _op == "=")
	    op = EQUAL;
	else if (_op == "!=")
	    op = NOTEQUAL;
	else if (_op == "<")
	    op = LESS;
	else if (_op == ">")
	    op = GREATER;
	else if (_op == "<=" || _op == "=<")
	    op = LESSEQUAL;
	else if (_op == ">=" || _op == "=>")
	    op = GREATEREQUAL;
	else
	    throw(BadSyntaxException("Program Error: invalid binary comparision operator."));
    }

    /// Recursively delete parse tree.
    virtual ~PNBinaryComparisonExpr()
    {
	delete left;
	delete right;
    }

    /// Applies the operator to the two recursive calculated values. The actual
    /// switching between types is handled by AnyScalar's operators. This
    /// result type of this processing node is always bool.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	AnyScalar vl = left->evaluate(st);
	AnyScalar vr = right->evaluate(st);

	AnyScalar dest(AnyScalar::ATTRTYPE_BOOL);

	switch(op)
	{
	case EQUAL:
	    dest = AnyScalar( vl.equal_to(vr) );
	    break;

	case NOTEQUAL:
	    dest = AnyScalar( vl.not_equal_to(vr) );
	    break;

	case LESS:
	    dest = AnyScalar( vl.less(vr) );
	    break;

	case GREATER:
	    dest = AnyScalar( vl.greater(vr) );
	    break;

	case LESSEQUAL:
	    dest = AnyScalar( vl.less_equal(vr) );
	    break;

	case GREATEREQUAL:
	    dest = AnyScalar( vl.greater_equal(vr) );
	    break;

	default:
	    assert(0);
	}

	return dest;
    }

    /// Returns false because this node isn't always constant.
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (!dest) return false;

	AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
	
	bool bl = left->evaluate_const(&vl);
	bool br = right->evaluate_const(&vr);

	switch(op)
	{
	case EQUAL:
	    *dest = AnyScalar( vl.equal_to(vr) );
	    break;

	case NOTEQUAL:
	    *dest = AnyScalar( vl.not_equal_to(vr) );
	    break;

	case LESS:
	    *dest = AnyScalar( vl.less(vr) );
	    break;

	case GREATER:
	    *dest = AnyScalar( vl.greater(vr) );
	    break;

	case LESSEQUAL:
	    *dest = AnyScalar( vl.less_equal(vr) );
	    break;

	case GREATEREQUAL:
	    *dest = AnyScalar( vl.greater_equal(vr) );
	    break;

	default:
	    assert(0);
	}

	return (bl && br);
    }

    /// String (operandA op operandB)
    virtual std::string toString() const
    {
	return std::string("(") + left->toString() + " " + opstr + " " + right->toString() + ")";
    }
};

/// Parse tree node representing a binary logic operator: and, or, &&, ||. This
/// node has two children.
class PNBinaryLogicExpr : public ParseNode
{
private:
    /// Pointers to the left of the two child parse trees.
    ParseNode*		left;

    /// Pointers to the right of the two child parse trees.
    ParseNode*		right;

    /// Comparison operation to perform: left op right
    enum { OP_AND, OP_OR } op;

public:
    /// Constructor from the parser: both operand subnodes and the operator id.
    PNBinaryLogicExpr(ParseNode* _left,
		      ParseNode* _right,
		      std::string _op)
	: ParseNode(),
	  left(_left), right(_right)
    {
	if (_op == "and" || _op == "&&")
	    op = OP_AND;
	else if (_op == "or" || _op == "||")
	    op = OP_OR;
	else
	    throw(BadSyntaxException("Program Error: invalid binary logic operator."));
    }

    /// Recursively delete parse tree.
    virtual ~PNBinaryLogicExpr()
    {
	if (left) delete left;
	if (right) delete right;
    }

    /// Calculate the operator
    inline bool do_operator(bool left, bool right) const
    {
	if (op == OP_AND)
	    return left && right;
	else if (op == OP_OR)
	    return left || right;
	else
	    return false;
    }

    /// Return the string of this operator
    inline std::string get_opstr() const
    {
	return (op == OP_AND) ? "&&" : "||";
    }

    /// Applies the operator to the two recursive calculated values. The actual
    /// switching between types is handled by AnyScalar's operators.
    virtual AnyScalar evaluate(const class SymbolTable &st) const
    {
	AnyScalar vl = left->evaluate(st);
	AnyScalar vr = right->evaluate(st);

	// these should never happen.
	if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
	    throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
	if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
	    throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));

	int bvl = vl.getInteger();
	int bvr = vr.getInteger();

	return AnyScalar( do_operator(bvl, bvr) );
    }

    /// Applies the operator to the two recursive calculated const
    /// values. Determining if this node is constant is somewhat more tricky
    /// than with the other parse nodes: AND with a false operand is always
    /// false. OR with a true operand is always true.
    virtual bool evaluate_const(AnyScalar *dest) const
    {
	if (!dest) return false; // returns false because this node isn't always constant

	AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
	
	bool bl = left->evaluate_const(&vl);
	bool br = right->evaluate_const(&vr);

	if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
	    throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
	if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
	    throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));

	int bvl = vl.getInteger();
	int bvr = vr.getInteger();

	*dest = AnyScalar( do_operator(bvl, bvr) );

	if (op == OP_AND)
	{
	    // true if either both ops are themselves constant, or if either of
	    // the ops are constant and evaluates to false.
	    return (bl && br) || (bl && !bvl) || (br && !bvr);
	}
	else if (op == OP_OR)
	{
	    // true if either both ops are themselves constant, or if either of
	    // the ops is constant and evaluates to true.
	    return (bl && br) || (bl && bvl) || (br && bvr);
	}
	else {
	    assert(0);
	    return false;
	}
    }

    /// String (operandA op operandB)
    virtual std::string toString() const
    {
	return std::string("(") + left->toString() + " " + get_opstr() + " " + right->toString() + ")";
    }

    /// Detach left node
    inline ParseNode* detach_left()
    {
	ParseNode *n = left;
	left = NULL;
	return n;
    }

    /// Detach right node
    inline ParseNode* detach_right()
    {
	ParseNode *n = right;
	right = NULL;
	return n;
    }
};

// *** Functions which translate the resulting parse tree into our expression
// *** tree, simultaneously folding constants.

/// Iterator type used by spirit's parsers.
typedef std::string::const_iterator InputIterT;

/// Resulting match tree after parsing
typedef tree_match<InputIterT> ParseTreeMatchT;

/// The iterator of the match tree used in build_expr()
typedef ParseTreeMatchT::const_tree_iterator TreeIterT;

/// Build_expr is the constructor method to create a parse tree from the
/// AST-tree returned by the spirit parser.
static ParseNode* build_expr(TreeIterT const& i)
{
#ifdef STX_DEBUG_PARSER
    std::cout << "In build_expr. i->value = " <<
        std::string(i->value.begin(), i->value.end()) <<
        " i->children.size() = " << i->children.size() << 
	" i->value.id = " << i->value.id().to_long() << std::endl;
#endif

    switch(i->value.id().to_long())
    {
    // *** Constant node cases

    case boolean_const_id:
    {
	return new PNConstant(AnyScalar::ATTRTYPE_BOOL,
			      std::string(i->value.begin(), i->value.end()));
    }

    case integer_const_id:
    {
	return new PNConstant(AnyScalar::ATTRTYPE_INTEGER,
			      std::string(i->value.begin(), i->value.end()));
    }

    case long_const_id:
    {
	return new PNConstant(AnyScalar::ATTRTYPE_LONG,
			      std::string(i->value.begin(), i->value.end()));
    }

    case double_const_id:
    {
	return new PNConstant(AnyScalar::ATTRTYPE_DOUBLE,
			      std::string(i->value.begin(), i->value.end()));
    }

    case string_const_id:
    {
	return new PNConstant(AnyScalar::ATTRTYPE_STRING,
			      std::string(i->value.begin(), i->value.end()));
    }

    // *** Arithmetic node cases

    case unary_expr_id:
    {
	char arithop = *i->value.begin();
	assert(i->children.size() == 1);

	const ParseNode *val = build_expr(i->children.begin());

	if (val->evaluate_const(NULL))
	{
	    // construct a constant node
	    PNUnaryArithmExpr tmpnode(val, arithop);
	    AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);

	    tmpnode.evaluate_const(&constval);

	    return new PNConstant(constval);
	}
	else
	{
	    // calculation node
	    return new PNUnaryArithmExpr(val, arithop);
	}
    }

    case add_expr_id:
    case mul_expr_id:
    {
	char arithop = *i->value.begin();
	assert(i->children.size() == 2);

	// auto_ptr needed because of possible parse exceptions in build_expr.

	std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
	std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );

	if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
	{
	    // construct a constant node
	    PNBinaryArithmExpr tmpnode(left.release(), right.release(), arithop);
	    AnyScalar both(AnyScalar::ATTRTYPE_INVALID);

	    tmpnode.evaluate_const(&both);

	    // left and right are deleted by tmpnode's deconstructor

	    return new PNConstant(both);
	}
	else
	{
	    // calculation node
	    return new PNBinaryArithmExpr(left.release(), right.release(), arithop);
        }
    }

    // *** Cast node case

    case cast_spec_id:
    {
	assert(i->children.size() == 1);

	std::string tname(i->value.begin(), i->value.end());
	AnyScalar::attrtype_t at = AnyScalar::stringToType(tname);
	
	const ParseNode *val = build_expr(i->children.begin());

	if (val->evaluate_const(NULL))
	{
	    // construct a constant node
	    PNCastExpr tmpnode(val, at);

	    AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);

	    tmpnode.evaluate_const(&constval);

	    return new PNConstant(constval);
	}
	else
	{
	    return new PNCastExpr(val, at);
	}
    }

    // *** Binary Comparison Operator

    case comp_expr_id:
    {
	assert(i->children.size() == 2);

	std::string arithop(i->value.begin(), i->value.end());

	// we need auto_ptr because of possible parse exceptions in build_expr.

	std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
	std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );

	if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
	{
	    // construct a constant node
	    PNBinaryComparisonExpr tmpnode(left.release(), right.release(), arithop);
	    AnyScalar both(AnyScalar::ATTRTYPE_INVALID);

	    tmpnode.evaluate_const(&both);

	    // left and right are deleted by tmpnode's deconstructor

	    return new PNConstant(both);
	}
	else
	{
	    // calculation node
	    return new PNBinaryComparisonExpr(left.release(), right.release(), arithop);
        }
    }

    // *** Binary Logic Operator

    case and_expr_id:
    case or_expr_id:
    {
	assert(i->children.size() == 2);

	std::string logicop(i->value.begin(), i->value.end());
	std::transform(logicop.begin(), logicop.end(), logicop.begin(), tolower);

	// auto_ptr needed because of possible parse exceptions in build_expr.

	std::auto_ptr<ParseNode> left( build_expr(i->children.begin()) );
	std::auto_ptr<ParseNode> right( build_expr(i->children.begin()+1) );

	bool constleft = left->evaluate_const(NULL);
	bool constright = right->evaluate_const(NULL);

	// a logical node is constant if one of the two ops is constant. so we
	// construct a calculation node and check later.
	std::auto_ptr<PNBinaryLogicExpr> node( new PNBinaryLogicExpr(left.release(), right.release(), logicop) );

	if (constleft || constright)
	{
	    AnyScalar both(AnyScalar::ATTRTYPE_INVALID);

	    // test if the node is really const.
	    if (node->evaluate_const(&both))
	    {
		// return a constant node instead, node will be deleted by
		// auto_ptr, left,right by node's destructor.
		return new PNConstant(both);
	    }
	}
	if (constleft)
	{
	    // left node is constant, but the evaluation is not
	    // -> only right node is meaningful.
	    return node->detach_right();
	}
	if (constright)
	{
	    // right node is constant, but the evaluation is not
	    // -> only left node is meaningful.
	    return node->detach_left();
	}

	return node.release();
    }

    // *** Variable and Function name place-holder

    case varname_id:
    {
	assert(i->children.size() == 0);

	std::string varname(i->value.begin(), i->value.end());

        return new PNVariable(varname);
    }

    case function_identifier_id:
    {
	std::string funcname(i->value.begin(), i->value.end());
	std::vector<const class ParseNode*> paramlist;

	if (i->children.size() > 0)
	{
	    TreeIterT const& paramlistchild = i->children.begin();

	    if (paramlistchild->value.id().to_long() == exprlist_id)
	    {
		try
		{
		    for(TreeIterT ci = paramlistchild->children.begin(); ci != paramlistchild->children.end(); ++ci)
		    {
			const ParseNode *pas = build_expr(ci);
			paramlist.push_back(pas);
		    }
		}
		catch (...) // need to clean-up
		{
		    for(unsigned int i = 0; i < paramlist.size(); ++i)
			delete paramlist[i];
		    throw;
		}
	    }
	    else
	    {
		// just one subnode and its not a full expression list
		paramlist.push_back( build_expr(paramlistchild) );
	    }
	}

        return new PNFunction(funcname, paramlist);
    }

    default:
	throw(ExpressionParserException("Unknown AST parse tree node found. This should never happen."));
    }
}

/// build_exprlist constructs the vector holding the ParseNode parse tree for
/// each parse tree.
ParseTreeList build_exprlist(TreeIterT const &i)
{
#ifdef STX_DEBUG_PARSER
    std::cout << "In build_exprlist. i->value = " <<
        std::string(i->value.begin(), i->value.end()) <<
        " i->children.size() = " << i->children.size() << 
	" i->value.id = " << i->value.id().to_long() << std::endl;
#endif

    ParseTreeList ptlist;

    for(TreeIterT ci = i->children.begin(); ci != i->children.end(); ++ci)
    {
	ParseNode *vas = build_expr(ci);

	ptlist.push_back( ParseTree(vas) );
    }

    return ptlist;
}

/// Uses boost::spirit function to convert the parse tree into a XML document.
static inline void tree_dump_xml(std::ostream &os, const std::string &input, const tree_parse_info<InputIterT> &info)
{
    // map used by the xml dumper to label the nodes

    std::map<parser_id, std::string> rule_names;

    rule_names[boolean_const_id] = "boolean_const";
    rule_names[integer_const_id] = "integer_const";
    rule_names[long_const_id] = "long_const";
    rule_names[double_const_id] = "double_const";
    rule_names[string_const_id] = "string_const";
    rule_names[constant_id] = "constant";

    rule_names[function_call_id] = "function_call";
    rule_names[function_identifier_id] = "function_identifier";

    rule_names[varname_id] = "varname";

    rule_names[unary_expr_id] = "unary_expr";
    rule_names[mul_expr_id] = "mul_expr";
    rule_names[add_expr_id] = "add_expr";

    rule_names[cast_expr_id] = "cast_expr";
    rule_names[cast_spec_id] = "cast_spec";

    rule_names[comp_expr_id] = "comp_expr";
    rule_names[and_expr_id] = "and_expr";
    rule_names[or_expr_id] = "or_expr";

    rule_names[expr_id] = "expr";
    rule_names[exprlist_id] = "exprlist";

    tree_to_xml(os, info.trees, input.c_str(), rule_names);
}

} // namespace Grammar

const ParseTree parseExpression(const std::string &input)
{
    // instance of the grammar
    Grammar::ExpressionGrammar g;

#ifdef STX_DEBUG_PARSER
    BOOST_SPIRIT_DEBUG_GRAMMAR(g);
#endif

    Grammar::tree_parse_info<Grammar::InputIterT> info =
	boost::spirit::ast_parse(input.begin(), input.end(),
				 g.use_parser<0>(),	// use first entry point: expr
				 boost::spirit::space_p);

    if (!info.full)
    {
	std::ostringstream oss;
	oss << "Syntax error at position "
	    << static_cast<int>(info.stop - input.begin())
	    << " near " 
	    << std::string(info.stop, input.end());

	throw(BadSyntaxException(oss.str()));
    }

    return ParseTree( Grammar::build_expr(info.trees.begin()) );
}

std::string parseExpressionXML(const std::string &input)
{
    // instance of the grammar
    Grammar::ExpressionGrammar g;

#ifdef STX_DEBUG_PARSER
    BOOST_SPIRIT_DEBUG_GRAMMAR(g);
#endif

    Grammar::tree_parse_info<Grammar::InputIterT> info =
	boost::spirit::ast_parse(input.begin(), input.end(),
				 g.use_parser<0>(),	// use first entry point: expr
				 boost::spirit::space_p);

    if (!info.full)
    {
	std::ostringstream oss;
	oss << "Syntax error at position "
	    << static_cast<int>(info.stop - input.begin())
	    << " near " 
	    << std::string(info.stop, input.end());

	throw(BadSyntaxException(oss.str()));
    }

    std::ostringstream oss;
    Grammar::tree_dump_xml(oss, input, info);
    return oss.str();
}

ParseTreeList parseExpressionList(const std::string &input)
{
    // instance of the grammar
    Grammar::ExpressionGrammar g;

#ifdef STX_DEBUG_PARSER
    BOOST_SPIRIT_DEBUG_GRAMMAR(g);
#endif

    Grammar::tree_parse_info<Grammar::InputIterT> info =
	boost::spirit::ast_parse(input.begin(), input.end(),
				 g.use_parser<1>(),	// use second entry point: exprlist
				 boost::spirit::space_p);

    if (!info.full)
    {
	std::ostringstream oss;
	oss << "Syntax error at position "
	    << static_cast<int>(info.stop - input.begin())
	    << " near " 
	    << std::string(info.stop, input.end());

	throw(BadSyntaxException(oss.str()));
    }

    return Grammar::build_exprlist(info.trees.begin());
}

std::vector<AnyScalar> ParseTreeList::evaluate(const class SymbolTable &st) const
{
    std::vector<AnyScalar> vl;

    for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
    {
	vl.push_back( i->evaluate(st) );
    }

    return vl;
}

std::string ParseTreeList::toString() const
{
    std::string sl;

    for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
    {
	if (i != parent_type::begin()) {
	    sl += ", ";
	}

	sl += i->toString();
    }

    return sl;
}

/// *** SymbolTable, EmptySymbolTable and BasicSymbolTable implementation

SymbolTable::~SymbolTable()
{
}

EmptySymbolTable::~EmptySymbolTable()
{
}

AnyScalar EmptySymbolTable::lookupVariable(const std::string &varname) const
{
    throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
}

AnyScalar EmptySymbolTable::processFunction(const std::string &funcname,
					    const paramlist_type &) const
{
    throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
}

BasicSymbolTable::BasicSymbolTable()
{
    addStandardFunctions();
}

BasicSymbolTable::~BasicSymbolTable()
{
}

void BasicSymbolTable::setVariable(const std::string& varname, const AnyScalar &value)
{
    std::string vn = varname;
    std::transform(vn.begin(), vn.end(), vn.begin(), tolower);

    variablemap[vn] = value;
}

void BasicSymbolTable::setFunction(const std::string& funcname, int arguments, functionptr_type funcptr)
{
    std::string fn = funcname;
    std::transform(fn.begin(), fn.end(), fn.begin(), toupper);

    functionmap[fn] = FunctionInfo(arguments, funcptr);
}

void BasicSymbolTable::clearVariables()
{
    variablemap.clear();
}

void BasicSymbolTable::clearFunctions()
{
    functionmap.clear();
}

AnyScalar BasicSymbolTable::funcPI(const paramlist_type &)
{
    return AnyScalar(3.14159265358979323846);
}

AnyScalar BasicSymbolTable::funcSIN(const paramlist_type &paramlist)
{
    return AnyScalar( std::sin(paramlist[0].getDouble()) );
}

AnyScalar BasicSymbolTable::funcCOS(const paramlist_type &paramlist)
{
    return AnyScalar( std::cos(paramlist[0].getDouble()) );
}

AnyScalar BasicSymbolTable::funcTAN(const paramlist_type &paramlist)
{
    return AnyScalar( std::tan(paramlist[0].getDouble()) );
}

AnyScalar BasicSymbolTable::funcABS(const paramlist_type &paramlist)
{
    if (paramlist[0].isIntegerType()) {
	return AnyScalar( std::abs(paramlist[0].getInteger()) );
    }
    else if (paramlist[0].isFloatingType()) {
	return AnyScalar( std::fabs(paramlist[0].getDouble()) );
    }
    else {
	throw(BadFunctionCallException("Function ABS() takes exactly one parameter"));
    }
}

AnyScalar BasicSymbolTable::funcEXP(const paramlist_type &paramlist)
{
    return AnyScalar( std::exp(paramlist[0].getDouble()) );
}

AnyScalar BasicSymbolTable::funcLOGN(const paramlist_type &paramlist)
{
    return AnyScalar( std::log(paramlist[0].getDouble()) );
}

AnyScalar BasicSymbolTable::funcPOW(const paramlist_type &paramlist)
{
    return AnyScalar( std::pow(paramlist[0].getDouble(), paramlist[1].getDouble()) );
}

AnyScalar BasicSymbolTable::funcSQRT(const paramlist_type &paramlist)
{
    return AnyScalar( std::sqrt(paramlist[0].getDouble()) );
}

void BasicSymbolTable::addStandardFunctions()
{
    setFunction("PI", 0, funcPI);

    setFunction("SIN", 1, funcSIN);
    setFunction("COS", 1, funcCOS);
    setFunction("TAN", 1, funcTAN);

    setFunction("ABS", 1, funcABS);
    setFunction("EXP", 1, funcEXP);
    setFunction("LOGN", 1, funcLOGN);
    setFunction("POW", 2, funcPOW);
    setFunction("SQRT", 1, funcSQRT);
}

AnyScalar BasicSymbolTable::lookupVariable(const std::string &_varname) const
{
    std::string varname = _varname;
    std::transform(varname.begin(), varname.end(), varname.begin(), tolower);

    variablemap_type::const_iterator fi = variablemap.find(varname);

    if (fi != variablemap.end())
    {
	return fi->second;
    }

    throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
}

AnyScalar BasicSymbolTable::processFunction(const std::string &_funcname,
					    const paramlist_type &paramlist) const
{
    std::string funcname = _funcname;
    std::transform(funcname.begin(), funcname.end(), funcname.begin(), toupper);

    functionmap_type::const_iterator fi = functionmap.find(funcname);

    if (fi != functionmap.end())
    {
	if (fi->second.arguments >= 0)
	{
	    if (fi->second.arguments == 0 && paramlist.size() != 0)
	    {
		throw(BadFunctionCallException(std::string("Function ") + funcname + "() does not take any parameter."));
	    }
	    else if (fi->second.arguments == 1 && paramlist.size() != 1)
	    {
		throw(BadFunctionCallException(std::string("Function ") + funcname + "() takes exactly one parameter."));
	    }
	    else if (static_cast<unsigned int>(fi->second.arguments) != paramlist.size())
	    {
		std::ostringstream oss;
		oss << "Function " << funcname << "() takes exactly " << fi->second.arguments << " parameters.";
		throw(BadFunctionCallException(oss.str()));
	    }
	}
	return fi->second.func(paramlist);
    }

    throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
}

} // namespace stx