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" |