LTP GCOV extension - code coverage report
Current view: directory - libstx-exparser - ExpressionParser.cc
Test: STX ExpressionParser Testsuite
Date: 2007-07-17 Instrumented lines: 523
Code covered: 75.1 % Executed lines: 393

       1                 : // $Id: ExpressionParser.cc 59 2007-07-17 14:43:23Z tb $
       2                 : 
       3                 : /*
       4                 :  * STX Expression Parser C++ Framework v0.7
       5                 :  * Copyright (C) 2007 Timo Bingmann
       6                 :  *
       7                 :  * This library is free software; you can redistribute it and/or modify it
       8                 :  * under the terms of the GNU Lesser General Public License as published by the
       9                 :  * Free Software Foundation; either version 2.1 of the License, or (at your
      10                 :  * option) any later version.
      11                 :  *
      12                 :  * This library is distributed in the hope that it will be useful, but WITHOUT
      13                 :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14                 :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
      15                 :  * for more details.
      16                 :  *
      17                 :  * You should have received a copy of the GNU Lesser General Public License
      18                 :  * along with this library; if not, write to the Free Software Foundation,
      19                 :  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20                 :  */
      21                 : 
      22                 : /** \file ExpressionParser.cc
      23                 :  * Implementation of the parser using a boost::spirit grammar and a different
      24                 :  * specializations of ParseNode.
      25                 :  */
      26                 : 
      27                 : #include "ExpressionParser.h"
      28                 : 
      29                 : #include <boost/spirit/core.hpp>
      30                 : 
      31                 : #include <boost/spirit/tree/ast.hpp>
      32                 : #include <boost/spirit/tree/tree_to_xml.hpp>
      33                 : 
      34                 : #include <boost/spirit/utility/lists.hpp>
      35                 : #include <boost/spirit/utility/distinct.hpp>
      36                 : #include <boost/spirit/utility/escape_char.hpp>
      37                 : #include <boost/spirit/utility/grammar_def.hpp> 
      38                 : 
      39                 : #include <iostream>
      40                 : #include <sstream>
      41                 : #include <cmath>
      42                 : 
      43                 : // #define STX_DEBUG_PARSER
      44                 : 
      45                 : namespace stx {
      46                 : 
      47                 : /// Enclosure for the spirit parser grammar and hidden parse node
      48                 : /// implementation classes.
      49                 : namespace Grammar {
      50                 : 
      51                 : using namespace boost::spirit;
      52                 : 
      53                 : /// This enum specifies ids for the parse tree nodes created for each rule.
      54                 : enum parser_ids
      55                 : {
      56                 :     boolean_const_id = 1,
      57                 :     integer_const_id,
      58                 :     long_const_id,
      59                 :     double_const_id,
      60                 :     string_const_id,
      61                 :     constant_id,
      62                 : 
      63                 :     function_call_id,
      64                 :     function_identifier_id,
      65                 : 
      66                 :     varname_id,
      67                 : 
      68                 :     atom_expr_id,
      69                 : 
      70                 :     unary_expr_id,
      71                 :     mul_expr_id,
      72                 :     add_expr_id,
      73                 : 
      74                 :     cast_expr_id,
      75                 :     cast_spec_id,
      76                 : 
      77                 :     comp_expr_id,
      78                 :     and_expr_id,
      79                 :     or_expr_id,
      80                 : 
      81                 :     expr_id,
      82                 :     exprlist_id,
      83                 : };
      84                 : 
      85                 : /// Keyword parser used for matching words with () and spaces as separators.
      86               2 : distinct_parser<> keyword_p("a-zA-Z0-9_");
      87                 : 
      88                 : /// The boost::spirit expression parser grammar
      89                 : struct ExpressionGrammar : public grammar<ExpressionGrammar>
      90              72 : {
      91                 :     /// The boost::spirit expression parser grammar definition (for a specific
      92                 :     /// scanner) with two entry points.
      93                 :     template <typename ScannerT>
      94                 :     struct definition : public grammar_def<rule<ScannerT, parser_context<>, parser_tag<expr_id> >,
      95                 :                                            rule<ScannerT, parser_context<>, parser_tag<exprlist_id> > >
      96              36 :     {
      97                 :         /// Real definition function of the grammar.
      98              36 :         definition(ExpressionGrammar const& /*self*/)
      99              36 :         {
     100                 :             // *** Constants
     101                 : 
     102              36 :             constant
     103                 :                 = double_const
     104                 :                 | integer_const
     105                 :                 | long_const
     106                 :                 | boolean_const
     107                 :                 | string_const
     108                 :                 ;
     109                 :             
     110              36 :             boolean_const
     111                 :                 = as_lower_d[keyword_p("true") | keyword_p("false")]
     112                 :                 ;
     113                 : 
     114              36 :             integer_const
     115                 :                 = int_p
     116                 :                 ;
     117                 : 
     118                 :             // this is needed because spirit's int_parsers don't work with
     119                 :             // these long numbers
     120              36 :             long_const
     121                 :                 = token_node_d[ lexeme_d[ !( ch_p('+') | ch_p('-' ) ) >> +( range_p('0','9') ) ] ]
     122                 :                 ;
     123                 : 
     124              36 :             double_const
     125                 :                 = strict_real_p
     126                 :                 ;
     127                 : 
     128              36 :             string_const
     129                 :                 = lexeme_d[
     130                 :                     token_node_d[ '"' >> *(c_escape_ch_p - '"') >> '"' ]
     131                 :                     ]
     132                 :                 ;
     133                 : 
     134                 :             // *** Function call and function identifier
     135                 : 
     136              36 :             function_call
     137                 :                 = root_node_d[function_identifier]
     138                 :                 >> discard_node_d[ ch_p('(') ] >> exprlist >> discard_node_d[ ch_p(')') ]
     139                 :                 ;
     140                 : 
     141              36 :             function_identifier
     142                 :                 = lexeme_d[ 
     143                 :                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
     144                 :                     ]
     145                 :                 ;
     146                 : 
     147                 :             // *** Expression names
     148                 : 
     149              36 :             varname
     150                 :                 = lexeme_d[ 
     151                 :                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
     152                 :                     ]
     153                 :                 ;
     154                 : 
     155                 :             // *** Valid Expressions, from small to large
     156                 : 
     157              36 :             atom_expr
     158                 :                 = constant
     159                 :                 | inner_node_d[ ch_p('(') >> expr >> ch_p(')') ]
     160                 :                 | function_call
     161                 :                 | varname
     162                 :                 ;
     163                 : 
     164              36 :             unary_expr
     165                 :                 = !( root_node_d[ as_lower_d[ch_p('+') | ch_p('-') | ch_p('!') | str_p("not")] ] )
     166                 :                 >> atom_expr
     167                 :                 ;
     168                 : 
     169              36 :             cast_spec
     170                 :                 = discard_node_d[ ch_p('(') ]
     171                 :                 >> (
     172                 :                     keyword_p("bool") |
     173                 :                     keyword_p("char") | keyword_p("short") | keyword_p("int") | keyword_p("integer") | keyword_p("long") |
     174                 :                     keyword_p("byte") | keyword_p("word") | keyword_p("dword") | keyword_p("qword") |
     175                 :                     keyword_p("float") | keyword_p("double") |
     176                 :                     keyword_p("string")
     177                 :                     )
     178                 :                 >> discard_node_d[ ch_p(')') ]
     179                 :                 ;
     180                 : 
     181              36 :             cast_expr
     182                 :                 = root_node_d[ !cast_spec ] >> unary_expr
     183                 :                 ;
     184                 : 
     185              36 :             mul_expr
     186                 :                 = cast_expr
     187                 :                 >> *( root_node_d[ch_p('*') | ch_p('/')] >> cast_expr )
     188                 :                 ;
     189                 : 
     190              36 :             add_expr
     191                 :                 = mul_expr
     192                 :                 >> *( root_node_d[ch_p('+') | ch_p('-')] >> mul_expr )
     193                 :                 ;
     194                 : 
     195              36 :             comp_expr
     196                 :                 = add_expr
     197                 :                 >> *( root_node_d[( str_p("==") | str_p("!=") |
     198                 :                                     str_p("<=") | str_p(">=") | str_p("=<") | str_p("=>") |
     199                 :                                     ch_p('=') | ch_p('<') | ch_p('>') )] >> add_expr )
     200                 :                 ;
     201                 : 
     202              36 :             and_expr
     203                 :                 = comp_expr
     204                 :                 >> *( root_node_d[ as_lower_d[str_p("and") | str_p("&&")] ] >> comp_expr )
     205                 :                 ;
     206                 : 
     207              36 :             or_expr
     208                 :                 = and_expr
     209                 :                 >> *( root_node_d[ as_lower_d[str_p("or") | str_p("||")] ] >> and_expr )
     210                 :                 ;
     211                 : 
     212                 :             // *** Base Expression and List
     213                 : 
     214              36 :             expr
     215                 :                 = or_expr
     216                 :                 ;
     217                 : 
     218              36 :             exprlist
     219                 :                 = infix_node_d[ !list_p(expr, ch_p(',')) ]
     220                 :                 ;
     221                 : 
     222                 :             // Special spirit feature to declare multiple grammar entry points
     223              36 :             this->start_parsers(expr, exprlist); 
     224                 : 
     225                 : #ifdef STX_DEBUG_PARSER
     226                 :             BOOST_SPIRIT_DEBUG_RULE(constant);
     227                 : 
     228                 :             BOOST_SPIRIT_DEBUG_RULE(boolean_const);
     229                 :             BOOST_SPIRIT_DEBUG_RULE(integer_const);
     230                 :             BOOST_SPIRIT_DEBUG_RULE(long_const);
     231                 :             BOOST_SPIRIT_DEBUG_RULE(double_const);
     232                 :             BOOST_SPIRIT_DEBUG_RULE(string_const);
     233                 : 
     234                 :             BOOST_SPIRIT_DEBUG_RULE(function_call);
     235                 :             BOOST_SPIRIT_DEBUG_RULE(function_identifier);
     236                 :             
     237                 :             BOOST_SPIRIT_DEBUG_RULE(varname);
     238                 : 
     239                 :             BOOST_SPIRIT_DEBUG_RULE(atom_expr);
     240                 : 
     241                 :             BOOST_SPIRIT_DEBUG_RULE(unary_expr);
     242                 :             BOOST_SPIRIT_DEBUG_RULE(mul_expr);
     243                 :             BOOST_SPIRIT_DEBUG_RULE(add_expr);
     244                 : 
     245                 :             BOOST_SPIRIT_DEBUG_RULE(cast_spec);
     246                 :             BOOST_SPIRIT_DEBUG_RULE(cast_expr);
     247                 : 
     248                 :             BOOST_SPIRIT_DEBUG_RULE(comp_expr);
     249                 :             BOOST_SPIRIT_DEBUG_RULE(and_expr);
     250                 :             BOOST_SPIRIT_DEBUG_RULE(or_expr);
     251                 : 
     252                 :             BOOST_SPIRIT_DEBUG_RULE(expr);
     253                 :             BOOST_SPIRIT_DEBUG_RULE(exprlist);
     254                 : #endif
     255                 :         }
     256                 : 
     257                 :         /// Rule for a constant: one of the three scalar types integer_const,
     258                 :         /// double_const or string_const
     259                 :         rule<ScannerT, parser_context<>, parser_tag<constant_id> >            constant;
     260                 : 
     261                 :         /// Boolean value constant rule: "true" or "false"
     262                 :         rule<ScannerT, parser_context<>, parser_tag<boolean_const_id> >       boolean_const;
     263                 :         /// Integer constant rule: "1234"
     264                 :         rule<ScannerT, parser_context<>, parser_tag<integer_const_id> >       integer_const;
     265                 :         /// Long integer constant rule: "12345452154"
     266                 :         rule<ScannerT, parser_context<>, parser_tag<long_const_id> >          long_const;
     267                 :         /// Float constant rule: "1234.3"
     268                 :         rule<ScannerT, parser_context<>, parser_tag<double_const_id> >                double_const;
     269                 :         /// String constant rule: with quotes "abc"
     270                 :         rule<ScannerT, parser_context<>, parser_tag<string_const_id> >                string_const;
     271                 : 
     272                 :         /// Function call rule: func1(a,b,c) where a,b,c is a list of exprs
     273                 :         rule<ScannerT, parser_context<>, parser_tag<function_call_id> >       function_call;
     274                 :         /// Function rule to match a function identifier: alphanumeric and _
     275                 :         /// are allowed.
     276                 :         rule<ScannerT, parser_context<>, parser_tag<function_identifier_id> >         function_identifier;
     277                 : 
     278                 :         /// Rule to match a variable name: alphanumeric with _
     279                 :         rule<ScannerT, parser_context<>, parser_tag<varname_id> >             varname;
     280                 : 
     281                 :         /// Helper rule which implements () bracket grouping.
     282                 :         rule<ScannerT, parser_context<>, parser_tag<atom_expr_id> >           atom_expr;
     283                 : 
     284                 :         /// Unary operator rule: recognizes + - ! and "not".
     285                 :         rule<ScannerT, parser_context<>, parser_tag<unary_expr_id> >          unary_expr;
     286                 :         /// Binary operator rule taking precedent before add_expr:
     287                 :         /// recognizes * and /
     288                 :         rule<ScannerT, parser_context<>, parser_tag<mul_expr_id> >            mul_expr;
     289                 :         /// Binary operator rule: recognizes + and -
     290                 :         rule<ScannerT, parser_context<>, parser_tag<add_expr_id> >            add_expr;
     291                 : 
     292                 :         /// Match all the allowed cast types: short, double, etc.
     293                 :         rule<ScannerT, parser_context<>, parser_tag<cast_spec_id> >           cast_spec;
     294                 :         /// Cast operator written like in C: (short)
     295                 :         rule<ScannerT, parser_context<>, parser_tag<cast_expr_id> >           cast_expr;
     296                 : 
     297                 :         /// Comparison operator: recognizes == = != <= >= < > => =<
     298                 :         rule<ScannerT, parser_context<>, parser_tag<comp_expr_id> >           comp_expr;
     299                 :         /// Boolean operator: recognizes && and "and" and works only on boolean
     300                 :         /// values
     301                 :         rule<ScannerT, parser_context<>, parser_tag<and_expr_id> >            and_expr;
     302                 :         /// Boolean operator: recognizes || and "or" and works only on boolean
     303                 :         /// values
     304                 :         rule<ScannerT, parser_context<>, parser_tag<or_expr_id> >             or_expr;
     305                 : 
     306                 :         /// Base rule to match an expression 
     307                 :         rule<ScannerT, parser_context<>, parser_tag<expr_id> >                        expr;
     308                 :         /// Base rule to match a comma-separated list of expressions (used for
     309                 :         /// function arguments and lists of expressions)
     310                 :         rule<ScannerT, parser_context<>, parser_tag<exprlist_id> >                    exprlist;
     311                 :     };
     312                 : };
     313                 : 
     314                 : // *** Classes representing the nodes in the resulting parse tree, these need
     315                 : // *** not be publicly available via the header file.
     316                 : 
     317                 : /// Constant value nodes of the parse tree. This class holds any of the three
     318                 : /// constant types in the enclosed AnyScalar object.
     319                 : class PNConstant : public ParseNode
     320             132 : {
     321                 : private:
     322                 :     /// The constant parsed value.
     323                 :     class AnyScalar     value;
     324                 : 
     325                 : public:
     326                 :     /// Assignment from the string received from the parser.
     327              86 :     PNConstant(AnyScalar::attrtype_t type, std::string strvalue)
     328              86 :         : ParseNode(), value(type)
     329                 :     {
     330                 :         // check whether to dequote the incoming string.
     331              86 :         if (type == AnyScalar::ATTRTYPE_STRING)
     332               6 :             value.setStringQuoted(strvalue);
     333                 :         else
     334              80 :             value.setString(strvalue); // not a string, but an integer or double or boolean value
     335              86 :     }
     336                 : 
     337                 :     /// constructor for folded constant values.
     338              46 :     PNConstant(const AnyScalar &_value)
     339              46 :         : value(_value)
     340                 :     {
     341              46 :     }
     342                 : 
     343                 :     /// Easiest evaluation: return the constant.
     344              24 :     virtual AnyScalar evaluate(const class SymbolTable &) const
     345                 :     {
     346              24 :         return value;
     347                 :     }
     348                 : 
     349                 :     /// Returns true, because value is constant
     350             176 :     virtual bool evaluate_const(AnyScalar *dest) const
     351                 :     {
     352             176 :         if (dest) *dest = value;
     353             176 :         return true;
     354                 :     }
     355                 : 
     356                 :     /// String representation of the constant AnyScalar value.
     357              48 :     virtual std::string toString() const
     358                 :     {
     359              48 :         if (value.getType() == AnyScalar::ATTRTYPE_STRING) {
     360               4 :             return value.getStringQuoted();
     361                 :         }
     362              44 :         return value.getString();
     363                 :     }
     364                 : };
     365                 : 
     366                 : /// Parse tree node representing a variable place-holder. It is filled when
     367                 : /// parameterized by a symbol table.
     368                 : class PNVariable : public ParseNode
     369               8 : {
     370                 : private:
     371                 :     /// String name of the variable
     372                 :     std::string         varname;
     373                 : 
     374                 : public:
     375                 :     /// Constructor from the string received from the parser.
     376               8 :     PNVariable(std::string _varname)
     377               8 :         : ParseNode(), varname(_varname)
     378                 :     {
     379               8 :     }
     380                 : 
     381                 :     /// Check the given symbol table for the actual value of this variable.
     382               4 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     383                 :     {
     384               4 :         return st.lookupVariable(varname);
     385                 :     }
     386                 : 
     387                 :     /// Returns false, because value isn't constant.
     388               8 :     virtual bool evaluate_const(AnyScalar *) const
     389                 :     {
     390               8 :         return false;
     391                 :     }
     392                 : 
     393                 :     /// Nothing but the variable name.
     394               8 :     virtual std::string toString() const
     395                 :     {
     396               8 :         return varname;
     397                 :     }
     398                 : };
     399                 : 
     400                 : /// Parse tree node representing a function place-holder. It is filled when
     401                 : /// parameterized by a symbol table.
     402                 : class PNFunction : public ParseNode
     403                 : {
     404                 : public:
     405                 :     /// Type of sequence of subtrees to evaluate as function parameters.
     406                 :     typedef std::vector<const class ParseNode*> paramlist_type;
     407                 : 
     408                 : private:
     409                 :     /// String name of the function
     410                 :     std::string         funcname;
     411                 : 
     412                 :     /// The array of function parameter subtrees
     413                 :     paramlist_type      paramlist;
     414                 : 
     415                 : public:
     416                 :     /// Constructor from the string received from the parser.
     417              12 :     PNFunction(std::string _funcname, const paramlist_type& _paramlist)
     418              12 :         : ParseNode(), funcname(_funcname), paramlist(_paramlist)
     419                 :     {
     420              12 :     }
     421                 : 
     422                 :     /// Delete the paramlist
     423              12 :     ~PNFunction()
     424              12 :     {
     425              26 :         for(unsigned int i = 0; i < paramlist.size(); ++i)
     426              14 :             delete paramlist[i];
     427              12 :     }
     428                 : 
     429                 :     /// Check the given symbol table for the actual value of this variable.
     430               6 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     431                 :     {
     432               6 :         std::vector<AnyScalar> paramvalues;
     433                 : 
     434              13 :         for(unsigned int i = 0; i < paramlist.size(); ++i)
     435                 :         {
     436               7 :             paramvalues.push_back( paramlist[i]->evaluate(st) );
     437                 :         }
     438                 : 
     439               6 :         return st.processFunction(funcname, paramvalues);
     440                 :     }
     441                 : 
     442                 :     /// Returns false, because value isn't constant.
     443               6 :     virtual bool evaluate_const(AnyScalar *) const
     444                 :     {
     445               6 :         return false;
     446                 :     }
     447                 : 
     448                 :     /// Nothing but the function and its parameters
     449              12 :     virtual std::string toString() const
     450                 :     {
     451              12 :         std::string str = funcname + "(";
     452              26 :         for(unsigned int i = 0; i < paramlist.size(); ++i)
     453                 :         {
     454              14 :             if (i != 0) str += ",";
     455              14 :             str += paramlist[i]->toString();
     456                 :         }
     457              12 :         return str + ")";
     458                 :     }
     459                 : };
     460                 : 
     461                 : /// Parse tree node representing an unary operator: '+', '-', '!' or
     462                 : /// "not". This node has one child.
     463                 : class PNUnaryArithmExpr : public ParseNode
     464                 : {
     465                 : private:
     466                 :     /// Pointer to the single operand
     467                 :     const ParseNode     *operand;
     468                 : 
     469                 :     /// Arithmetic operation to perform: either '+', '-' or '!'. Further
     470                 :     /// optimization would be to create an extra class for each op
     471                 :     char        op;
     472                 : 
     473                 : public:
     474                 :     /// Constructor from the parser: operand subnode and operator id.
     475               8 :     PNUnaryArithmExpr(const ParseNode* _operand, char _op)
     476               8 :         : ParseNode(), operand(_operand), op(_op)
     477                 :     {
     478               8 :         if (op == 'n' || op == 'N') op = '!';
     479               8 :     }
     480                 : 
     481                 :     /// Recursively delete the parse tree.
     482               8 :     virtual ~PNUnaryArithmExpr()
     483               8 :     {
     484               8 :         delete operand;
     485               8 :     }
     486                 : 
     487                 :     /// Applies the operator to the recursively calculated value.
     488               1 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     489                 :     {
     490               1 :         AnyScalar dest = operand->evaluate(st);
     491                 : 
     492               1 :         if (op == '-') {
     493               1 :             dest = -dest;           
     494                 :         }
     495               0 :         else if (op == '!')
     496                 :         {
     497                 :             // This should not happend, as types are constant in the parse tree
     498               0 :             if (dest.getType() != AnyScalar::ATTRTYPE_BOOL)
     499               0 :                 throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
     500                 : 
     501               0 :             dest = -dest;
     502                 :         }
     503                 :         else {
     504               0 :             assert(op == '+');
     505                 :         }
     506                 : 
     507               0 :         return dest;
     508                 :     }
     509                 : 
     510                 :     /// Calculates subnodes and returns result if the operator can be applied.
     511               8 :     virtual bool evaluate_const(AnyScalar *dest) const
     512                 :     {
     513               8 :         if (!dest) return false;
     514                 : 
     515               6 :         bool b = operand->evaluate_const(dest);
     516                 : 
     517               6 :         if (op == '-') {
     518               4 :             *dest = -(*dest);
     519                 :         }
     520               2 :         else if (op == '!')
     521                 :         {
     522               2 :             if (dest->getType() != AnyScalar::ATTRTYPE_BOOL)
     523               0 :                 throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
     524                 : 
     525               2 :             *dest = -(*dest);
     526                 :         }
     527                 :         else {
     528               0 :             assert(op == '+');
     529                 :         }
     530                 :         
     531               6 :         return b;
     532                 :     }
     533                 : 
     534                 :     /// Return the subnode's string with this operator prepended.
     535               2 :     virtual std::string toString() const
     536                 :     {
     537               2 :         return std::string("(") + op + " " + operand->toString() + ")";
     538                 :     }
     539                 : };
     540                 : 
     541                 : /// Parse tree node representing a binary operators: +, -, * and / for numeric
     542                 : /// values. This node has two children.
     543                 : class PNBinaryArithmExpr : public ParseNode
     544                 : {
     545                 : private:
     546                 :     /// Pointers to the left of the two child parse trees.
     547                 :     const ParseNode     *left;
     548                 : 
     549                 :     /// Pointers to the right of the two child parse trees.
     550                 :     const ParseNode     *right;
     551                 : 
     552                 :     /// Arithmetic operation to perform: left op right.
     553                 :     /// Further optimization would be to create an extra class for each op
     554                 :     char        op;
     555                 : 
     556                 : public:
     557                 :     /// Constructor from the parser: both operand subnodes and the operator id.
     558                 :     PNBinaryArithmExpr(const ParseNode* _left,
     559                 :                        const ParseNode* _right,
     560              28 :                        char _op)
     561                 :         : ParseNode(),
     562              28 :           left(_left), right(_right), op(_op)
     563              28 :     { }
     564                 : 
     565                 :     /// Recursively delete parse tree.
     566              28 :     virtual ~PNBinaryArithmExpr()
     567              28 :     {
     568              28 :         delete left;
     569              28 :         delete right;
     570              28 :     }
     571                 : 
     572                 :     /// Applies the operator to the two recursive calculated values. The actual
     573                 :     /// switching between types is handled by AnyScalar's operators.
     574               8 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     575                 :     {
     576               8 :         AnyScalar vl = left->evaluate(st);
     577               8 :         AnyScalar vr = right->evaluate(st);
     578                 : 
     579               5 :         if (op == '+') {
     580               3 :             return (vl + vr);
     581                 :         }
     582               2 :         else if (op == '-') {
     583               0 :             return (vl - vr);
     584                 :         }
     585               2 :         else if (op == '*') {
     586               1 :             return (vl * vr);
     587                 :         }
     588               1 :         else if (op == '/') {
     589               1 :             return (vl / vr);
     590                 :         }
     591                 : 
     592               0 :         assert(0);
     593               0 :         return 0;
     594                 :     }
     595                 : 
     596                 :     /// Returns false because this node isn't always constant. Tries to
     597                 :     /// calculate a constant subtree's value.
     598              20 :     virtual bool evaluate_const(AnyScalar *dest) const
     599                 :     {
     600              20 :         if (!dest) return false;
     601                 : 
     602              12 :         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
     603                 :         
     604              12 :         bool bl = left->evaluate_const(&vl);
     605              12 :         bool br = right->evaluate_const(&vr);
     606                 : 
     607              12 :         if (op == '+') {
     608               7 :             *dest = vl + vr;
     609                 :         }
     610               5 :         else if (op == '-') {
     611               1 :             *dest = vl - vr;
     612                 :         }
     613               4 :         else if (op == '*') {
     614               4 :             *dest = vl * vr;
     615                 :         }
     616               0 :         else if (op == '/') {
     617               0 :             *dest = vl / vr;
     618                 :         }
     619                 : 
     620              12 :         return (bl && br);
     621                 :     }
     622                 : 
     623                 :     /// String representing (operandA op operandB)
     624              16 :     virtual std::string toString() const
     625                 :     {
     626              16 :         return std::string("(") + left->toString() + " " + op + " " + right->toString() + ")";
     627                 :     }
     628                 : };
     629                 : 
     630                 : /// Parse tree node handling type conversions within the tree.
     631                 : class PNCastExpr : public ParseNode
     632                 : {
     633                 : private:
     634                 :     /// Child tree of which the return value should be casted.
     635                 :     const ParseNode*    operand;
     636                 : 
     637                 :     /// AnyScalar type to cast the value to.
     638                 :     AnyScalar::attrtype_t       type;
     639                 : 
     640                 : public:
     641                 :     /// Constructor from the parser: operand subnode and the cast type as
     642                 :     /// recognized by AnyScalar.
     643               4 :     PNCastExpr(const ParseNode* _operand, AnyScalar::attrtype_t _type)
     644                 :         : ParseNode(),
     645               4 :           operand(_operand), type(_type)
     646               4 :     { }
     647                 : 
     648                 :     /// Recursively delete parse tree.
     649               4 :     virtual ~PNCastExpr()
     650               4 :     {
     651               4 :         delete operand;
     652               4 :     }
     653                 : 
     654                 :     /// Recursive calculation of the value and subsequent casting via
     655                 :     /// AnyScalar's convertType method.
     656               1 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     657                 :     {
     658               1 :         AnyScalar val = operand->evaluate(st);
     659               1 :         val.convertType(type);
     660               0 :         return val;
     661                 :     }
     662                 : 
     663                 :     /// Returns false because this node isn't always constant.
     664               2 :     virtual bool evaluate_const(AnyScalar *dest) const
     665                 :     {
     666               2 :         if (!dest) return false;
     667                 : 
     668               2 :         bool b = operand->evaluate_const(dest);
     669               2 :         dest->convertType(type);
     670               2 :         return b;
     671                 :     }
     672                 : 
     673                 :     /// c-like representation of the cast
     674               2 :     virtual std::string toString() const
     675                 :     {
     676               2 :         return std::string("((") + AnyScalar::getTypeString(type) + ")" + operand->toString() + ")";
     677                 :     }
     678                 : };
     679                 : 
     680                 : /// Parse tree node representing a binary comparison operator: ==, =, !=, <, >,
     681                 : /// >=, <=, =>, =<. This node has two children.
     682                 : class PNBinaryComparisonExpr : public ParseNode
     683                 : {
     684                 : private:
     685                 :     /// Pointers to the left of the two child parse trees.
     686                 :     const ParseNode     *left;
     687                 : 
     688                 :     /// Pointers to the right of the two child parse trees.
     689                 :     const ParseNode     *right;
     690                 : 
     691                 :     /// Comparison operation to perform: left op right
     692                 :     enum { EQUAL, NOTEQUAL, LESS, GREATER, LESSEQUAL, GREATEREQUAL } op;
     693                 : 
     694                 :     /// String saved for toString()
     695                 :     std::string         opstr;
     696                 : 
     697                 : public:
     698                 :     /// Constructor from the parser: both operand subnodes and the operator id.
     699                 :     PNBinaryComparisonExpr(const ParseNode* _left,
     700                 :                            const ParseNode* _right,
     701              17 :                            std::string _op)
     702                 :         : ParseNode(),
     703              17 :           left(_left), right(_right), opstr(_op)
     704                 :     {
     705              17 :         if (_op == "==" || _op == "=")
     706               7 :             op = EQUAL;
     707              10 :         else if (_op == "!=")
     708               1 :             op = NOTEQUAL;
     709               9 :         else if (_op == "<")
     710               1 :             op = LESS;
     711               8 :         else if (_op == ">")
     712               2 :             op = GREATER;
     713               6 :         else if (_op == "<=" || _op == "=<")
     714               3 :             op = LESSEQUAL;
     715               3 :         else if (_op == ">=" || _op == "=>")
     716               3 :             op = GREATEREQUAL;
     717                 :         else
     718               0 :             throw(BadSyntaxException("Program Error: invalid binary comparision operator."));
     719              17 :     }
     720                 : 
     721                 :     /// Recursively delete parse tree.
     722              17 :     virtual ~PNBinaryComparisonExpr()
     723              17 :     {
     724              17 :         delete left;
     725              17 :         delete right;
     726              17 :     }
     727                 : 
     728                 :     /// Applies the operator to the two recursive calculated values. The actual
     729                 :     /// switching between types is handled by AnyScalar's operators. This
     730                 :     /// result type of this processing node is always bool.
     731               2 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     732                 :     {
     733               2 :         AnyScalar vl = left->evaluate(st);
     734               2 :         AnyScalar vr = right->evaluate(st);
     735                 : 
     736               2 :         AnyScalar dest(AnyScalar::ATTRTYPE_BOOL);
     737                 : 
     738               2 :         switch(op)
     739                 :         {
     740                 :         case EQUAL:
     741               2 :             dest = AnyScalar( vl.equal_to(vr) );
     742               2 :             break;
     743                 : 
     744                 :         case NOTEQUAL:
     745               0 :             dest = AnyScalar( vl.not_equal_to(vr) );
     746               0 :             break;
     747                 : 
     748                 :         case LESS:
     749               0 :             dest = AnyScalar( vl.less(vr) );
     750               0 :             break;
     751                 : 
     752                 :         case GREATER:
     753               0 :             dest = AnyScalar( vl.greater(vr) );
     754               0 :             break;
     755                 : 
     756                 :         case LESSEQUAL:
     757               0 :             dest = AnyScalar( vl.less_equal(vr) );
     758               0 :             break;
     759                 : 
     760                 :         case GREATEREQUAL:
     761               0 :             dest = AnyScalar( vl.greater_equal(vr) );
     762               0 :             break;
     763                 : 
     764                 :         default:
     765               0 :             assert(0);
     766                 :         }
     767                 : 
     768               2 :         return dest;
     769                 :     }
     770                 : 
     771                 :     /// Returns false because this node isn't always constant.
     772              13 :     virtual bool evaluate_const(AnyScalar *dest) const
     773                 :     {
     774              13 :         if (!dest) return false;
     775                 : 
     776              13 :         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
     777                 :         
     778              13 :         bool bl = left->evaluate_const(&vl);
     779              13 :         bool br = right->evaluate_const(&vr);
     780                 : 
     781              13 :         switch(op)
     782                 :         {
     783                 :         case EQUAL:
     784               3 :             *dest = AnyScalar( vl.equal_to(vr) );
     785               3 :             break;
     786                 : 
     787                 :         case NOTEQUAL:
     788               1 :             *dest = AnyScalar( vl.not_equal_to(vr) );
     789               1 :             break;
     790                 : 
     791                 :         case LESS:
     792               1 :             *dest = AnyScalar( vl.less(vr) );
     793               1 :             break;
     794                 : 
     795                 :         case GREATER:
     796               2 :             *dest = AnyScalar( vl.greater(vr) );
     797               2 :             break;
     798                 : 
     799                 :         case LESSEQUAL:
     800               3 :             *dest = AnyScalar( vl.less_equal(vr) );
     801               3 :             break;
     802                 : 
     803                 :         case GREATEREQUAL:
     804               3 :             *dest = AnyScalar( vl.greater_equal(vr) );
     805               3 :             break;
     806                 : 
     807                 :         default:
     808               0 :             assert(0);
     809                 :         }
     810                 : 
     811              13 :         return (bl && br);
     812                 :     }
     813                 : 
     814                 :     /// String (operandA op operandB)
     815               4 :     virtual std::string toString() const
     816                 :     {
     817               4 :         return std::string("(") + left->toString() + " " + opstr + " " + right->toString() + ")";
     818                 :     }
     819                 : };
     820                 : 
     821                 : /// Parse tree node representing a binary logic operator: and, or, &&, ||. This
     822                 : /// node has two children.
     823                 : class PNBinaryLogicExpr : public ParseNode
     824                 : {
     825                 : private:
     826                 :     /// Pointers to the left of the two child parse trees.
     827                 :     ParseNode*          left;
     828                 : 
     829                 :     /// Pointers to the right of the two child parse trees.
     830                 :     ParseNode*          right;
     831                 : 
     832                 :     /// Comparison operation to perform: left op right
     833                 :     enum { OP_AND, OP_OR } op;
     834                 : 
     835                 : public:
     836                 :     /// Constructor from the parser: both operand subnodes and the operator id.
     837                 :     PNBinaryLogicExpr(ParseNode* _left,
     838                 :                       ParseNode* _right,
     839              13 :                       std::string _op)
     840                 :         : ParseNode(),
     841              13 :           left(_left), right(_right)
     842                 :     {
     843              13 :         if (_op == "and" || _op == "&&")
     844              10 :             op = OP_AND;
     845               3 :         else if (_op == "or" || _op == "||")
     846               3 :             op = OP_OR;
     847                 :         else
     848               0 :             throw(BadSyntaxException("Program Error: invalid binary logic operator."));
     849              13 :     }
     850                 : 
     851                 :     /// Recursively delete parse tree.
     852              13 :     virtual ~PNBinaryLogicExpr()
     853              13 :     {
     854              13 :         if (left) delete left;
     855              13 :         if (right) delete right;
     856              13 :     }
     857                 : 
     858                 :     /// Calculate the operator
     859              13 :     inline bool do_operator(bool left, bool right) const
     860                 :     {
     861              13 :         if (op == OP_AND)
     862              10 :             return left && right;
     863               3 :         else if (op == OP_OR)
     864               3 :             return left || right;
     865                 :         else
     866               0 :             return false;
     867                 :     }
     868                 : 
     869                 :     /// Return the string of this operator
     870               0 :     inline std::string get_opstr() const
     871                 :     {
     872               0 :         return (op == OP_AND) ? "&&" : "||";
     873                 :     }
     874                 : 
     875                 :     /// Applies the operator to the two recursive calculated values. The actual
     876                 :     /// switching between types is handled by AnyScalar's operators.
     877               0 :     virtual AnyScalar evaluate(const class SymbolTable &st) const
     878                 :     {
     879               0 :         AnyScalar vl = left->evaluate(st);
     880               0 :         AnyScalar vr = right->evaluate(st);
     881                 : 
     882                 :         // these should never happen.
     883               0 :         if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
     884               0 :             throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
     885               0 :         if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
     886               0 :             throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
     887                 : 
     888               0 :         int bvl = vl.getInteger();
     889               0 :         int bvr = vr.getInteger();
     890                 : 
     891               0 :         return AnyScalar( do_operator(bvl, bvr) );
     892                 :     }
     893                 : 
     894                 :     /// Applies the operator to the two recursive calculated const
     895                 :     /// values. Determining if this node is constant is somewhat more tricky
     896                 :     /// than with the other parse nodes: AND with a false operand is always
     897                 :     /// false. OR with a true operand is always true.
     898              13 :     virtual bool evaluate_const(AnyScalar *dest) const
     899                 :     {
     900              13 :         if (!dest) return false; // returns false because this node isn't always constant
     901                 : 
     902              13 :         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
     903                 :         
     904              13 :         bool bl = left->evaluate_const(&vl);
     905              13 :         bool br = right->evaluate_const(&vr);
     906                 : 
     907              13 :         if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
     908               0 :             throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
     909              13 :         if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
     910               0 :             throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
     911                 : 
     912              13 :         int bvl = vl.getInteger();
     913              13 :         int bvr = vr.getInteger();
     914                 : 
     915              13 :         *dest = AnyScalar( do_operator(bvl, bvr) );
     916                 : 
     917              13 :         if (op == OP_AND)
     918                 :         {
     919                 :             // true if either both ops are themselves constant, or if either of
     920                 :             // the ops are constant and evaluates to false.
     921              23 :             return (bl && br) || (bl && !bvl) || (br && !bvr);
     922                 :         }
     923               3 :         else if (op == OP_OR)
     924                 :         {
     925                 :             // true if either both ops are themselves constant, or if either of
     926                 :             // the ops is constant and evaluates to true.
     927               3 :             return (bl && br) || (bl && bvl) || (br && bvr);
     928                 :         }
     929                 :         else {
     930               0 :             assert(0);
     931                 :             return false;
     932               0 :         }
     933                 :     }
     934                 : 
     935                 :     /// String (operandA op operandB)
     936               0 :     virtual std::string toString() const
     937                 :     {
     938               0 :         return std::string("(") + left->toString() + " " + get_opstr() + " " + right->toString() + ")";
     939                 :     }
     940                 : 
     941                 :     /// Detach left node
     942               0 :     inline ParseNode* detach_left()
     943                 :     {
     944               0 :         ParseNode *n = left;
     945               0 :         left = NULL;
     946               0 :         return n;
     947                 :     }
     948                 : 
     949                 :     /// Detach right node
     950               0 :     inline ParseNode* detach_right()
     951                 :     {
     952               0 :         ParseNode *n = right;
     953               0 :         right = NULL;
     954               0 :         return n;
     955                 :     }
     956                 : };
     957                 : 
     958                 : // *** Functions which translate the resulting parse tree into our expression
     959                 : // *** tree, simultaneously folding constants.
     960                 : 
     961                 : /// Iterator type used by spirit's parsers.
     962                 : typedef std::string::const_iterator InputIterT;
     963                 : 
     964                 : /// Resulting match tree after parsing
     965                 : typedef tree_match<InputIterT> ParseTreeMatchT;
     966                 : 
     967                 : /// The iterator of the match tree used in build_expr()
     968                 : typedef ParseTreeMatchT::const_tree_iterator TreeIterT;
     969                 : 
     970                 : /// Build_expr is the constructor method to create a parse tree from the
     971                 : /// AST-tree returned by the spirit parser.
     972             176 : static ParseNode* build_expr(TreeIterT const& i)
     973                 : {
     974                 : #ifdef STX_DEBUG_PARSER
     975                 :     std::cout << "In build_expr. i->value = " <<
     976                 :         std::string(i->value.begin(), i->value.end()) <<
     977                 :         " i->children.size() = " << i->children.size() << 
     978                 :         " i->value.id = " << i->value.id().to_long() << std::endl;
     979                 : #endif
     980                 : 
     981             176 :     switch(i->value.id().to_long())
     982                 :     {
     983                 :     // *** Constant node cases
     984                 : 
     985                 :     case boolean_const_id:
     986                 :     {
     987                 :         return new PNConstant(AnyScalar::ATTRTYPE_BOOL,
     988               7 :                               std::string(i->value.begin(), i->value.end()));
     989                 :     }
     990                 : 
     991                 :     case integer_const_id:
     992                 :     {
     993                 :         return new PNConstant(AnyScalar::ATTRTYPE_INTEGER,
     994              63 :                               std::string(i->value.begin(), i->value.end()));
     995                 :     }
     996                 : 
     997                 :     case long_const_id:
     998                 :     {
     999                 :         return new PNConstant(AnyScalar::ATTRTYPE_LONG,
    1000               0 :                               std::string(i->value.begin(), i->value.end()));
    1001                 :     }
    1002                 : 
    1003                 :     case double_const_id:
    1004                 :     {
    1005                 :         return new PNConstant(AnyScalar::ATTRTYPE_DOUBLE,
    1006              10 :                               std::string(i->value.begin(), i->value.end()));
    1007                 :     }
    1008                 : 
    1009                 :     case string_const_id:
    1010                 :     {
    1011                 :         return new PNConstant(AnyScalar::ATTRTYPE_STRING,
    1012               6 :                               std::string(i->value.begin(), i->value.end()));
    1013                 :     }
    1014                 : 
    1015                 :     // *** Arithmetic node cases
    1016                 : 
    1017                 :     case unary_expr_id:
    1018                 :     {
    1019               8 :         char arithop = *i->value.begin();
    1020               8 :         assert(i->children.size() == 1);
    1021                 : 
    1022               8 :         const ParseNode *val = build_expr(i->children.begin());
    1023                 : 
    1024               8 :         if (val->evaluate_const(NULL))
    1025                 :         {
    1026                 :             // construct a constant node
    1027               6 :             PNUnaryArithmExpr tmpnode(val, arithop);
    1028               6 :             AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
    1029                 : 
    1030               6 :             tmpnode.evaluate_const(&constval);
    1031                 : 
    1032               6 :             return new PNConstant(constval);
    1033                 :         }
    1034                 :         else
    1035                 :         {
    1036                 :             // calculation node
    1037               2 :             return new PNUnaryArithmExpr(val, arithop);
    1038                 :         }
    1039                 :     }
    1040                 : 
    1041                 :     case add_expr_id:
    1042                 :     case mul_expr_id:
    1043                 :     {
    1044              28 :         char arithop = *i->value.begin();
    1045              28 :         assert(i->children.size() == 2);
    1046                 : 
    1047                 :         // auto_ptr needed because of possible parse exceptions in build_expr.
    1048                 : 
    1049              28 :         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
    1050              28 :         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
    1051                 : 
    1052              28 :         if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
    1053                 :         {
    1054                 :             // construct a constant node
    1055              12 :             PNBinaryArithmExpr tmpnode(left.release(), right.release(), arithop);
    1056              12 :             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
    1057                 : 
    1058              12 :             tmpnode.evaluate_const(&both);
    1059                 : 
    1060                 :             // left and right are deleted by tmpnode's deconstructor
    1061                 : 
    1062              40 :             return new PNConstant(both);
    1063                 :         }
    1064                 :         else
    1065                 :         {
    1066                 :             // calculation node
    1067              16 :             return new PNBinaryArithmExpr(left.release(), right.release(), arithop);
    1068               0 :         }
    1069                 :     }
    1070                 : 
    1071                 :     // *** Cast node case
    1072                 : 
    1073                 :     case cast_spec_id:
    1074                 :     {
    1075               4 :         assert(i->children.size() == 1);
    1076                 : 
    1077               4 :         std::string tname(i->value.begin(), i->value.end());
    1078               8 :         AnyScalar::attrtype_t at = AnyScalar::stringToType(tname);
    1079                 :         
    1080               4 :         const ParseNode *val = build_expr(i->children.begin());
    1081                 : 
    1082               4 :         if (val->evaluate_const(NULL))
    1083                 :         {
    1084                 :             // construct a constant node
    1085               2 :             PNCastExpr tmpnode(val, at);
    1086                 : 
    1087               2 :             AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
    1088                 : 
    1089               2 :             tmpnode.evaluate_const(&constval);
    1090                 : 
    1091               6 :             return new PNConstant(constval);
    1092                 :         }
    1093                 :         else
    1094                 :         {
    1095               2 :             return new PNCastExpr(val, at);
    1096               0 :         }
    1097                 :     }
    1098                 : 
    1099                 :     // *** Binary Comparison Operator
    1100                 : 
    1101                 :     case comp_expr_id:
    1102                 :     {
    1103              17 :         assert(i->children.size() == 2);
    1104                 : 
    1105              17 :         std::string arithop(i->value.begin(), i->value.end());
    1106                 : 
    1107                 :         // we need auto_ptr because of possible parse exceptions in build_expr.
    1108                 : 
    1109              34 :         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
    1110              17 :         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
    1111                 : 
    1112              17 :         if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
    1113                 :         {
    1114                 :             // construct a constant node
    1115              13 :             PNBinaryComparisonExpr tmpnode(left.release(), right.release(), arithop);
    1116              13 :             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
    1117                 : 
    1118              13 :             tmpnode.evaluate_const(&both);
    1119                 : 
    1120                 :             // left and right are deleted by tmpnode's deconstructor
    1121                 : 
    1122              30 :             return new PNConstant(both);
    1123                 :         }
    1124                 :         else
    1125                 :         {
    1126                 :             // calculation node
    1127               4 :             return new PNBinaryComparisonExpr(left.release(), right.release(), arithop);
    1128               0 :         }
    1129                 :     }
    1130                 : 
    1131                 :     // *** Binary Logic Operator
    1132                 : 
    1133                 :     case and_expr_id:
    1134                 :     case or_expr_id:
    1135                 :     {
    1136              13 :         assert(i->children.size() == 2);
    1137                 : 
    1138              13 :         std::string logicop(i->value.begin(), i->value.end());
    1139              26 :         std::transform(logicop.begin(), logicop.end(), logicop.begin(), tolower);
    1140                 : 
    1141                 :         // auto_ptr needed because of possible parse exceptions in build_expr.
    1142                 : 
    1143              13 :         std::auto_ptr<ParseNode> left( build_expr(i->children.begin()) );
    1144              13 :         std::auto_ptr<ParseNode> right( build_expr(i->children.begin()+1) );
    1145                 : 
    1146              13 :         bool constleft = left->evaluate_const(NULL);
    1147              13 :         bool constright = right->evaluate_const(NULL);
    1148                 : 
    1149                 :         // a logical node is constant if one of the two ops is constant. so we
    1150                 :         // construct a calculation node and check later.
    1151              13 :         std::auto_ptr<PNBinaryLogicExpr> node( new PNBinaryLogicExpr(left.release(), right.release(), logicop) );
    1152                 : 
    1153              13 :         if (constleft || constright)
    1154                 :         {
    1155              13 :             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
    1156                 : 
    1157                 :             // test if the node is really const.
    1158              13 :             if (node->evaluate_const(&both))
    1159                 :             {
    1160                 :                 // return a constant node instead, node will be deleted by
    1161                 :                 // auto_ptr, left,right by node's destructor.
    1162              26 :                 return new PNConstant(both);
    1163               0 :             }
    1164                 :         }
    1165               0 :         if (constleft)
    1166                 :         {
    1167                 :             // left node is constant, but the evaluation is not
    1168                 :             // -> only right node is meaningful.
    1169               0 :             return node->detach_right();
    1170                 :         }
    1171               0 :         if (constright)
    1172                 :         {
    1173                 :             // right node is constant, but the evaluation is not
    1174                 :             // -> only left node is meaningful.
    1175               0 :             return node->detach_left();
    1176                 :         }
    1177                 : 
    1178               0 :         return node.release();
    1179                 :     }
    1180                 : 
    1181                 :     // *** Variable and Function name place-holder
    1182                 : 
    1183                 :     case varname_id:
    1184                 :     {
    1185               8 :         assert(i->children.size() == 0);
    1186                 : 
    1187               8 :         std::string varname(i->value.begin(), i->value.end());
    1188                 : 
    1189              16 :         return new PNVariable(varname);
    1190                 :     }
    1191                 : 
    1192                 :     case function_identifier_id:
    1193                 :     {
    1194              12 :         std::string funcname(i->value.begin(), i->value.end());
    1195              24 :         std::vector<const class ParseNode*> paramlist;
    1196                 : 
    1197              24 :         if (i->children.size() > 0)
    1198                 :         {
    1199              10 :             TreeIterT const& paramlistchild = i->children.begin();
    1200                 : 
    1201              10 :             if (paramlistchild->value.id().to_long() == exprlist_id)
    1202                 :             {
    1203                 :                 try
    1204                 :                 {
    1205              12 :                     for(TreeIterT ci = paramlistchild->children.begin(); ci != paramlistchild->children.end(); ++ci)
    1206                 :                     {
    1207               8 :                         const ParseNode *pas = build_expr(ci);
    1208               8 :                         paramlist.push_back(pas);
    1209                 :                     }
    1210                 :                 }
    1211               0 :                 catch (...) // need to clean-up
    1212                 :                 {
    1213               0 :                     for(unsigned int i = 0; i < paramlist.size(); ++i)
    1214               0 :                         delete paramlist[i];
    1215               0 :                     throw;
    1216                 :                 }
    1217                 :             }
    1218                 :             else
    1219                 :             {
    1220                 :                 // just one subnode and its not a full expression list
    1221               6 :                 paramlist.push_back( build_expr(paramlistchild) );
    1222                 :             }
    1223                 :         }
    1224                 : 
    1225              12 :         return new PNFunction(funcname, paramlist);
    1226                 :     }
    1227                 : 
    1228                 :     default:
    1229               0 :         throw(ExpressionParserException("Unknown AST parse tree node found. This should never happen."));
    1230                 :     }
    1231                 : }
    1232                 : 
    1233                 : /// build_exprlist constructs the vector holding the ParseNode parse tree for
    1234                 : /// each parse tree.
    1235               0 : ParseTreeList build_exprlist(TreeIterT const &i)
    1236                 : {
    1237                 : #ifdef STX_DEBUG_PARSER
    1238                 :     std::cout << "In build_exprlist. i->value = " <<
    1239                 :         std::string(i->value.begin(), i->value.end()) <<
    1240                 :         " i->children.size() = " << i->children.size() << 
    1241                 :         " i->value.id = " << i->value.id().to_long() << std::endl;
    1242                 : #endif
    1243                 : 
    1244               0 :     ParseTreeList ptlist;
    1245                 : 
    1246               0 :     for(TreeIterT ci = i->children.begin(); ci != i->children.end(); ++ci)
    1247                 :     {
    1248               0 :         ParseNode *vas = build_expr(ci);
    1249                 : 
    1250               0 :         ptlist.push_back( ParseTree(vas) );
    1251                 :     }
    1252                 : 
    1253               0 :     return ptlist;
    1254                 : }
    1255                 : 
    1256                 : /// Uses boost::spirit function to convert the parse tree into a XML document.
    1257               1 : static inline void tree_dump_xml(std::ostream &os, const std::string &input, const tree_parse_info<InputIterT> &info)
    1258                 : {
    1259                 :     // map used by the xml dumper to label the nodes
    1260                 : 
    1261               1 :     std::map<parser_id, std::string> rule_names;
    1262                 : 
    1263               1 :     rule_names[boolean_const_id] = "boolean_const";
    1264               1 :     rule_names[integer_const_id] = "integer_const";
    1265               1 :     rule_names[long_const_id] = "long_const";
    1266               1 :     rule_names[double_const_id] = "double_const";
    1267               1 :     rule_names[string_const_id] = "string_const";
    1268               1 :     rule_names[constant_id] = "constant";
    1269                 : 
    1270               1 :     rule_names[function_call_id] = "function_call";
    1271               1 :     rule_names[function_identifier_id] = "function_identifier";
    1272                 : 
    1273               1 :     rule_names[varname_id] = "varname";
    1274                 : 
    1275               1 :     rule_names[unary_expr_id] = "unary_expr";
    1276               1 :     rule_names[mul_expr_id] = "mul_expr";
    1277               1 :     rule_names[add_expr_id] = "add_expr";
    1278                 : 
    1279               1 :     rule_names[cast_expr_id] = "cast_expr";
    1280               1 :     rule_names[cast_spec_id] = "cast_spec";
    1281                 : 
    1282               1 :     rule_names[comp_expr_id] = "comp_expr";
    1283               1 :     rule_names[and_expr_id] = "and_expr";
    1284               1 :     rule_names[or_expr_id] = "or_expr";
    1285                 : 
    1286               1 :     rule_names[expr_id] = "expr";
    1287               1 :     rule_names[exprlist_id] = "exprlist";
    1288                 : 
    1289               1 :     tree_to_xml(os, info.trees, input.c_str(), rule_names);
    1290               1 : }
    1291                 : 
    1292                 : } // namespace Grammar
    1293                 : 
    1294              35 : const ParseTree parseExpression(const std::string &input)
    1295                 : {
    1296                 :     // instance of the grammar
    1297              35 :     Grammar::ExpressionGrammar g;
    1298                 : 
    1299                 : #ifdef STX_DEBUG_PARSER
    1300                 :     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
    1301                 : #endif
    1302                 : 
    1303                 :     Grammar::tree_parse_info<Grammar::InputIterT> info =
    1304                 :         boost::spirit::ast_parse(input.begin(), input.end(),
    1305                 :                                  g.use_parser<0>(),       // use first entry point: expr
    1306              35 :                                  boost::spirit::space_p);
    1307                 : 
    1308              35 :     if (!info.full)
    1309                 :     {
    1310               1 :         std::ostringstream oss;
    1311                 :         oss << "Syntax error at position "
    1312                 :             << static_cast<int>(info.stop - input.begin())
    1313                 :             << " near " 
    1314               1 :             << std::string(info.stop, input.end());
    1315                 : 
    1316               2 :         throw(BadSyntaxException(oss.str()));
    1317                 :     }
    1318                 : 
    1319              34 :     return ParseTree( Grammar::build_expr(info.trees.begin()) );
    1320                 : }
    1321                 : 
    1322               1 : std::string parseExpressionXML(const std::string &input)
    1323                 : {
    1324                 :     // instance of the grammar
    1325               1 :     Grammar::ExpressionGrammar g;
    1326                 : 
    1327                 : #ifdef STX_DEBUG_PARSER
    1328                 :     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
    1329                 : #endif
    1330                 : 
    1331                 :     Grammar::tree_parse_info<Grammar::InputIterT> info =
    1332                 :         boost::spirit::ast_parse(input.begin(), input.end(),
    1333                 :                                  g.use_parser<0>(),       // use first entry point: expr
    1334               1 :                                  boost::spirit::space_p);
    1335                 : 
    1336               1 :     if (!info.full)
    1337                 :     {
    1338               0 :         std::ostringstream oss;
    1339                 :         oss << "Syntax error at position "
    1340                 :             << static_cast<int>(info.stop - input.begin())
    1341                 :             << " near " 
    1342               0 :             << std::string(info.stop, input.end());
    1343                 : 
    1344               0 :         throw(BadSyntaxException(oss.str()));
    1345                 :     }
    1346                 : 
    1347               1 :     std::ostringstream oss;
    1348               1 :     Grammar::tree_dump_xml(oss, input, info);
    1349               1 :     return oss.str();
    1350                 : }
    1351                 : 
    1352               0 : ParseTreeList parseExpressionList(const std::string &input)
    1353                 : {
    1354                 :     // instance of the grammar
    1355               0 :     Grammar::ExpressionGrammar g;
    1356                 : 
    1357                 : #ifdef STX_DEBUG_PARSER
    1358                 :     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
    1359                 : #endif
    1360                 : 
    1361                 :     Grammar::tree_parse_info<Grammar::InputIterT> info =
    1362                 :         boost::spirit::ast_parse(input.begin(), input.end(),
    1363                 :                                  g.use_parser<1>(),       // use second entry point: exprlist
    1364               0 :                                  boost::spirit::space_p);
    1365                 : 
    1366               0 :     if (!info.full)
    1367                 :     {
    1368               0 :         std::ostringstream oss;
    1369                 :         oss << "Syntax error at position "
    1370                 :             << static_cast<int>(info.stop - input.begin())
    1371                 :             << " near " 
    1372               0 :             << std::string(info.stop, input.end());
    1373                 : 
    1374               0 :         throw(BadSyntaxException(oss.str()));
    1375                 :     }
    1376                 : 
    1377               0 :     return Grammar::build_exprlist(info.trees.begin());
    1378                 : }
    1379                 : 
    1380               0 : std::vector<AnyScalar> ParseTreeList::evaluate(const class SymbolTable &st) const
    1381                 : {
    1382               0 :     std::vector<AnyScalar> vl;
    1383                 : 
    1384               0 :     for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
    1385                 :     {
    1386               0 :         vl.push_back( i->evaluate(st) );
    1387                 :     }
    1388                 : 
    1389               0 :     return vl;
    1390                 : }
    1391                 : 
    1392               0 : std::string ParseTreeList::toString() const
    1393                 : {
    1394               0 :     std::string sl;
    1395                 : 
    1396               0 :     for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
    1397                 :     {
    1398               0 :         if (i != parent_type::begin()) {
    1399               0 :             sl += ", ";
    1400                 :         }
    1401                 : 
    1402               0 :         sl += i->toString();
    1403                 :     }
    1404                 : 
    1405               0 :     return sl;
    1406                 : }
    1407                 : 
    1408                 : /// *** SymbolTable, EmptySymbolTable and BasicSymbolTable implementation
    1409                 : 
    1410              17 : SymbolTable::~SymbolTable()
    1411                 : {
    1412              17 : }
    1413                 : 
    1414               0 : EmptySymbolTable::~EmptySymbolTable()
    1415                 : {
    1416               0 : }
    1417                 : 
    1418               0 : AnyScalar EmptySymbolTable::lookupVariable(const std::string &varname) const
    1419                 : {
    1420               0 :     throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
    1421                 : }
    1422                 : 
    1423                 : AnyScalar EmptySymbolTable::processFunction(const std::string &funcname,
    1424               0 :                                             const paramlist_type &) const
    1425                 : {
    1426               0 :     throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
    1427                 : }
    1428                 : 
    1429              17 : BasicSymbolTable::BasicSymbolTable()
    1430                 : {
    1431              17 :     addStandardFunctions();
    1432              17 : }
    1433                 : 
    1434              17 : BasicSymbolTable::~BasicSymbolTable()
    1435                 : {
    1436              17 : }
    1437                 : 
    1438              34 : void BasicSymbolTable::setVariable(const std::string& varname, const AnyScalar &value)
    1439                 : {
    1440              34 :     std::string vn = varname;
    1441              34 :     std::transform(vn.begin(), vn.end(), vn.begin(), tolower);
    1442                 : 
    1443              34 :     variablemap[vn] = value;
    1444              34 : }
    1445                 : 
    1446             153 : void BasicSymbolTable::setFunction(const std::string& funcname, int arguments, functionptr_type funcptr)
    1447                 : {
    1448             153 :     std::string fn = funcname;
    1449             153 :     std::transform(fn.begin(), fn.end(), fn.begin(), toupper);
    1450                 : 
    1451             153 :     functionmap[fn] = FunctionInfo(arguments, funcptr);
    1452             153 : }
    1453                 : 
    1454               0 : void BasicSymbolTable::clearVariables()
    1455                 : {
    1456               0 :     variablemap.clear();
    1457               0 : }
    1458                 : 
    1459               0 : void BasicSymbolTable::clearFunctions()
    1460                 : {
    1461               0 :     functionmap.clear();
    1462               0 : }
    1463                 : 
    1464               0 : AnyScalar BasicSymbolTable::funcPI(const paramlist_type &)
    1465                 : {
    1466               0 :     return AnyScalar(3.14159265358979323846);
    1467                 : }
    1468                 : 
    1469               0 : AnyScalar BasicSymbolTable::funcSIN(const paramlist_type &paramlist)
    1470                 : {
    1471               0 :     return AnyScalar( std::sin(paramlist[0].getDouble()) );
    1472                 : }
    1473                 : 
    1474               0 : AnyScalar BasicSymbolTable::funcCOS(const paramlist_type &paramlist)
    1475                 : {
    1476               0 :     return AnyScalar( std::cos(paramlist[0].getDouble()) );
    1477                 : }
    1478                 : 
    1479               0 : AnyScalar BasicSymbolTable::funcTAN(const paramlist_type &paramlist)
    1480                 : {
    1481               0 :     return AnyScalar( std::tan(paramlist[0].getDouble()) );
    1482                 : }
    1483                 : 
    1484               0 : AnyScalar BasicSymbolTable::funcABS(const paramlist_type &paramlist)
    1485                 : {
    1486               0 :     if (paramlist[0].isIntegerType()) {
    1487               0 :         return AnyScalar( std::abs(paramlist[0].getInteger()) );
    1488                 :     }
    1489               0 :     else if (paramlist[0].isFloatingType()) {
    1490               0 :         return AnyScalar( std::fabs(paramlist[0].getDouble()) );
    1491                 :     }
    1492                 :     else {
    1493               0 :         throw(BadFunctionCallException("Function ABS() takes exactly one parameter"));
    1494                 :     }
    1495                 : }
    1496                 : 
    1497               1 : AnyScalar BasicSymbolTable::funcEXP(const paramlist_type &paramlist)
    1498                 : {
    1499               1 :     return AnyScalar( std::exp(paramlist[0].getDouble()) );
    1500                 : }
    1501                 : 
    1502               1 : AnyScalar BasicSymbolTable::funcLOGN(const paramlist_type &paramlist)
    1503                 : {
    1504               1 :     return AnyScalar( std::log(paramlist[0].getDouble()) );
    1505                 : }
    1506                 : 
    1507               1 : AnyScalar BasicSymbolTable::funcPOW(const paramlist_type &paramlist)
    1508                 : {
    1509               1 :     return AnyScalar( std::pow(paramlist[0].getDouble(), paramlist[1].getDouble()) );
    1510                 : }
    1511                 : 
    1512               1 : AnyScalar BasicSymbolTable::funcSQRT(const paramlist_type &paramlist)
    1513                 : {
    1514               1 :     return AnyScalar( std::sqrt(paramlist[0].getDouble()) );
    1515                 : }
    1516                 : 
    1517              17 : void BasicSymbolTable::addStandardFunctions()
    1518                 : {
    1519              17 :     setFunction("PI", 0, funcPI);
    1520                 : 
    1521              34 :     setFunction("SIN", 1, funcSIN);
    1522              34 :     setFunction("COS", 1, funcCOS);
    1523              34 :     setFunction("TAN", 1, funcTAN);
    1524                 : 
    1525              34 :     setFunction("ABS", 1, funcABS);
    1526              34 :     setFunction("EXP", 1, funcEXP);
    1527              34 :     setFunction("LOGN", 1, funcLOGN);
    1528              34 :     setFunction("POW", 2, funcPOW);
    1529              34 :     setFunction("SQRT", 1, funcSQRT);
    1530              17 : }
    1531                 : 
    1532               4 : AnyScalar BasicSymbolTable::lookupVariable(const std::string &_varname) const
    1533                 : {
    1534               4 :     std::string varname = _varname;
    1535               4 :     std::transform(varname.begin(), varname.end(), varname.begin(), tolower);
    1536                 : 
    1537               4 :     variablemap_type::const_iterator fi = variablemap.find(varname);
    1538                 : 
    1539               4 :     if (fi != variablemap.end())
    1540                 :     {
    1541               3 :         return fi->second;
    1542                 :     }
    1543                 : 
    1544               3 :     throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
    1545                 : }
    1546                 : 
    1547                 : AnyScalar BasicSymbolTable::processFunction(const std::string &_funcname,
    1548               6 :                                             const paramlist_type &paramlist) const
    1549                 : {
    1550               6 :     std::string funcname = _funcname;
    1551               6 :     std::transform(funcname.begin(), funcname.end(), funcname.begin(), toupper);
    1552                 : 
    1553               6 :     functionmap_type::const_iterator fi = functionmap.find(funcname);
    1554                 : 
    1555               6 :     if (fi != functionmap.end())
    1556                 :     {
    1557               5 :         if (fi->second.arguments >= 0)
    1558                 :         {
    1559               5 :             if (fi->second.arguments == 0 && paramlist.size() != 0)
    1560                 :             {
    1561               0 :                 throw(BadFunctionCallException(std::string("Function ") + funcname + "() does not take any parameter."));
    1562                 :             }
    1563               5 :             else if (fi->second.arguments == 1 && paramlist.size() != 1)
    1564                 :             {
    1565               1 :                 throw(BadFunctionCallException(std::string("Function ") + funcname + "() takes exactly one parameter."));
    1566                 :             }
    1567               4 :             else if (static_cast<unsigned int>(fi->second.arguments) != paramlist.size())
    1568                 :             {
    1569               0 :                 std::ostringstream oss;
    1570               0 :                 oss << "Function " << funcname << "() takes exactly " << fi->second.arguments << " parameters.";
    1571               0 :                 throw(BadFunctionCallException(oss.str()));
    1572                 :             }
    1573                 :         }
    1574               4 :         return fi->second.func(paramlist);
    1575                 :     }
    1576                 : 
    1577               4 :     throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
    1578                 : }
    1579               0 : 
    1580               2 : } // namespace stx

Generated by: LTP GCOV extension version 1.4