Orocos Real-Time Toolkit  2.5.0
ExpressionParser.cpp
00001 /***************************************************************************
00002   tag: Peter Soetens  Mon May 10 19:10:37 CEST 2004  ExpressionParser.cxx
00003 
00004                         ExpressionParser.cxx -  description
00005                            -------------------
00006     begin                : Mon May 10 2004
00007     copyright            : (C) 2004 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place,                                    *
00024  *   Suite 330, Boston, MA  02111-1307  USA                                *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #include "parser-debug.hpp"
00029 #include "parse_exception.hpp"
00030 
00031 #ifdef ORO_PRAGMA_INTERFACE
00032 #pragma implementation
00033 #endif
00034 #include "ExpressionParser.hpp"
00035 //#include "DumpObject.hpp"
00036 
00037 #include "ArgumentsParser.hpp"
00038 #include "../types/Operators.hpp"
00039 #include "DataSourceCondition.hpp"
00040 #include "../internal/DataSourceCommand.hpp"
00041 #include "../internal/GlobalService.hpp"
00042 
00043 #include "DataSourceTime.hpp"
00044 #include "../TaskContext.hpp"
00045 #include "PeerParser.hpp"
00046 #include "../types/Types.hpp"
00047 #include "SendHandleAlias.hpp"
00048 
00049 #include <boost/lambda/lambda.hpp>
00050 
00051 #include <boost/bind.hpp>
00052 #include <boost/ref.hpp>
00053 #include "rtt-scripting-config.h"
00054 #include <iostream>
00055 
00056 namespace RTT
00057 {
00058     using boost::bind;
00059     using boost::ref;
00060 
00061     using namespace detail;
00062     using namespace std;
00063 
00064     namespace {
00065         boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
00066         boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected ( or could not find out what this line means ).");
00067         boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type.");
00068         boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression.");
00069         boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
00070         boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the value.");
00071         boost::spirit::classic::assertion<std::string> expect_comma("Expected the ',' separator after expression.");
00072         boost::spirit::classic::assertion<std::string> expect_timespec("Expected a time specification (e.g. > 10s or > varname ) after 'time' .");
00073 
00074         guard<std::string> my_guard;
00075     }
00076 
00077 
00078 
00079   DataCallParser::DataCallParser( ExpressionParser& p, CommonParser& cp, TaskContext* c, ExecutionEngine* caller )
00080       : mcaller( caller ? caller : c->engine()), mis_send(false), commonparser(cp), expressionparser( p ),
00081         peerparser( c, cp, false ) // accept partial paths
00082   {
00083     BOOST_SPIRIT_DEBUG_RULE( datacall );
00084     BOOST_SPIRIT_DEBUG_RULE( arguments );
00085     BOOST_SPIRIT_DEBUG_RULE( peerpath );
00086     BOOST_SPIRIT_DEBUG_RULE( object );
00087     BOOST_SPIRIT_DEBUG_RULE( method );
00088 
00089     // this parser uses a neat boost.spirit trick to avoid keeping
00090     // loads of stacks for all parsing data ( this parser needs to be
00091     // reentrant because it can be called while parsing an argument of
00092     // a datacall, which has itself been called while parsing an
00093     // argument of a datacall... ).  Boost.Spirit allows you to change
00094     // the parser that a rule points to at runtime, so we only create
00095     // the parser just before it's going to be used, when we know what
00096     // arguments we want..  See the ArgumentsParser doc for more
00097     // details..
00098     peerpath = peerparser.locator();
00099     object= (commonparser.identifier >> ".")[boost::bind(&DataCallParser::seenobjectname, this, _1, _2)];
00100     method= ( commonparser.keyword | expect_ident(commonparser.tidentifier))[boost::bind( &DataCallParser::seenmethodname, this, _1, _2 ) ]; // may be send, call or method name.
00101     datacall =
00102         ( peerpath >> !object >> method[ boost::bind( &DataCallParser::seendataname, this ) ] >> !arguments)[ boost::bind( &DataCallParser::seendatacall, this ) ];
00103   }
00104 
00105   void DataCallParser::seensend() {
00106       mis_send = true;
00107   }
00108 
00109   void DataCallParser::seenobjectname( iter_t begin, iter_t end )
00110     {
00111       std::string name( begin, end );
00112       mobject = name.substr(0, name.length() - 1);
00113     };
00114 
00115   void DataCallParser::seenmethodname( iter_t begin, iter_t end )
00116     {
00117       std::string name( begin, end );
00118       if ( name == "send") {
00119           mis_send = true;
00120           mmethod = mobject;
00121           mobject.clear();
00122       } else {
00123           mis_send = false;
00124           mmethod = name;
00125       }
00126 //      cout << "seenmethodname "<< mobject << "." << mmethod<<endl;
00127     };
00128 
00129   void DataCallParser::seendataname()
00130   {
00131       // re-init mobject, might have been cleared during parsing of send().
00132       mobject =  peerparser.object();
00133       TaskContext* peer = peerparser.peer();
00134       Service::shared_ptr ops  = peerparser.taskObject();
00135       peerparser.reset();
00136 //      cout << "seendataname "<< mobject << "." << mmethod<<endl;
00137       if (true) {
00138           // it ain't...
00139           // set the proper object name again in case of a send()
00140           if (mis_send && ops)
00141               mobject = ops->getName();
00142 //          cout << "DCP saw method "<< mmethod <<" of object "<<mobject<<" of peer "<<peer->getName()<<endl;
00143           // Check sanity of what we parsed:
00144           if (mmethod != "collect" && mmethod != "collectIfDone" ) {
00145               if ( ops == 0 || (mobject != "this" && ops->getName() != mobject ) ) {
00146                   throw parse_exception_no_such_component( peer->getName(), mobject);
00147               }
00148               // Check if method exists on current object:
00149               if ( ops->hasMember(mmethod) == false ) {
00150                   // Check if it is a method of the global service:
00151                   if ( ops == peerparser.taskObject() && GlobalService::Instance()->hasMember(mmethod) ) {
00152                       mobject = "GlobalService";
00153                       ops = GlobalService::Instance();
00154                   } else {
00155                       if ( ops == peerparser.taskObject() && ops->provides("scripting")->hasMember(mmethod) ) {
00156                           mobject = "scripting";
00157                           ops = ops->provides("scripting");
00158                       } else {
00159                       //DumpObject( peer );
00160                       if ( mobject != "this" )
00161                           throw parse_exception_no_such_method_on_component( mobject, mmethod );
00162                       else
00163                           throw parse_exception_no_such_method_on_component( peer->getName(), mmethod );
00164                       }
00165                   }
00166               }
00167           }
00168       }
00169 
00170       // create an argument parser for the call..
00171       // Store everything in the ArgumentsParser ! This DataCallParser instance is recursively called !
00172       ArgumentsParser* argspar =
00173           new ArgumentsParser( expressionparser, peer, ops,
00174                                mobject, mmethod );
00175       // we no longer need these two..
00176       mobject.clear();
00177       mmethod.clear();
00178 
00179       // keep hold of the argspar, we're still going to need it after
00180       // it's done its work..  ( in seendatacall(), that is.. )
00181       argparsers.push( argspar );
00182 
00183       // set the arguments parser to the parser provided by the
00184       // ArgumentsParser we just created..
00185       arguments = argspar->parser();
00186   }
00187 
00188   void DataCallParser::seendatacall()
00189   {
00190     ArgumentsParser* argspar = argparsers.top();
00191     argparsers.pop();
00192     std::string obj = argspar->objectname();
00193     std::string meth = argspar->methodname();
00194     std::vector<DataSourceBase::shared_ptr> args = argspar->result();
00195     Service::shared_ptr peer = argspar->object();
00196     delete argspar;
00197     assert(peer && "peer may never be null.");
00198 //    cout << "seendatacall "<< mobject << "." << mmethod<<endl;
00199 
00200     if ( true ) {
00201         // plain method or collect/collectIfDone
00202 
00203         Service::shared_ptr ops = peer;
00204         // we already checked for the existence of this object and method
00205         // in seendataname()..
00206         peerparser.reset();
00207 
00208         try {
00209             if ( (meth == "collect" || meth == "collectIfDone") && !ops->hasMember(mmethod) ) {
00210                 if ( ops->hasAttribute(obj) ) {
00211                     SendHandleAlias* sha = dynamic_cast<SendHandleAlias*>( peer->getValue(obj) );
00212                     if (sha) {
00213                         // add SendHandle DS for Collect:
00214                         args.insert( args.begin(), sha->getDataSource() );
00215                         if (meth == "collect")
00216                             ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(true) );// blocking
00217                         else
00218                             ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(false) );// non-blocking
00219                         return;
00220                     }
00221                 }
00222                 throw parse_exception_fatal_semantic_error( obj + "."+meth +": "+ obj +" is not a valid SendHandle object.");
00223             }
00224             if (!mis_send) {
00225                 ret = ops->produce( meth, args, mcaller );
00226                 mhandle.reset();
00227             } else {
00228                 ret = ops->produceSend( meth, args, mcaller );
00229                 mhandle.reset( new SendHandleAlias( meth, ops->produceHandle(meth), ops->getPart(meth)) );
00230             }
00231         }
00232         catch( const wrong_number_of_args_exception& e )
00233             {
00234                 throw parse_exception_wrong_number_of_arguments
00235                     (obj, meth, e.wanted, e.received );
00236             }
00237         catch( const wrong_types_of_args_exception& e )
00238             {
00239                 throw parse_exception_wrong_type_of_argument
00240                     (obj, meth, e.whicharg, e.expected_, e.received_ );
00241             }
00242         catch( const std::exception& e)
00243         {
00244             throw parse_exception_fatal_semantic_error("While calling "+obj+"."+meth+": "+e.what());
00245         }
00246     }
00247     assert( ret.get() );
00248   }
00249 
00250   DataCallParser::~DataCallParser()
00251   {
00252     // if argparsers is not empty, then something went wrong during
00253     // the parsing ( someone threw an exception ), and we're
00254     // responsible for cleaning up the argparsers we created..
00255     while ( ! argparsers.empty() )
00256     {
00257       delete argparsers.top();
00258       argparsers.pop();
00259     };
00260   }
00261 
00262   ConstructorParser::ConstructorParser( ExpressionParser& p, CommonParser& cp)
00263       : commonparser(cp), expressionparser( p )
00264   {
00265     BOOST_SPIRIT_DEBUG_RULE( type_name );
00266     BOOST_SPIRIT_DEBUG_RULE( arguments );
00267 
00268     type_name =
00269         ( commonparser.type_name[ boost::bind( &ConstructorParser::seen_type_name, this, _1, _2 ) ] >> !arguments)[ boost::bind( &ConstructorParser::seen_constructor, this ) ];
00270   }
00271 
00272   ConstructorParser::~ConstructorParser()
00273   {
00274     // if argparsers is not empty, then something went wrong during
00275     // the parsing ( someone threw an exception ), and we're
00276     // responsible for cleaning up the argparsers we created..
00277     while ( ! argparsers.empty() )
00278     {
00279       delete argparsers.top();
00280       argparsers.pop();
00281     };
00282   }
00283 
00284 
00285   void ConstructorParser::seen_type_name( iter_t begin, iter_t end )
00286   {
00287       std::string name( begin, end );
00288       TypeInfo* type = Types()->type( name );
00289       if ( type == 0 )
00290           throw_(iter_t(), "\"" + name + "\" is an unknown type...");
00291 
00292       ArgumentsParser* argspar =
00293           new ArgumentsParser( expressionparser, 0, Service::shared_ptr(), name, "" );
00294 
00295       // keep hold of the argspar, we're still going to need it after
00296       // it's done its work..  ( in seen_constructor(), that is.. )
00297       argparsers.push( argspar );
00298 
00299       // set the arguments parser to the parser provided by the
00300       // ArgumentsParser we just created..
00301       arguments = argspar->parser();
00302 
00303   }
00304 
00305   void ConstructorParser::seen_constructor( void )
00306   {
00307     ArgumentsParser* argspar = argparsers.top();
00308     argparsers.pop();
00309     std::string obj = argspar->objectname();
00310     std::vector<DataSourceBase::shared_ptr> args = argspar->result();
00311     delete argspar;
00312 
00313     ret = TypeInfoRepository::Instance()->type( obj )->construct( args );
00314 
00315     if (!ret) {
00316         throw parse_exception_no_such_constructor( obj, args );
00317     }
00318 
00319   }
00320 
00322     static void abort_rule(const string& reason) {
00323         throw_(iter_t(), reason);
00324     }
00325 
00326     static error_status<> fail_rule(scanner_t const& scan, parser_error<std::string, iter_t>&e )
00327     {
00328         return error_status<>( error_status<>::fail );
00329     }
00332   ExpressionParser::ExpressionParser( TaskContext* pc, ExecutionEngine* caller, CommonParser& cp )
00333       : datacallparser( *this, cp, pc, caller ),
00334         constrparser(*this, cp),
00335         commonparser( cp ),
00336         valueparser( pc, cp ),
00337         _invert_time(false),
00338         opreg( OperatorRepository::Instance() ),
00339         context(pc)
00340   {
00341     BOOST_SPIRIT_DEBUG_RULE( expression );
00342     BOOST_SPIRIT_DEBUG_RULE( unarynotexp );
00343     BOOST_SPIRIT_DEBUG_RULE( unaryminusexp );
00344     BOOST_SPIRIT_DEBUG_RULE( unaryplusexp );
00345     BOOST_SPIRIT_DEBUG_RULE( div_or_mul );
00346     BOOST_SPIRIT_DEBUG_RULE( modexp );
00347     BOOST_SPIRIT_DEBUG_RULE( plus_or_min );
00348     BOOST_SPIRIT_DEBUG_RULE( smallereqexp );
00349     BOOST_SPIRIT_DEBUG_RULE( smallerexp );
00350     BOOST_SPIRIT_DEBUG_RULE( greatereqexp );
00351     BOOST_SPIRIT_DEBUG_RULE( greaterexp );
00352     BOOST_SPIRIT_DEBUG_RULE( equalexp );
00353     BOOST_SPIRIT_DEBUG_RULE( notequalexp );
00354     BOOST_SPIRIT_DEBUG_RULE( orexp );
00355     BOOST_SPIRIT_DEBUG_RULE( andexp );
00356     BOOST_SPIRIT_DEBUG_RULE( ifthenelseexp );
00357     BOOST_SPIRIT_DEBUG_RULE( groupexp );
00358     BOOST_SPIRIT_DEBUG_RULE( dotexp );
00359     BOOST_SPIRIT_DEBUG_RULE( atomicexpression );
00360     BOOST_SPIRIT_DEBUG_RULE( time_expression );
00361     BOOST_SPIRIT_DEBUG_RULE( time_spec );
00362     BOOST_SPIRIT_DEBUG_RULE( indexexp );
00363     BOOST_SPIRIT_DEBUG_RULE( comma );
00364     BOOST_SPIRIT_DEBUG_RULE( close_brace );
00365     BOOST_SPIRIT_DEBUG_RULE( value_expression );
00366     BOOST_SPIRIT_DEBUG_RULE( call_expression );
00367     BOOST_SPIRIT_DEBUG_RULE( constructor_expression );
00368 
00369     comma = expect_comma( ch_p(',') );
00370     close_brace = expect_close( ch_p(')') );
00371     expression = assignexp;
00372 
00373     // We parse expressions without regard of the types.  First we
00374     // parse the expressions, then we worry about whether what the
00375     // user says is actually valid.  You can try to add up two
00376     // booleans, and the parser will parse it, but it will notice
00377     // you're writing bogus when it tries to pass it to an operator
00378     // structure from Operators.hpp
00379 
00380     // TODO: implement the ifthenelse operator ?
00381     assignexp = andexp >> *( ch_p( '=' ) >> eps_p(~ch_p( '=' ))  // prevent parsing first '=' of "=="
00382             >> assignexp)[ bind( &ExpressionParser::seen_assign, this)];
00383     andexp =
00384       orexp >> *( ( str_p( "&&" ) ) >> orexp[
00385                     boost::bind( &ExpressionParser::seen_binary, this, "&&" ) ] );
00386     orexp =
00387       notequalexp >> *( ( str_p( "||" ) ) >> notequalexp[
00388                         boost::bind( &ExpressionParser::seen_binary, this, "||" ) ] );
00389     notequalexp =
00390       equalexp >> *( "!=" >> equalexp[
00391                        boost::bind( &ExpressionParser::seen_binary, this, "!=" ) ] );
00392     equalexp =
00393          greatereqexp
00394       >> *( "==" >> greatereqexp[
00395               boost::bind( &ExpressionParser::seen_binary, this, "==" ) ] );
00396     greatereqexp =
00397          greaterexp
00398       >> *( ">=" >> greaterexp[
00399               boost::bind( &ExpressionParser::seen_binary, this, ">=" ) ] );
00400     greaterexp =
00401          smallereqexp
00402       >> *( '>' >> smallereqexp[
00403               boost::bind( &ExpressionParser::seen_binary, this, ">" ) ] );
00404     smallereqexp =
00405          smallerexp
00406       >> *( "<=" >> smallerexp[
00407               boost::bind( &ExpressionParser::seen_binary, this, "<=" ) ] );
00408     smallerexp =
00409       plus_or_min >> *( '<' >> plus_or_min[
00410                        boost::bind( &ExpressionParser::seen_binary, this, "<" ) ] );
00411 
00412     plus_or_min =
00413               modexp >> *( ('-' >> modexp[
00414                     boost::bind( &ExpressionParser::seen_binary, this, "-" ) ] )
00415                | ('+' >> modexp[
00416                     boost::bind( &ExpressionParser::seen_binary, this, "+" ) ] ) );
00417 
00418     modexp =
00419       div_or_mul >> *( '%' >> div_or_mul[
00420                      boost::bind( &ExpressionParser::seen_binary, this, "%" ) ] );
00421     div_or_mul =
00422       unaryplusexp >> *( ('/' >> unaryplusexp[
00423             boost::bind( &ExpressionParser::seen_binary, this, "/" ) ] )
00424        | ('*' >> unaryplusexp[
00425             boost::bind( &ExpressionParser::seen_binary, this, "*" ) ] ) );
00426 
00427     unaryplusexp =
00428         '+' >> unaryminusexp[
00429           boost::bind( &ExpressionParser::seen_unary, this, "+" ) ]
00430       | unaryminusexp;
00431     unaryminusexp =
00432         '-' >> unarynotexp[
00433           boost::bind( &ExpressionParser::seen_unary, this, "-" ) ]
00434       | unarynotexp;
00435     unarynotexp =
00436         ch_p('!') >> atomicexpression[
00437             boost::bind( &ExpressionParser::seen_unary, this, "!" ) ]
00438         | atomicexpression;
00439 
00440     // note the order is important: commonparser.identifier throws a
00441     // useful "cannot use x as identifier" error if it fails, so we
00442     // must first show all non-identifier rules.
00443     atomicexpression = (
00444         // A parenthesis group.
00445       groupexp
00446         // or a time expression
00447       | time_expression
00448         // or a constant or user-defined value..
00449       | value_expression
00450       | constructor_expression
00451       | call_expression
00452         // or an index or dot expression
00453         ) >> *( dotexp | indexexp);
00454 
00455     constructor_expression = my_guard( constrparser.parser()[ boost::bind(&ExpressionParser::seenconstructor, this)])[&fail_rule];
00456 
00457     // if it's value.keyword then pass it on to the call_expression.
00458     value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &fail_rule ]
00459                                                         [ bind( &ExpressionParser::seenvalue, this ) ];
00460     call_expression  = my_guard( datacallparser.parser() )[&fail_rule]
00461                                 [bind( &ExpressionParser::seendatacall, this ) ];
00462     // take index of an atomicexpression
00463     indexexp =
00464         (ch_p('[') >> expression[bind(&ExpressionParser::seen_index, this)] >> expect_close( ch_p( ']') ) );
00465 
00466     dotexp =
00467         ( ch_p('.') >> commonparser.identifier[ boost::bind(&ExpressionParser::seen_dotmember, this, _1, _2)]);
00468 
00469     // needs no semantic action, its result is already on top of
00470     // the stack, where it should be..
00471     groupexp = '(' >> expression >> close_brace;
00472 
00473     // the day i find a clean way to temporarily disable 'eol' skipping, a lot of
00474     // grammar will look better...
00475     time_expression =
00476         (str_p("time")>>eps_p(~commonparser.identchar | eol_p | end_p ))[bind(&ExpressionParser::seentimeexpr, this)]
00477         |
00478         ( (eps_p[boost::lambda::var(commonparser.skipeol) = false] >> uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
00479            >> (str_p( "s" ) | "ms" | "us" | "ns" )[boost::lambda::var(commonparser.skipeol) = true][boost::bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ])
00480           | (eps_p[boost::lambda::var(commonparser.skipeol) = true] >> nothing_p) // eps_p succeeds always, then fail.
00481           )
00482           ; // enable skipeol.
00483 
00484 //         >> expect_timespec( (( str_p( ">=" ) | ">" )
00485 //                             |
00486 //                             (str_p("<=") | "<")[bind( &ExpressionParser::inverttime, this)])
00487 //         >> time_spec);
00488 
00489 //     time_spec =
00490 //         ( uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
00491 //         >>
00492 //       ( str_p( "s" ) | "ms" | "us" | "ns" )[
00493 //         bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ] ) | expression[bind(&ExpressionParser::seentimeexpr, this)];
00494 
00495   };
00496 
00497     void ExpressionParser::inverttime()
00498     {
00499         _invert_time = true;
00500     }
00501 
00502     void ExpressionParser::seentimeexpr()
00503     {
00504         parsestack.push( new DataSourceTime() );
00505 
00506 //         DataSourceBase::shared_ptr res = parsestack.top();
00507 //         parsestack.pop();
00508 //         DataSource<double>::shared_ptr dres = dynamic_cast<DataSource<double>*>( res.get() );
00509 //         if ( !dres )
00510 //             throw parse_exception_semantic_error("Expected time in seconds but expression is not a floating point number.");
00511 //         DataSourceBase::shared_ptr dsb( new DataSourceCondition( new ConditionDSDuration( dres, _invert_time ) ) );
00512 //         _invert_time = false;
00513 //         parsestack.push( dsb );
00514     }
00515 
00516   void ExpressionParser::seentimeunit( iter_t begin, iter_t end)
00517   {
00518     // the string starting at begin, ending at end is either ms, us,
00519     // ns or s, so we only need to check the first letter...
00520       // Convert to seconds...
00521       TimeService::Seconds total = 0;
00522     switch( *begin )
00523     {
00524     case 's': total = TimeService::Seconds(tsecs);
00525         break;
00526     case 'm': total = tsecs / 1000.0;
00527         break;
00528     case 'u': total = tsecs / 1000000.0;
00529         break;
00530     case 'n': total = tsecs / 1000000000.0;
00531         break;
00532     default:
00533         std::string arg(begin, end);
00534         throw parse_exception_semantic_error("Expected time expression 's', 'ms', 'us' or 'ns' after integer value, got "+arg);
00535     };
00536 
00537     parsestack.push( new ConstantDataSource<double>( total ) );
00538 
00539 //     DataSourceBase::shared_ptr dsb( new DataSourceCondition(
00540 //       new ConditionDuration( total, _invert_time ) ) );
00541 //     _invert_time = false;
00542 //     parsestack.push( dsb );
00543   }
00544 
00545   void ExpressionParser::seentimespec( int n )
00546   {
00547     tsecs = n;
00548   }
00549 
00550   void ExpressionParser::seenvalue()
00551   {
00552     DataSourceBase::shared_ptr ds = valueparser.lastParsed();
00553     parsestack.push( ds );
00554   }
00555 
00556   void ExpressionParser::seendatacall()
00557   {
00558       DataSourceBase::shared_ptr n( datacallparser.getParseResult() );
00559       parsestack.push( n );
00560       mhandle = datacallparser.getParseHandle();
00561   }
00562 
00563   void ExpressionParser::seenconstructor()
00564   {
00565       DataSourceBase::shared_ptr n( constrparser.getParseResult() );
00566       parsestack.push( n );
00567   }
00568 
00569   ExpressionParser::~ExpressionParser()
00570   {
00571       // if parsestack is not empty, then something went wrong, someone
00572       // threw an exception, so we clean up..
00573       while ( !parsestack.empty() )
00574           parsestack.pop();
00575   }
00576 
00577   rule_t& ExpressionParser::parser()
00578   {
00579     return expression;
00580   }
00581 
00582   DataSourceBase::shared_ptr ExpressionParser::getResult()
00583   {
00584     assert( !parsestack.empty() );
00585     return parsestack.top();
00586   }
00587 
00588   boost::shared_ptr<AttributeBase> ExpressionParser::getHandle()
00589   {
00590     assert( !parsestack.empty() );
00591     return mhandle;
00592   }
00593 
00594   void ExpressionParser::seen_unary( const std::string& op )
00595   {
00596     DataSourceBase::shared_ptr arg( parsestack.top() );
00597     parsestack.pop();
00598     DataSourceBase::shared_ptr ret =
00599         opreg->applyUnary( op, arg.get() );
00600     if ( ! ret )
00601         throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op +
00602                                                     "\" to " + arg->getType() +"." );
00603     parsestack.push( ret );
00604   }
00605 
00606   void ExpressionParser::seen_dotmember( iter_t s, iter_t f )
00607   {
00608       std::string member(s,f);
00609       // inspirired on seen_unary
00610     DataSourceBase::shared_ptr arg( parsestack.top() );
00611     parsestack.pop();
00612     DataSourceBase::shared_ptr ret = arg->getMember(member);
00613     if ( ! ret )
00614       throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member +
00615                                             "\"." );
00616     parsestack.push( ret );
00617   }
00618 
00619   void ExpressionParser::seen_binary( const std::string& op )
00620   {
00621     DataSourceBase::shared_ptr arg1( parsestack.top() );
00622     parsestack.pop();
00623     DataSourceBase::shared_ptr arg2( parsestack.top() );
00624     parsestack.pop();
00625 
00626     // Arg2 is the first (!) argument, as it was pushed on the stack
00627     // first.
00628     DataSourceBase::shared_ptr ret =
00629       opreg->applyBinary( op, arg2.get(), arg1.get() );
00630     if ( ! ret )
00631       throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op +
00632                                             " "+arg1->getType() +"." );
00633     parsestack.push( ret );
00634   }
00635 
00636   void ExpressionParser::seen_assign()
00637   {
00638     DataSourceBase::shared_ptr arg1( parsestack.top() );
00639     parsestack.pop(); // right hand side
00640     DataSourceBase::shared_ptr arg2( parsestack.top() );
00641     parsestack.pop(); // left hand side
00642 
00643     // hack to drop-in a new instance of SendHandle:
00644     if (arg2->getTypeName() == "SendHandle" && mhandle) {
00645 //        cout << "Trying to replace SendHandle/..."<<endl;
00646         ConfigurationInterface::AttributeObjects attrs = context->attributes()->getValues();
00647         for( ConfigurationInterface::AttributeObjects::iterator it = attrs.begin(); it != attrs.end(); ++it) {
00648             if ( (*it)->getDataSource() == arg2 ) { // since the parsestack only saves the DSB, we need to do lookup by DSB and not by name :-(
00649 //                cout << "Found !"<<endl;
00650                 string name = (*it)->getName();
00651                 context->attributes()->removeAttribute(name);
00652                 AttributeBase* var = mhandle->clone();
00653                 var->setName( name ); // fill in the final handle name.
00654                 context->attributes()->setValue( var );
00655                 arg2 = var->getDataSource(); // frees up dummy and puts real one in place.
00656                 break;
00657             }
00658         }
00659     }
00660 
00661     DataSourceBase::shared_ptr ret;
00662     ActionInterface* act = 0;
00663     try {
00664         act = arg2->updateAction( arg1.get() );
00665     } catch(...) { // bad assignment
00666         throw parse_exception_fatal_semantic_error( "Incompatible types. Cannot assign: "+ arg2->getType() +" = " +
00667                 " "+arg1->getType() +"." );
00668     }
00669     if (!act)
00670         throw parse_exception_fatal_semantic_error( "2:Cannot assign constant (or returned) variable of types: "+ arg2->getType() +" = " +
00671                 " "+arg1->getType() );
00672     // only try this if not unknown_t.
00673     if (arg2->getTypeInfo()->getTypeName() != "unknown_t")
00674         ret = arg2->getTypeInfo()->buildActionAlias(act, arg2);
00675     if (!ret) { // no type info !
00676         ret = new DataSourceCommand( act ); // fall back into the old behavior of returning a boolean.
00677     }
00678     parsestack.push( ret );
00679   }
00680 
00681   void ExpressionParser::seen_index()
00682   {
00683     DataSourceBase::shared_ptr arg1( parsestack.top() );
00684     parsestack.pop();
00685     DataSourceBase::shared_ptr arg2( parsestack.top() );
00686     parsestack.pop();
00687 
00688     // Arg2 is the first (!) argument, as it was pushed on the stack
00689     // first.
00690     DataSourceBase::shared_ptr ret = arg2->getMember( arg1, 0 );
00691     if ( ! ret )
00692       throw parse_exception_fatal_semantic_error( "Illegal use of []: "+ arg2->getType() +"[ "
00693                                                 +arg1->getType() +" ]." );
00694     parsestack.push( ret );
00695   }
00696 
00697   void ExpressionParser::dropResult()
00698   {
00699     parsestack.pop();
00700   }
00701 }