libstx-exparser/ExpressionParser.cc

Go to the documentation of this file.
00001 // $Id: ExpressionParser.cc 59 2007-07-17 14:43:23Z tb $
00002 
00003 /*
00004  * STX Expression Parser C++ Framework v0.7
00005  * Copyright (C) 2007 Timo Bingmann
00006  *
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or (at your
00010  * option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
00015  * for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00027 #include "ExpressionParser.h"
00028 
00029 #include <boost/spirit/core.hpp>
00030 
00031 #include <boost/spirit/tree/ast.hpp>
00032 #include <boost/spirit/tree/tree_to_xml.hpp>
00033 
00034 #include <boost/spirit/utility/lists.hpp>
00035 #include <boost/spirit/utility/distinct.hpp>
00036 #include <boost/spirit/utility/escape_char.hpp>
00037 #include <boost/spirit/utility/grammar_def.hpp> 
00038 
00039 #include <iostream>
00040 #include <sstream>
00041 #include <cmath>
00042 
00043 // #define STX_DEBUG_PARSER
00044 
00045 namespace stx {
00046 
00049 namespace Grammar {
00050 
00051 using namespace boost::spirit;
00052 
00054 enum parser_ids
00055 {
00056     boolean_const_id = 1,
00057     integer_const_id,
00058     long_const_id,
00059     double_const_id,
00060     string_const_id,
00061     constant_id,
00062 
00063     function_call_id,
00064     function_identifier_id,
00065 
00066     varname_id,
00067 
00068     atom_expr_id,
00069 
00070     unary_expr_id,
00071     mul_expr_id,
00072     add_expr_id,
00073 
00074     cast_expr_id,
00075     cast_spec_id,
00076 
00077     comp_expr_id,
00078     and_expr_id,
00079     or_expr_id,
00080 
00081     expr_id,
00082     exprlist_id,
00083 };
00084 
00086 distinct_parser<> keyword_p("a-zA-Z0-9_");
00087 
00089 struct ExpressionGrammar : public grammar<ExpressionGrammar>
00090 {
00093     template <typename ScannerT>
00094     struct definition : public grammar_def<rule<ScannerT, parser_context<>, parser_tag<expr_id> >,
00095                                            rule<ScannerT, parser_context<>, parser_tag<exprlist_id> > >
00096     {
00098         definition(ExpressionGrammar const& /*self*/)
00099         {
00100             // *** Constants
00101 
00102             constant
00103                 = double_const
00104                 | integer_const
00105                 | long_const
00106                 | boolean_const
00107                 | string_const
00108                 ;
00109             
00110             boolean_const
00111                 = as_lower_d[keyword_p("true") | keyword_p("false")]
00112                 ;
00113 
00114             integer_const
00115                 = int_p
00116                 ;
00117 
00118             // this is needed because spirit's int_parsers don't work with
00119             // these long numbers
00120             long_const
00121                 = token_node_d[ lexeme_d[ !( ch_p('+') | ch_p('-' ) ) >> +( range_p('0','9') ) ] ]
00122                 ;
00123 
00124             double_const
00125                 = strict_real_p
00126                 ;
00127 
00128             string_const
00129                 = lexeme_d[
00130                     token_node_d[ '"' >> *(c_escape_ch_p - '"') >> '"' ]
00131                     ]
00132                 ;
00133 
00134             // *** Function call and function identifier
00135 
00136             function_call
00137                 = root_node_d[function_identifier]
00138                 >> discard_node_d[ ch_p('(') ] >> exprlist >> discard_node_d[ ch_p(')') ]
00139                 ;
00140 
00141             function_identifier
00142                 = lexeme_d[ 
00143                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
00144                     ]
00145                 ;
00146 
00147             // *** Expression names
00148 
00149             varname
00150                 = lexeme_d[ 
00151                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
00152                     ]
00153                 ;
00154 
00155             // *** Valid Expressions, from small to large
00156 
00157             atom_expr
00158                 = constant
00159                 | inner_node_d[ ch_p('(') >> expr >> ch_p(')') ]
00160                 | function_call
00161                 | varname
00162                 ;
00163 
00164             unary_expr
00165                 = !( root_node_d[ as_lower_d[ch_p('+') | ch_p('-') | ch_p('!') | str_p("not")] ] )
00166                 >> atom_expr
00167                 ;
00168 
00169             cast_spec
00170                 = discard_node_d[ ch_p('(') ]
00171                 >> (
00172                     keyword_p("bool") |
00173                     keyword_p("char") | keyword_p("short") | keyword_p("int") | keyword_p("integer") | keyword_p("long") |
00174                     keyword_p("byte") | keyword_p("word") | keyword_p("dword") | keyword_p("qword") |
00175                     keyword_p("float") | keyword_p("double") |
00176                     keyword_p("string")
00177                     )
00178                 >> discard_node_d[ ch_p(')') ]
00179                 ;
00180 
00181             cast_expr
00182                 = root_node_d[ !cast_spec ] >> unary_expr
00183                 ;
00184 
00185             mul_expr
00186                 = cast_expr
00187                 >> *( root_node_d[ch_p('*') | ch_p('/')] >> cast_expr )
00188                 ;
00189 
00190             add_expr
00191                 = mul_expr
00192                 >> *( root_node_d[ch_p('+') | ch_p('-')] >> mul_expr )
00193                 ;
00194 
00195             comp_expr
00196                 = add_expr
00197                 >> *( root_node_d[( str_p("==") | str_p("!=") |
00198                                     str_p("<=") | str_p(">=") | str_p("=<") | str_p("=>") |
00199                                     ch_p('=') | ch_p('<') | ch_p('>') )] >> add_expr )
00200                 ;
00201 
00202             and_expr
00203                 = comp_expr
00204                 >> *( root_node_d[ as_lower_d[str_p("and") | str_p("&&")] ] >> comp_expr )
00205                 ;
00206 
00207             or_expr
00208                 = and_expr
00209                 >> *( root_node_d[ as_lower_d[str_p("or") | str_p("||")] ] >> and_expr )
00210                 ;
00211 
00212             // *** Base Expression and List
00213 
00214             expr
00215                 = or_expr
00216                 ;
00217 
00218             exprlist
00219                 = infix_node_d[ !list_p(expr, ch_p(',')) ]
00220                 ;
00221 
00222             // Special spirit feature to declare multiple grammar entry points
00223             this->start_parsers(expr, exprlist); 
00224 
00225 #ifdef STX_DEBUG_PARSER
00226             BOOST_SPIRIT_DEBUG_RULE(constant);
00227 
00228             BOOST_SPIRIT_DEBUG_RULE(boolean_const);
00229             BOOST_SPIRIT_DEBUG_RULE(integer_const);
00230             BOOST_SPIRIT_DEBUG_RULE(long_const);
00231             BOOST_SPIRIT_DEBUG_RULE(double_const);
00232             BOOST_SPIRIT_DEBUG_RULE(string_const);
00233 
00234             BOOST_SPIRIT_DEBUG_RULE(function_call);
00235             BOOST_SPIRIT_DEBUG_RULE(function_identifier);
00236             
00237             BOOST_SPIRIT_DEBUG_RULE(varname);
00238 
00239             BOOST_SPIRIT_DEBUG_RULE(atom_expr);
00240 
00241             BOOST_SPIRIT_DEBUG_RULE(unary_expr);
00242             BOOST_SPIRIT_DEBUG_RULE(mul_expr);
00243             BOOST_SPIRIT_DEBUG_RULE(add_expr);
00244 
00245             BOOST_SPIRIT_DEBUG_RULE(cast_spec);
00246             BOOST_SPIRIT_DEBUG_RULE(cast_expr);
00247 
00248             BOOST_SPIRIT_DEBUG_RULE(comp_expr);
00249             BOOST_SPIRIT_DEBUG_RULE(and_expr);
00250             BOOST_SPIRIT_DEBUG_RULE(or_expr);
00251 
00252             BOOST_SPIRIT_DEBUG_RULE(expr);
00253             BOOST_SPIRIT_DEBUG_RULE(exprlist);
00254 #endif
00255         }
00256 
00259         rule<ScannerT, parser_context<>, parser_tag<constant_id> >              constant;
00260 
00262         rule<ScannerT, parser_context<>, parser_tag<boolean_const_id> >         boolean_const;
00264         rule<ScannerT, parser_context<>, parser_tag<integer_const_id> >         integer_const;
00266         rule<ScannerT, parser_context<>, parser_tag<long_const_id> >            long_const;
00268         rule<ScannerT, parser_context<>, parser_tag<double_const_id> >          double_const;
00270         rule<ScannerT, parser_context<>, parser_tag<string_const_id> >          string_const;
00271 
00273         rule<ScannerT, parser_context<>, parser_tag<function_call_id> >         function_call;
00276         rule<ScannerT, parser_context<>, parser_tag<function_identifier_id> >   function_identifier;
00277 
00279         rule<ScannerT, parser_context<>, parser_tag<varname_id> >               varname;
00280 
00282         rule<ScannerT, parser_context<>, parser_tag<atom_expr_id> >             atom_expr;
00283 
00285         rule<ScannerT, parser_context<>, parser_tag<unary_expr_id> >            unary_expr;
00288         rule<ScannerT, parser_context<>, parser_tag<mul_expr_id> >              mul_expr;
00290         rule<ScannerT, parser_context<>, parser_tag<add_expr_id> >              add_expr;
00291 
00293         rule<ScannerT, parser_context<>, parser_tag<cast_spec_id> >             cast_spec;
00295         rule<ScannerT, parser_context<>, parser_tag<cast_expr_id> >             cast_expr;
00296 
00298         rule<ScannerT, parser_context<>, parser_tag<comp_expr_id> >             comp_expr;
00301         rule<ScannerT, parser_context<>, parser_tag<and_expr_id> >              and_expr;
00304         rule<ScannerT, parser_context<>, parser_tag<or_expr_id> >               or_expr;
00305 
00307         rule<ScannerT, parser_context<>, parser_tag<expr_id> >                  expr;
00310         rule<ScannerT, parser_context<>, parser_tag<exprlist_id> >              exprlist;
00311     };
00312 };
00313 
00314 // *** Classes representing the nodes in the resulting parse tree, these need
00315 // *** not be publicly available via the header file.
00316 
00319 class PNConstant : public ParseNode
00320 {
00321 private:
00323     class AnyScalar     value;
00324 
00325 public:
00327     PNConstant(AnyScalar::attrtype_t type, std::string strvalue)
00328         : ParseNode(), value(type)
00329     {
00330         // check whether to dequote the incoming string.
00331         if (type == AnyScalar::ATTRTYPE_STRING)
00332             value.setStringQuoted(strvalue);
00333         else
00334             value.setString(strvalue); // not a string, but an integer or double or boolean value
00335     }
00336 
00338     PNConstant(const AnyScalar &_value)
00339         : value(_value)
00340     {
00341     }
00342 
00344     virtual AnyScalar evaluate(const class SymbolTable &) const
00345     {
00346         return value;
00347     }
00348 
00350     virtual bool evaluate_const(AnyScalar *dest) const
00351     {
00352         if (dest) *dest = value;
00353         return true;
00354     }
00355 
00357     virtual std::string toString() const
00358     {
00359         if (value.getType() == AnyScalar::ATTRTYPE_STRING) {
00360             return value.getStringQuoted();
00361         }
00362         return value.getString();
00363     }
00364 };
00365 
00368 class PNVariable : public ParseNode
00369 {
00370 private:
00372     std::string         varname;
00373 
00374 public:
00376     PNVariable(std::string _varname)
00377         : ParseNode(), varname(_varname)
00378     {
00379     }
00380 
00382     virtual AnyScalar evaluate(const class SymbolTable &st) const
00383     {
00384         return st.lookupVariable(varname);
00385     }
00386 
00388     virtual bool evaluate_const(AnyScalar *) const
00389     {
00390         return false;
00391     }
00392 
00394     virtual std::string toString() const
00395     {
00396         return varname;
00397     }
00398 };
00399 
00402 class PNFunction : public ParseNode
00403 {
00404 public:
00406     typedef std::vector<const class ParseNode*> paramlist_type;
00407 
00408 private:
00410     std::string         funcname;
00411 
00413     paramlist_type      paramlist;
00414 
00415 public:
00417     PNFunction(std::string _funcname, const paramlist_type& _paramlist)
00418         : ParseNode(), funcname(_funcname), paramlist(_paramlist)
00419     {
00420     }
00421 
00423     ~PNFunction()
00424     {
00425         for(unsigned int i = 0; i < paramlist.size(); ++i)
00426             delete paramlist[i];
00427     }
00428 
00430     virtual AnyScalar evaluate(const class SymbolTable &st) const
00431     {
00432         std::vector<AnyScalar> paramvalues;
00433 
00434         for(unsigned int i = 0; i < paramlist.size(); ++i)
00435         {
00436             paramvalues.push_back( paramlist[i]->evaluate(st) );
00437         }
00438 
00439         return st.processFunction(funcname, paramvalues);
00440     }
00441 
00443     virtual bool evaluate_const(AnyScalar *) const
00444     {
00445         return false;
00446     }
00447 
00449     virtual std::string toString() const
00450     {
00451         std::string str = funcname + "(";
00452         for(unsigned int i = 0; i < paramlist.size(); ++i)
00453         {
00454             if (i != 0) str += ",";
00455             str += paramlist[i]->toString();
00456         }
00457         return str + ")";
00458     }
00459 };
00460 
00463 class PNUnaryArithmExpr : public ParseNode
00464 {
00465 private:
00467     const ParseNode     *operand;
00468 
00471     char        op;
00472 
00473 public:
00475     PNUnaryArithmExpr(const ParseNode* _operand, char _op)
00476         : ParseNode(), operand(_operand), op(_op)
00477     {
00478         if (op == 'n' || op == 'N') op = '!';
00479     }
00480 
00482     virtual ~PNUnaryArithmExpr()
00483     {
00484         delete operand;
00485     }
00486 
00488     virtual AnyScalar evaluate(const class SymbolTable &st) const
00489     {
00490         AnyScalar dest = operand->evaluate(st);
00491 
00492         if (op == '-') {
00493             dest = -dest;           
00494         }
00495         else if (op == '!')
00496         {
00497             // This should not happend, as types are constant in the parse tree
00498             if (dest.getType() != AnyScalar::ATTRTYPE_BOOL)
00499                 throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
00500 
00501             dest = -dest;
00502         }
00503         else {
00504             assert(op == '+');
00505         }
00506 
00507         return dest;
00508     }
00509 
00511     virtual bool evaluate_const(AnyScalar *dest) const
00512     {
00513         if (!dest) return false;
00514 
00515         bool b = operand->evaluate_const(dest);
00516 
00517         if (op == '-') {
00518             *dest = -(*dest);
00519         }
00520         else if (op == '!')
00521         {
00522             if (dest->getType() != AnyScalar::ATTRTYPE_BOOL)
00523                 throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
00524 
00525             *dest = -(*dest);
00526         }
00527         else {
00528             assert(op == '+');
00529         }
00530         
00531         return b;
00532     }
00533 
00535     virtual std::string toString() const
00536     {
00537         return std::string("(") + op + " " + operand->toString() + ")";
00538     }
00539 };
00540 
00543 class PNBinaryArithmExpr : public ParseNode
00544 {
00545 private:
00547     const ParseNode     *left;
00548 
00550     const ParseNode     *right;
00551 
00554     char        op;
00555 
00556 public:
00558     PNBinaryArithmExpr(const ParseNode* _left,
00559                        const ParseNode* _right,
00560                        char _op)
00561         : ParseNode(),
00562           left(_left), right(_right), op(_op)
00563     { }
00564 
00566     virtual ~PNBinaryArithmExpr()
00567     {
00568         delete left;
00569         delete right;
00570     }
00571 
00574     virtual AnyScalar evaluate(const class SymbolTable &st) const
00575     {
00576         AnyScalar vl = left->evaluate(st);
00577         AnyScalar vr = right->evaluate(st);
00578 
00579         if (op == '+') {
00580             return (vl + vr);
00581         }
00582         else if (op == '-') {
00583             return (vl - vr);
00584         }
00585         else if (op == '*') {
00586             return (vl * vr);
00587         }
00588         else if (op == '/') {
00589             return (vl / vr);
00590         }
00591 
00592         assert(0);
00593         return 0;
00594     }
00595 
00598     virtual bool evaluate_const(AnyScalar *dest) const
00599     {
00600         if (!dest) return false;
00601 
00602         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
00603         
00604         bool bl = left->evaluate_const(&vl);
00605         bool br = right->evaluate_const(&vr);
00606 
00607         if (op == '+') {
00608             *dest = vl + vr;
00609         }
00610         else if (op == '-') {
00611             *dest = vl - vr;
00612         }
00613         else if (op == '*') {
00614             *dest = vl * vr;
00615         }
00616         else if (op == '/') {
00617             *dest = vl / vr;
00618         }
00619 
00620         return (bl && br);
00621     }
00622 
00624     virtual std::string toString() const
00625     {
00626         return std::string("(") + left->toString() + " " + op + " " + right->toString() + ")";
00627     }
00628 };
00629 
00631 class PNCastExpr : public ParseNode
00632 {
00633 private:
00635     const ParseNode*    operand;
00636 
00638     AnyScalar::attrtype_t       type;
00639 
00640 public:
00643     PNCastExpr(const ParseNode* _operand, AnyScalar::attrtype_t _type)
00644         : ParseNode(),
00645           operand(_operand), type(_type)
00646     { }
00647 
00649     virtual ~PNCastExpr()
00650     {
00651         delete operand;
00652     }
00653 
00656     virtual AnyScalar evaluate(const class SymbolTable &st) const
00657     {
00658         AnyScalar val = operand->evaluate(st);
00659         val.convertType(type);
00660         return val;
00661     }
00662 
00664     virtual bool evaluate_const(AnyScalar *dest) const
00665     {
00666         if (!dest) return false;
00667 
00668         bool b = operand->evaluate_const(dest);
00669         dest->convertType(type);
00670         return b;
00671     }
00672 
00674     virtual std::string toString() const
00675     {
00676         return std::string("((") + AnyScalar::getTypeString(type) + ")" + operand->toString() + ")";
00677     }
00678 };
00679 
00682 class PNBinaryComparisonExpr : public ParseNode
00683 {
00684 private:
00686     const ParseNode     *left;
00687 
00689     const ParseNode     *right;
00690 
00692     enum { EQUAL, NOTEQUAL, LESS, GREATER, LESSEQUAL, GREATEREQUAL } op;
00693 
00695     std::string         opstr;
00696 
00697 public:
00699     PNBinaryComparisonExpr(const ParseNode* _left,
00700                            const ParseNode* _right,
00701                            std::string _op)
00702         : ParseNode(),
00703           left(_left), right(_right), opstr(_op)
00704     {
00705         if (_op == "==" || _op == "=")
00706             op = EQUAL;
00707         else if (_op == "!=")
00708             op = NOTEQUAL;
00709         else if (_op == "<")
00710             op = LESS;
00711         else if (_op == ">")
00712             op = GREATER;
00713         else if (_op == "<=" || _op == "=<")
00714             op = LESSEQUAL;
00715         else if (_op == ">=" || _op == "=>")
00716             op = GREATEREQUAL;
00717         else
00718             throw(BadSyntaxException("Program Error: invalid binary comparision operator."));
00719     }
00720 
00722     virtual ~PNBinaryComparisonExpr()
00723     {
00724         delete left;
00725         delete right;
00726     }
00727 
00731     virtual AnyScalar evaluate(const class SymbolTable &st) const
00732     {
00733         AnyScalar vl = left->evaluate(st);
00734         AnyScalar vr = right->evaluate(st);
00735 
00736         AnyScalar dest(AnyScalar::ATTRTYPE_BOOL);
00737 
00738         switch(op)
00739         {
00740         case EQUAL:
00741             dest = AnyScalar( vl.equal_to(vr) );
00742             break;
00743 
00744         case NOTEQUAL:
00745             dest = AnyScalar( vl.not_equal_to(vr) );
00746             break;
00747 
00748         case LESS:
00749             dest = AnyScalar( vl.less(vr) );
00750             break;
00751 
00752         case GREATER:
00753             dest = AnyScalar( vl." greater-than.">greater(vr) );
00754             break;
00755 
00756         case LESSEQUAL:
00757             dest = AnyScalar( vl.less_equal(vr) );
00758             break;
00759 
00760         case GREATEREQUAL:
00761             dest = AnyScalar( vl.=" greater-or-equal-than.">greater_equal(vr) );
00762             break;
00763 
00764         default:
00765             assert(0);
00766         }
00767 
00768         return dest;
00769     }
00770 
00772     virtual bool evaluate_const(AnyScalar *dest) const
00773     {
00774         if (!dest) return false;
00775 
00776         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
00777         
00778         bool bl = left->evaluate_const(&vl);
00779         bool br = right->evaluate_const(&vr);
00780 
00781         switch(op)
00782         {
00783         case EQUAL:
00784             *dest = AnyScalar( vl.equal_to(vr) );
00785             break;
00786 
00787         case NOTEQUAL:
00788             *dest = AnyScalar( vl.not_equal_to(vr) );
00789             break;
00790 
00791         case LESS:
00792             *dest = AnyScalar( vl.less(vr) );
00793             break;
00794 
00795         case GREATER:
00796             *dest = AnyScalar( vl.greater(vr) );
00797             break;
00798 
00799         case LESSEQUAL:
00800             *dest = AnyScalar( vl.less_equal(vr) );
00801             break;
00802 
00803         case GREATEREQUAL:
00804             *dest = AnyScalar( vl.greater_equal(vr) );
00805             break;
00806 
00807         default:
00808             assert(0);
00809         }
00810 
00811         return (bl && br);
00812     }
00813 
00815     virtual std::string toString() const
00816     {
00817         return std::string("(") + left->toString() + " " + opstr + " " + right->toString() + ")";
00818     }
00819 };
00820 
00823 class PNBinaryLogicExpr : public ParseNode
00824 {
00825 private:
00827     ParseNode*          left;
00828 
00830     ParseNode*          right;
00831 
00833     enum { OP_AND, OP_OR } op;
00834 
00835 public:
00837     PNBinaryLogicExpr(ParseNode* _left,
00838                       ParseNode* _right,
00839                       std::string _op)
00840         : ParseNode(),
00841           left(_left), right(_right)
00842     {
00843         if (_op == "and" || _op == "&&")
00844             op = OP_AND;
00845         else if (_op == "or" || _op == "||")
00846             op = OP_OR;
00847         else
00848             throw(BadSyntaxException("Program Error: invalid binary logic operator."));
00849     }
00850 
00852     virtual ~PNBinaryLogicExpr()
00853     {
00854         if (left) delete left;
00855         if (right) delete right;
00856     }
00857 
00859     inline bool do_operator(bool left, bool right) const
00860     {
00861         if (op == OP_AND)
00862             return left && right;
00863         else if (op == OP_OR)
00864             return left || right;
00865         else
00866             return false;
00867     }
00868 
00870     inline std::string get_opstr() const
00871     {
00872         return (op == OP_AND) ? "&&" : "||";
00873     }
00874 
00877     virtual AnyScalar evaluate(const class SymbolTable &st) const
00878     {
00879         AnyScalar vl = left->evaluate(st);
00880         AnyScalar vr = right->evaluate(st);
00881 
00882         // these should never happen.
00883         if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
00884             throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
00885         if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
00886             throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
00887 
00888         int bvl = vl.getInteger();
00889         int bvr = vr.getInteger();
00890 
00891         return AnyScalar( do_operator(bvl, bvr) );
00892     }
00893 
00898     virtual bool evaluate_const(AnyScalar *dest) const
00899     {
00900         if (!dest) return false; // returns false because this node isn't always constant
00901 
00902         AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
00903         
00904         bool bl = left->evaluate_const(&vl);
00905         bool br = right->evaluate_const(&vr);
00906 
00907         if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
00908             throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
00909         if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
00910             throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
00911 
00912         int bvl = vl.getInteger();
00913         int bvr = vr.getInteger();
00914 
00915         *dest = AnyScalar( do_operator(bvl, bvr) );
00916 
00917         if (op == OP_AND)
00918         {
00919             // true if either both ops are themselves constant, or if either of
00920             // the ops are constant and evaluates to false.
00921             return (bl && br) || (bl && !bvl) || (br && !bvr);
00922         }
00923         else if (op == OP_OR)
00924         {
00925             // true if either both ops are themselves constant, or if either of
00926             // the ops is constant and evaluates to true.
00927             return (bl && br) || (bl && bvl) || (br && bvr);
00928         }
00929         else {
00930             assert(0);
00931             return false;
00932         }
00933     }
00934 
00936     virtual std::string toString() const
00937     {
00938         return std::string("(") + left->toString() + " " + get_opstr() + " " + right->toString() + ")";
00939     }
00940 
00942     inline ParseNode* detach_left()
00943     {
00944         ParseNode *n = left;
00945         left = NULL;
00946         return n;
00947     }
00948 
00950     inline ParseNode* detach_right()
00951     {
00952         ParseNode *n = right;
00953         right = NULL;
00954         return n;
00955     }
00956 };
00957 
00958 // *** Functions which translate the resulting parse tree into our expression
00959 // *** tree, simultaneously folding constants.
00960 
00962 typedef std::string::const_iterator InputIterT;
00963 
00965 typedef tree_match<InputIterT> ParseTreeMatchT;
00966 
00968 typedef ParseTreeMatchT::const_tree_iterator TreeIterT;
00969 
00972 static ParseNode* build_expr(TreeIterT const& i)
00973 {
00974 #ifdef STX_DEBUG_PARSER
00975     std::cout << "In build_expr. i->value = " <<
00976         std::string(i->value.begin(), i->value.end()) <<
00977         " i->children.size() = " << i->children.size() << 
00978         " i->value.id = " << i->value.id().to_long() << std::endl;
00979 #endif
00980 
00981     switch(i->value.id().to_long())
00982     {
00983     // *** Constant node cases
00984 
00985     case boolean_const_id:
00986     {
00987         return new PNConstant(AnyScalar::ATTRTYPE_BOOL,
00988                               std::string(i->value.begin(), i->value.end()));
00989     }
00990 
00991     case integer_const_id:
00992     {
00993         return new PNConstant(AnyScalar::ATTRTYPE_INTEGER,
00994                               std::string(i->value.begin(), i->value.end()));
00995     }
00996 
00997     case long_const_id:
00998     {
00999         return new PNConstant(AnyScalar::ATTRTYPE_LONG,
01000                               std::string(i->value.begin(), i->value.end()));
01001     }
01002 
01003     case double_const_id:
01004     {
01005         return new PNConstant(AnyScalar::ATTRTYPE_DOUBLE,
01006                               std::string(i->value.begin(), i->value.end()));
01007     }
01008 
01009     case string_const_id:
01010     {
01011         return new PNConstant(AnyScalar::ATTRTYPE_STRING,
01012                               std::string(i->value.begin(), i->value.end()));
01013     }
01014 
01015     // *** Arithmetic node cases
01016 
01017     case unary_expr_id:
01018     {
01019         char arithop = *i->value.begin();
01020         assert(i->children.size() == 1);
01021 
01022         const ParseNode *val = build_expr(i->children.begin());
01023 
01024         if (val->evaluate_const(NULL))
01025         {
01026             // construct a constant node
01027             PNUnaryArithmExpr tmpnode(val, arithop);
01028             AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
01029 
01030             tmpnode.evaluate_const(&constval);
01031 
01032             return new PNConstant(constval);
01033         }
01034         else
01035         {
01036             // calculation node
01037             return new PNUnaryArithmExpr(val, arithop);
01038         }
01039     }
01040 
01041     case add_expr_id:
01042     case mul_expr_id:
01043     {
01044         char arithop = *i->value.begin();
01045         assert(i->children.size() == 2);
01046 
01047         // auto_ptr needed because of possible parse exceptions in build_expr.
01048 
01049         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
01050         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
01051 
01052         if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
01053         {
01054             // construct a constant node
01055             PNBinaryArithmExpr tmpnode(left.release(), right.release(), arithop);
01056             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
01057 
01058             tmpnode.evaluate_const(&both);
01059 
01060             // left and right are deleted by tmpnode's deconstructor
01061 
01062             return new PNConstant(both);
01063         }
01064         else
01065         {
01066             // calculation node
01067             return new PNBinaryArithmExpr(left.release(), right.release(), arithop);
01068         }
01069     }
01070 
01071     // *** Cast node case
01072 
01073     case cast_spec_id:
01074     {
01075         assert(i->children.size() == 1);
01076 
01077         std::string tname(i->value.begin(), i->value.end());
01078         AnyScalar::attrtype_t at = AnyScalar::stringToType(tname);
01079         
01080         const ParseNode *val = build_expr(i->children.begin());
01081 
01082         if (val->evaluate_const(NULL))
01083         {
01084             // construct a constant node
01085             PNCastExpr tmpnode(val, at);
01086 
01087             AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
01088 
01089             tmpnode.evaluate_const(&constval);
01090 
01091             return new PNConstant(constval);
01092         }
01093         else
01094         {
01095             return new PNCastExpr(val, at);
01096         }
01097     }
01098 
01099     // *** Binary Comparison Operator
01100 
01101     case comp_expr_id:
01102     {
01103         assert(i->children.size() == 2);
01104 
01105         std::string arithop(i->value.begin(), i->value.end());
01106 
01107         // we need auto_ptr because of possible parse exceptions in build_expr.
01108 
01109         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
01110         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
01111 
01112         if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
01113         {
01114             // construct a constant node
01115             PNBinaryComparisonExpr tmpnode(left.release(), right.release(), arithop);
01116             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
01117 
01118             tmpnode.evaluate_const(&both);
01119 
01120             // left and right are deleted by tmpnode's deconstructor
01121 
01122             return new PNConstant(both);
01123         }
01124         else
01125         {
01126             // calculation node
01127             return new PNBinaryComparisonExpr(left.release(), right.release(), arithop);
01128         }
01129     }
01130 
01131     // *** Binary Logic Operator
01132 
01133     case and_expr_id:
01134     case or_expr_id:
01135     {
01136         assert(i->children.size() == 2);
01137 
01138         std::string logicop(i->value.begin(), i->value.end());
01139         std::transform(logicop.begin(), logicop.end(), logicop.begin(), tolower);
01140 
01141         // auto_ptr needed because of possible parse exceptions in build_expr.
01142 
01143         std::auto_ptr<ParseNode> left( build_expr(i->children.begin()) );
01144         std::auto_ptr<ParseNode> right( build_expr(i->children.begin()+1) );
01145 
01146         bool constleft = left->evaluate_const(NULL);
01147         bool constright = right->evaluate_const(NULL);
01148 
01149         // a logical node is constant if one of the two ops is constant. so we
01150         // construct a calculation node and check later.
01151         std::auto_ptr<PNBinaryLogicExpr> node( new PNBinaryLogicExpr(left.release(), right.release(), logicop) );
01152 
01153         if (constleft || constright)
01154         {
01155             AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
01156 
01157             // test if the node is really const.
01158             if (node->evaluate_const(&both))
01159             {
01160                 // return a constant node instead, node will be deleted by
01161                 // auto_ptr, left,right by node's destructor.
01162                 return new PNConstant(both);
01163             }
01164         }
01165         if (constleft)
01166         {
01167             // left node is constant, but the evaluation is not
01168             // -> only right node is meaningful.
01169             return node->detach_right();
01170         }
01171         if (constright)
01172         {
01173             // right node is constant, but the evaluation is not
01174             // -> only left node is meaningful.
01175             return node->detach_left();
01176         }
01177 
01178         return node.release();
01179     }
01180 
01181     // *** Variable and Function name place-holder
01182 
01183     case varname_id:
01184     {
01185         assert(i->children.size() == 0);
01186 
01187         std::string varname(i->value.begin(), i->value.end());
01188 
01189         return new PNVariable(varname);
01190     }
01191 
01192     case function_identifier_id:
01193     {
01194         std::string funcname(i->value.begin(), i->value.end());
01195         std::vector<const class ParseNode*> paramlist;
01196 
01197         if (i->children.size() > 0)
01198         {
01199             TreeIterT const& paramlistchild = i->children.begin();
01200 
01201             if (paramlistchild->value.id().to_long() == exprlist_id)
01202             {
01203                 try
01204                 {
01205                     for(TreeIterT ci = paramlistchild->children.begin(); ci != paramlistchild->children.end(); ++ci)
01206                     {
01207                         const ParseNode *pas = build_expr(ci);
01208                         paramlist.push_back(pas);
01209                     }
01210                 }
01211                 catch (...) // need to clean-up
01212                 {
01213                     for(unsigned int i = 0; i < paramlist.size(); ++i)
01214                         delete paramlist[i];
01215                     throw;
01216                 }
01217             }
01218             else
01219             {
01220                 // just one subnode and its not a full expression list
01221                 paramlist.push_back( build_expr(paramlistchild) );
01222             }
01223         }
01224 
01225         return new PNFunction(funcname, paramlist);
01226     }
01227 
01228     default:
01229         throw(ExpressionParserException("Unknown AST parse tree node found. This should never happen."));
01230     }
01231 }
01232 
01235 ParseTreeList build_exprlist(TreeIterT const &i)
01236 {
01237 #ifdef STX_DEBUG_PARSER
01238     std::cout << "In build_exprlist. i->value = " <<
01239         std::string(i->value.begin(), i->value.end()) <<
01240         " i->children.size() = " << i->children.size() << 
01241         " i->value.id = " << i->value.id().to_long() << std::endl;
01242 #endif
01243 
01244     ParseTreeList ptlist;
01245 
01246     for(TreeIterT ci = i->children.begin(); ci != i->children.end(); ++ci)
01247     {
01248         ParseNode *vas = build_expr(ci);
01249 
01250         ptlist.push_back( ParseTree(vas) );
01251     }
01252 
01253     return ptlist;
01254 }
01255 
01257 static inline void tree_dump_xml(std::ostream &os, const std::string &input, const tree_parse_info<InputIterT> &info)
01258 {
01259     // map used by the xml dumper to label the nodes
01260 
01261     std::map<parser_id, std::string> rule_names;
01262 
01263     rule_names[boolean_const_id] = "boolean_const";
01264     rule_names[integer_const_id] = "integer_const";
01265     rule_names[long_const_id] = "long_const";
01266     rule_names[double_const_id] = "double_const";
01267     rule_names[string_const_id] = "string_const";
01268     rule_names[constant_id] = "constant";
01269 
01270     rule_names[function_call_id] = "function_call";
01271     rule_names[function_identifier_id] = "function_identifier";
01272 
01273     rule_names[varname_id] = "varname";
01274 
01275     rule_names[unary_expr_id] = "unary_expr";
01276     rule_names[mul_expr_id] = "mul_expr";
01277     rule_names[add_expr_id] = "add_expr";
01278 
01279     rule_names[cast_expr_id] = "cast_expr";
01280     rule_names[cast_spec_id] = "cast_spec";
01281 
01282     rule_names[comp_expr_id] = "comp_expr";
01283     rule_names[and_expr_id] = "and_expr";
01284     rule_names[or_expr_id] = "or_expr";
01285 
01286     rule_names[expr_id] = "expr";
01287     rule_names[exprlist_id] = "exprlist";
01288 
01289     tree_to_xml(os, info.trees, input.c_str(), rule_names);
01290 }
01291 
01292 } // namespace Grammar
01293 
01294 const ParseTree parseExpression(const std::string &input)
01295 {
01296     // instance of the grammar
01297     Grammar::ExpressionGrammar g;
01298 
01299 #ifdef STX_DEBUG_PARSER
01300     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
01301 #endif
01302 
01303     Grammar::tree_parse_info<Grammar::InputIterT> info =
01304         boost::spirit::ast_parse(input.begin(), input.end(),
01305                                  g.use_parser<0>(),     // use first entry point: expr
01306                                  boost::spirit::space_p);
01307 
01308     if (!info.full)
01309     {
01310         std::ostringstream oss;
01311         oss << "Syntax error at position "
01312             << static_cast<int>(info.stop - input.begin())
01313             << " near " 
01314             << std::string(info.stop, input.end());
01315 
01316         throw(BadSyntaxException(oss.str()));
01317     }
01318 
01319     return ParseTree( Grammar::build_expr(info.trees.begin()) );
01320 }
01321 
01322 std::string parseExpressionXML(const std::string &input)
01323 {
01324     // instance of the grammar
01325     Grammar::ExpressionGrammar g;
01326 
01327 #ifdef STX_DEBUG_PARSER
01328     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
01329 #endif
01330 
01331     Grammar::tree_parse_info<Grammar::InputIterT> info =
01332         boost::spirit::ast_parse(input.begin(), input.end(),
01333                                  g.use_parser<0>(),     // use first entry point: expr
01334                                  boost::spirit::space_p);
01335 
01336     if (!info.full)
01337     {
01338         std::ostringstream oss;
01339         oss << "Syntax error at position "
01340             << static_cast<int>(info.stop - input.begin())
01341             << " near " 
01342             << std::string(info.stop, input.end());
01343 
01344         throw(BadSyntaxException(oss.str()));
01345     }
01346 
01347     std::ostringstream oss;
01348     Grammar::tree_dump_xml(oss, input, info);
01349     return oss.str();
01350 }
01351 
01352 ParseTreeList parseExpressionList(const std::string &input)
01353 {
01354     // instance of the grammar
01355     Grammar::ExpressionGrammar g;
01356 
01357 #ifdef STX_DEBUG_PARSER
01358     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
01359 #endif
01360 
01361     Grammar::tree_parse_info<Grammar::InputIterT> info =
01362         boost::spirit::ast_parse(input.begin(), input.end(),
01363                                  g.use_parser<1>(),     // use second entry point: exprlist
01364                                  boost::spirit::space_p);
01365 
01366     if (!info.full)
01367     {
01368         std::ostringstream oss;
01369         oss << "Syntax error at position "
01370             << static_cast<int>(info.stop - input.begin())
01371             << " near " 
01372             << std::string(info.stop, input.end());
01373 
01374         throw(BadSyntaxException(oss.str()));
01375     }
01376 
01377     return Grammar::build_exprlist(info.trees.begin());
01378 }
01379 
01380 std::vector<AnyScalar> ParseTreeList::evaluate(const class SymbolTable &st) const
01381 {
01382     std::vector<AnyScalar> vl;
01383 
01384     for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
01385     {
01386         vl.push_back( i->evaluate(st) );
01387     }
01388 
01389     return vl;
01390 }
01391 
01392 std::string ParseTreeList::toString() const
01393 {
01394     std::string sl;
01395 
01396     for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
01397     {
01398         if (i != parent_type::begin()) {
01399             sl += ", ";
01400         }
01401 
01402         sl += i->toString();
01403     }
01404 
01405     return sl;
01406 }
01407 
01409 
01410 SymbolTable::~SymbolTable()
01411 {
01412 }
01413 
01414 EmptySymbolTable::~EmptySymbolTable()
01415 {
01416 }
01417 
01418 AnyScalar EmptySymbolTable::lookupVariable(const std::string &varname) const
01419 {
01420     throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
01421 }
01422 
01423 AnyScalar EmptySymbolTable::processFunction(const std::string &funcname,
01424                                             const paramlist_type &) const
01425 {
01426     throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
01427 }
01428 
01429 BasicSymbolTable::BasicSymbolTable()
01430 {
01431     addStandardFunctions();
01432 }
01433 
01434 BasicSymbolTable::~BasicSymbolTable()
01435 {
01436 }
01437 
01438 void BasicSymbolTable::setVariable(const std::string& varname, const AnyScalar &value)
01439 {
01440     std::string vn = varname;
01441     std::transform(vn.begin(), vn.end(), vn.begin(), tolower);
01442 
01443     variablemap[vn] = value;
01444 }
01445 
01446 void BasicSymbolTable::setFunction(const std::string& funcname, int arguments, functionptr_type funcptr)
01447 {
01448     std::string fn = funcname;
01449     std::transform(fn.begin(), fn.end(), fn.begin(), toupper);
01450 
01451     functionmap[fn] = FunctionInfo(arguments, funcptr);
01452 }
01453 
01454 void BasicSymbolTable::clearVariables()
01455 {
01456     variablemap.clear();
01457 }
01458 
01459 void BasicSymbolTable::clearFunctions()
01460 {
01461     functionmap.clear();
01462 }
01463 
01464 AnyScalar BasicSymbolTable::funcPI(const paramlist_type &)
01465 {
01466     return AnyScalar(3.14159265358979323846);
01467 }
01468 
01469 AnyScalar BasicSymbolTable::funcSIN(const paramlist_type &paramlist)
01470 {
01471     return AnyScalar( std::sin(paramlist[0].getDouble()) );
01472 }
01473 
01474 AnyScalar BasicSymbolTable::funcCOS(const paramlist_type &paramlist)
01475 {
01476     return AnyScalar( std::cos(paramlist[0].getDouble()) );
01477 }
01478 
01479 AnyScalar BasicSymbolTable::funcTAN(const paramlist_type &paramlist)
01480 {
01481     return AnyScalar( std::tan(paramlist[0].getDouble()) );
01482 }
01483 
01484 AnyScalar BasicSymbolTable::funcABS(const paramlist_type &paramlist)
01485 {
01486     if (paramlist[0].isIntegerType()) {
01487         return AnyScalar( std::abs(paramlist[0].getInteger()) );
01488     }
01489     else if (paramlist[0].isFloatingType()) {
01490         return AnyScalar( std::fabs(paramlist[0].getDouble()) );
01491     }
01492     else {
01493         throw(BadFunctionCallException("Function ABS() takes exactly one parameter"));
01494     }
01495 }
01496 
01497 AnyScalar BasicSymbolTable::funcEXP(const paramlist_type &paramlist)
01498 {
01499     return AnyScalar( std::exp(paramlist[0].getDouble()) );
01500 }
01501 
01502 AnyScalar BasicSymbolTable::funcLOGN(const paramlist_type &paramlist)
01503 {
01504     return AnyScalar( std::log(paramlist[0].getDouble()) );
01505 }
01506 
01507 AnyScalar BasicSymbolTable::funcPOW(const paramlist_type &paramlist)
01508 {
01509     return AnyScalar( std::pow(paramlist[0].getDouble(), paramlist[1].getDouble()) );
01510 }
01511 
01512 AnyScalar BasicSymbolTable::funcSQRT(const paramlist_type &paramlist)
01513 {
01514     return AnyScalar( std::sqrt(paramlist[0].getDouble()) );
01515 }
01516 
01517 void BasicSymbolTable::addStandardFunctions()
01518 {
01519     setFunction("PI", 0, funcPI);
01520 
01521     setFunction("SIN", 1, funcSIN);
01522     setFunction("COS", 1, funcCOS);
01523     setFunction("TAN", 1, funcTAN);
01524 
01525     setFunction("ABS", 1, funcABS);
01526     setFunction("EXP", 1, funcEXP);
01527     setFunction("LOGN", 1, funcLOGN);
01528     setFunction("POW", 2, funcPOW);
01529     setFunction("SQRT", 1, funcSQRT);
01530 }
01531 
01532 AnyScalar BasicSymbolTable::lookupVariable(const std::string &_varname) const
01533 {
01534     std::string varname = _varname;
01535     std::transform(varname.begin(), varname.end(), varname.begin(), tolower);
01536 
01537     variablemap_type::const_iterator fi = variablemap.find(varname);
01538 
01539     if (fi != variablemap.end())
01540     {
01541         return fi->second;
01542     }
01543 
01544     throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
01545 }
01546 
01547 AnyScalar BasicSymbolTable::processFunction(const std::string &_funcname,
01548                                             const paramlist_type &paramlist) const
01549 {
01550     std::string funcname = _funcname;
01551     std::transform(funcname.begin(), funcname.end(), funcname.begin(), toupper);
01552 
01553     functionmap_type::const_iterator fi = functionmap.find(funcname);
01554 
01555     if (fi != functionmap.end())
01556     {
01557         if (fi->second.arguments >= 0)
01558         {
01559             if (fi->second.arguments == 0 && paramlist.size() != 0)
01560             {
01561                 throw(BadFunctionCallException(std::string("Function ") + funcname + "() does not take any parameter."));
01562             }
01563             else if (fi->second.arguments == 1 && paramlist.size() != 1)
01564             {
01565                 throw(BadFunctionCallException(std::string("Function ") + funcname + "() takes exactly one parameter."));
01566             }
01567             else if (static_cast<unsigned int>(fi->second.arguments) != paramlist.size())
01568             {
01569                 std::ostringstream oss;
01570                 oss << "Function " << funcname << "() takes exactly " << fi->second.arguments << " parameters.";
01571                 throw(BadFunctionCallException(oss.str()));
01572             }
01573         }
01574         return fi->second.func(paramlist);
01575     }
01576 
01577     throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
01578 }
01579 
01580 } // namespace stx

Generated on Tue Jul 17 16:51:58 2007 for STX Expression Parser by  doxygen 1.5.2