Orocos Real-Time Toolkit  2.9.0
ExpressionParser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ExpressionParser.cxx
3 
4  ExpressionParser.cxx - description
5  -------------------
6  begin : Mon May 10 2004
7  copyright : (C) 2004 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, *
24  * Suite 330, Boston, MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 #include "parser-debug.hpp"
29 #include "parse_exception.hpp"
30 
31 #ifdef ORO_PRAGMA_INTERFACE
32 #pragma implementation
33 #endif
34 #include "ExpressionParser.hpp"
35 //#include "DumpObject.hpp"
36 
37 #include "ArgumentsParser.hpp"
38 #include "../types/Operators.hpp"
39 #include "DataSourceCondition.hpp"
40 #include "../internal/DataSourceCommand.hpp"
41 #include "CmdFunction.hpp"
42 #include "../internal/GlobalService.hpp"
43 #include "CommandDataSource.hpp"
44 
45 #include "DataSourceTime.hpp"
46 #include "../TaskContext.hpp"
47 #include "PeerParser.hpp"
48 #include "../types/Types.hpp"
49 #include "SendHandleAlias.hpp"
50 
51 #include <boost/lambda/lambda.hpp>
52 
53 #include <boost/bind.hpp>
54 #include <boost/ref.hpp>
55 #include "rtt-scripting-config.h"
56 #include <iostream>
57 
58 namespace RTT
59 {
60  using boost::bind;
61  using boost::ref;
62 
63  using namespace detail;
64  using namespace std;
65 
66  namespace {
67  boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
68  boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected ( or could not find out what this line means ).");
69  boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type.");
70  boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression.");
71  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
72  boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the value.");
73  boost::spirit::classic::assertion<std::string> expect_comma("Expected the ',' separator after expression.");
74  boost::spirit::classic::assertion<std::string> expect_timespec("Expected a time specification (e.g. > 10s or > varname ) after 'time' .");
75 
76  guard<std::string> my_guard;
77  }
78 
79 
80 
82  : ret(), mhandle(), mcmdcnd(0), mobject(), mmethod(),
83  mcaller( caller ? caller : c->engine()), mcalltype(DEFAULT_CALLTYPE), commonparser(cp), expressionparser( p ),
84  peerparser( c, cp, false ) // accept partial paths
85  {
86  BOOST_SPIRIT_DEBUG_RULE( datacall );
87  BOOST_SPIRIT_DEBUG_RULE( arguments );
88  BOOST_SPIRIT_DEBUG_RULE( peerpath );
89  BOOST_SPIRIT_DEBUG_RULE( object );
90  BOOST_SPIRIT_DEBUG_RULE( method );
91 
92  // this parser uses a neat boost.spirit trick to avoid keeping
93  // loads of stacks for all parsing data ( this parser needs to be
94  // reentrant because it can be called while parsing an argument of
95  // a datacall, which has itself been called while parsing an
96  // argument of a datacall... ). Boost.Spirit allows you to change
97  // the parser that a rule points to at runtime, so we only create
98  // the parser just before it's going to be used, when we know what
99  // arguments we want.. See the ArgumentsParser doc for more
100  // details..
101  peerpath = peerparser.locator();
102  object= (commonparser.identifier >> ".")[boost::bind(&DataCallParser::seenobjectname, this, _1, _2)];
103  method= ( commonparser.keyword | expect_ident(commonparser.tidentifier))[boost::bind( &DataCallParser::seenmethodname, this, _1, _2 ) ]; // may be send, call or method name.
104  datacall =
105  ( peerpath >> !object >> method[ boost::bind( &DataCallParser::seendataname, this ) ] >> !arguments)[ boost::bind( &DataCallParser::seendatacall, this ) ];
106  }
107 
108  void DataCallParser::seenobjectname( iter_t begin, iter_t end )
109  {
110  std::string name( begin, end );
111  mobject = name.substr(0, name.length() - 1);
112  }
113 
114  void DataCallParser::seenmethodname( iter_t begin, iter_t end )
115  {
116  std::string name( begin, end );
117  if ( name == "send" ) {
118  mcalltype = CALLTYPE_SEND;
119  mmethod = mobject;
120  mobject.clear();
121  } else if (name == "cmd" ) {
122  mcalltype = CALLTYPE_CMD;
123  mmethod = mobject;
124  mobject.clear();
125  } else if (name == "call" ) {
126  mcalltype = CALLTYPE_CALL;
127  mmethod = mobject;
128  mobject.clear();
129  } else {
130  mcalltype = DEFAULT_CALLTYPE;
131  mmethod = name;
132  }
133 // cout << "seenmethodname "<< mobject << "." << mmethod<<endl;
134  }
135 
136  void DataCallParser::seendataname()
137  {
138  // re-init mobject, might have been cleared during parsing of send(), cmd() or call().
139  mobject = peerparser.object();
140  TaskContext* peer = peerparser.peer();
141  Service::shared_ptr ops = peerparser.taskObject();
142  peerparser.reset();
143 // cout << "seendataname "<< mobject << "." << mmethod<<endl;
144  if (true) {
145  // it ain't...
146  // set the proper object name again in case of a send()
147  if ( (mcalltype != DEFAULT_CALLTYPE) && ops)
148  mobject = ops->getName();
149 // cout << "DCP saw method "<< mmethod <<" of object "<<mobject<<" of peer "<<peer->getName()<<endl;
150  // Check sanity of what we parsed:
151  if (mmethod != "collect" && mmethod != "collectIfDone" ) {
152  if ( ops == 0 || (mobject != "this" && ops->getName() != mobject ) ) {
153  throw parse_exception_no_such_component( peer->getName(), mobject);
154  }
155  // Check if method exists on current object:
156  if ( ops->hasMember(mmethod) == false ) {
157  // Check if it is a method of the global service:
158  if ( ops == peerparser.taskObject() && GlobalService::Instance()->hasMember(mmethod) ) {
159  mobject = "GlobalService";
160  ops = GlobalService::Instance();
161  } else {
162  if ( ops == peerparser.taskObject() && ops->hasService("scripting") && ops->provides("scripting")->hasMember(mmethod) ) {
163  mobject = "scripting";
164  ops = ops->provides("scripting");
165  } else {
166  //DumpObject( peer );
167  if ( mobject != "this" )
168  throw parse_exception_no_such_method_on_component( mobject, mmethod );
169  else
170  throw parse_exception_no_such_method_on_component( peer->getName(), mmethod );
171  }
172  }
173  }
174  }
175  }
176 
177  // create an argument parser for the call..
178  // Store everything in the ArgumentsParser ! This DataCallParser instance is recursively called !
179  ArgumentsParser* argspar =
180  new ArgumentsParser( expressionparser, peer, ops,
181  mobject, mmethod );
182  // we no longer need these two..
183  mobject.clear();
184  mmethod.clear();
185  mcmdcnd = 0;
186 
187  // keep hold of the argspar, we're still going to need it after
188  // it's done its work.. ( in seendatacall(), that is.. )
189  argparsers.push( argspar );
190 
191  // set the arguments parser to the parser provided by the
192  // ArgumentsParser we just created..
193  arguments = argspar->parser();
194  }
195 
196  void DataCallParser::seendatacall()
197  {
198  ArgumentsParser* argspar = argparsers.top();
199  argparsers.pop();
200  std::string obj = argspar->objectname();
201  std::string meth = argspar->methodname();
202  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
203  Service::shared_ptr peer = argspar->object();
204  delete argspar;
205  assert(peer && "peer may never be null.");
206 // cout << "seendatacall "<< mobject << "." << mmethod<<endl;
207 
208  if ( true ) {
209  // plain method or collect/collectIfDone
210 
211  Service::shared_ptr ops = peer;
212  // we already checked for the existence of this object and method
213  // in seendataname()..
214  peerparser.reset();
215 
216  try {
217  if ( (meth == "collect" || meth == "collectIfDone") && !ops->hasMember(mmethod) ) {
218  if ( ops->hasAttribute(obj) ) {
219  SendHandleAlias* sha = dynamic_cast<SendHandleAlias*>( peer->getValue(obj) );
220  if (sha) {
221  // add SendHandle DS for Collect:
222  args.insert( args.begin(), sha->getDataSource() );
223  if (meth == "collect")
224  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(true) );// blocking
225  else // (meth == "collectIfDone")
226  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(false) );// non-blocking
227  return;
228  }
229  }
230  throw parse_exception_fatal_semantic_error( obj + "."+meth +": "+ obj +" is not a valid SendHandle object.");
231  }
232 
233  unsigned int arity = ops->getCollectArity(meth);
234  switch(mcalltype) {
235  case DEFAULT_CALLTYPE:
236  case CALLTYPE_CALL:
237  ret = ops->produce( meth, args, mcaller );
238  mhandle.reset();
239  break;
240  case CALLTYPE_SEND:
241  ret = ops->produceSend( meth, args, mcaller );
242  mhandle.reset( new SendHandleAlias( meth, ops->produceHandle(meth), ops->getPart(meth)) );
243  break;
244  case CALLTYPE_CMD:
245  DataSourceBase::shared_ptr sendds = ops->produceSend( meth, args, mcaller );
246  args.clear();
247  args.push_back( sendds ); // store the produceSend DS for collecting:
248  for ( unsigned int i =0; i != arity; ++i) {
249  args.push_back( ops->getOperation(meth)->getCollectType( i + 1 )->buildValue() ); // this is only to satisfy produceCollect. We ignore the results...
250  }
251 
253  = boost::dynamic_pointer_cast<DataSource<SendStatus> >(
254  ops->produceCollect( meth, args, new ValueDataSource<bool>(false) )
255  ); // non-blocking, need extra condition
256  assert(collectds);
257 
258  ret = new ActionAliasDataSource<SendStatus>(new CommandDataSource( sendds ), collectds.get() );
259  mcmdcnd = new CmdCollectCondition( collectds ); // Replaces RTT 1.x completion condition.
260  break;
261  }
262  }
263  catch( const wrong_number_of_args_exception& e )
264  {
266  (obj, meth, e.wanted, e.received );
267  }
268  catch( const wrong_types_of_args_exception& e )
269  {
271  (obj, meth, e.whicharg, e.expected_, e.received_ );
272  }
273  catch( const std::exception& e)
274  {
275  throw parse_exception_fatal_semantic_error("While calling "+obj+"."+meth+": "+e.what());
276  }
277  }
278  assert( ret.get() );
279  }
280 
282  {
283  // if argparsers is not empty, then something went wrong during
284  // the parsing ( someone threw an exception ), and we're
285  // responsible for cleaning up the argparsers we created..
286  while ( ! argparsers.empty() )
287  {
288  delete argparsers.top();
289  argparsers.pop();
290  }
291  }
292 
294  : commonparser(cp), expressionparser( p )
295  {
296  BOOST_SPIRIT_DEBUG_RULE( type_name );
297  BOOST_SPIRIT_DEBUG_RULE( arguments );
298 
299  type_name =
300  ( commonparser.type_name[ boost::bind( &ConstructorParser::seen_type_name, this, _1, _2 ) ] >> !arguments)[ boost::bind( &ConstructorParser::seen_constructor, this ) ];
301  }
302 
304  {
305  // if argparsers is not empty, then something went wrong during
306  // the parsing ( someone threw an exception ), and we're
307  // responsible for cleaning up the argparsers we created..
308  while ( ! argparsers.empty() )
309  {
310  delete argparsers.top();
311  argparsers.pop();
312  }
313  }
314 
315 
317  {
318  std::string name( begin, end );
319  TypeInfo* type = Types()->type( name );
320  if ( type == 0 )
321  throw_(iter_t(), "\"" + name + "\" is an unknown type...");
322 
323  ArgumentsParser* argspar =
324  new ArgumentsParser( expressionparser, 0, Service::shared_ptr(), name, "" );
325 
326  // keep hold of the argspar, we're still going to need it after
327  // it's done its work.. ( in seen_constructor(), that is.. )
328  argparsers.push( argspar );
329 
330  // set the arguments parser to the parser provided by the
331  // ArgumentsParser we just created..
332  arguments = argspar->parser();
333 
334  }
335 
337  {
338  ArgumentsParser* argspar = argparsers.top();
339  argparsers.pop();
340  std::string obj = argspar->objectname();
341  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
342  delete argspar;
343 
344  ret = TypeInfoRepository::Instance()->type( obj )->construct( args );
345 
346  if (!ret) {
347  throw parse_exception_no_such_constructor( obj, args );
348  }
349 
350  }
351 
353  static void abort_rule(const string& reason) {
354  throw_(iter_t(), reason);
355  }
356 
357  static error_status<> fail_rule(scanner_t const& scan, parser_error<std::string, iter_t>&e )
358  {
359  return error_status<>( error_status<>::fail );
360  }
364  : mcmdcnd(0),
365  datacallparser( *this, cp, pc, caller ),
366  constrparser(*this, cp),
367  commonparser( cp ),
368  valueparser( pc, cp ),
369  _invert_time(false),
370  opreg( OperatorRepository::Instance() ),
371  context(pc)
372  {
373  BOOST_SPIRIT_DEBUG_RULE( expression );
374  BOOST_SPIRIT_DEBUG_RULE( unarynotexp );
375  BOOST_SPIRIT_DEBUG_RULE( unaryminusexp );
376  BOOST_SPIRIT_DEBUG_RULE( unaryplusexp );
377  BOOST_SPIRIT_DEBUG_RULE( div_or_mul );
378  BOOST_SPIRIT_DEBUG_RULE( modexp );
379  BOOST_SPIRIT_DEBUG_RULE( plus_or_min );
380  BOOST_SPIRIT_DEBUG_RULE( smallereqexp );
381  BOOST_SPIRIT_DEBUG_RULE( smallerexp );
382  BOOST_SPIRIT_DEBUG_RULE( greatereqexp );
383  BOOST_SPIRIT_DEBUG_RULE( greaterexp );
384  BOOST_SPIRIT_DEBUG_RULE( equalexp );
385  BOOST_SPIRIT_DEBUG_RULE( notequalexp );
386  BOOST_SPIRIT_DEBUG_RULE( orexp );
387  BOOST_SPIRIT_DEBUG_RULE( andexp );
388  BOOST_SPIRIT_DEBUG_RULE( ifthenelseexp );
389  BOOST_SPIRIT_DEBUG_RULE( groupexp );
390  BOOST_SPIRIT_DEBUG_RULE( dotexp );
391  BOOST_SPIRIT_DEBUG_RULE( atomicexpression );
392  BOOST_SPIRIT_DEBUG_RULE( time_expression );
393  BOOST_SPIRIT_DEBUG_RULE( time_spec );
394  BOOST_SPIRIT_DEBUG_RULE( indexexp );
395  BOOST_SPIRIT_DEBUG_RULE( comma );
396  BOOST_SPIRIT_DEBUG_RULE( close_brace );
397  BOOST_SPIRIT_DEBUG_RULE( value_expression );
398  BOOST_SPIRIT_DEBUG_RULE( call_expression );
399  BOOST_SPIRIT_DEBUG_RULE( constructor_expression );
400 
401  comma = expect_comma( ch_p(',') );
402  close_brace = expect_close( ch_p(')') );
403  expression = assignexp;
404 
405  // We parse expressions without regard of the types. First we
406  // parse the expressions, then we worry about whether what the
407  // user says is actually valid. You can try to add up two
408  // booleans, and the parser will parse it, but it will notice
409  // you're writing bogus when it tries to pass it to an operator
410  // structure from Operators.hpp
411 
412  // TODO: implement the ifthenelse operator ?
413  assignexp = andexp >> *( ch_p( '=' ) >> eps_p(~ch_p( '=' )) // prevent parsing first '=' of "=="
414  >> assignexp)[ bind( &ExpressionParser::seen_assign, this)];
415  andexp =
416  orexp >> *( ( str_p( "&&" ) ) >> orexp[
417  boost::bind( &ExpressionParser::seen_binary, this, "&&" ) ] );
418  orexp =
419  notequalexp >> *( ( str_p( "||" ) ) >> notequalexp[
420  boost::bind( &ExpressionParser::seen_binary, this, "||" ) ] );
421  notequalexp =
422  equalexp >> *( "!=" >> equalexp[
423  boost::bind( &ExpressionParser::seen_binary, this, "!=" ) ] );
424  equalexp =
425  greatereqexp
426  >> *( "==" >> greatereqexp[
427  boost::bind( &ExpressionParser::seen_binary, this, "==" ) ] );
428  greatereqexp =
429  greaterexp
430  >> *( ">=" >> greaterexp[
431  boost::bind( &ExpressionParser::seen_binary, this, ">=" ) ] );
432  greaterexp =
433  smallereqexp
434  >> *( '>' >> smallereqexp[
435  boost::bind( &ExpressionParser::seen_binary, this, ">" ) ] );
436  smallereqexp =
437  smallerexp
438  >> *( "<=" >> smallerexp[
439  boost::bind( &ExpressionParser::seen_binary, this, "<=" ) ] );
440  smallerexp =
441  plus_or_min >> *( '<' >> plus_or_min[
442  boost::bind( &ExpressionParser::seen_binary, this, "<" ) ] );
443 
444  plus_or_min =
445  modexp >> *( ('-' >> modexp[
446  boost::bind( &ExpressionParser::seen_binary, this, "-" ) ] )
447  | ('+' >> modexp[
448  boost::bind( &ExpressionParser::seen_binary, this, "+" ) ] ) );
449 
450  modexp =
451  div_or_mul >> *( '%' >> div_or_mul[
452  boost::bind( &ExpressionParser::seen_binary, this, "%" ) ] );
453  div_or_mul =
454  unaryplusexp >> *( ('/' >> unaryplusexp[
455  boost::bind( &ExpressionParser::seen_binary, this, "/" ) ] )
456  | ('*' >> unaryplusexp[
457  boost::bind( &ExpressionParser::seen_binary, this, "*" ) ] ) );
458 
459  unaryplusexp =
460  '+' >> unaryminusexp[
461  boost::bind( &ExpressionParser::seen_unary, this, "+" ) ]
462  | unaryminusexp;
463  unaryminusexp =
464  '-' >> unarynotexp[
465  boost::bind( &ExpressionParser::seen_unary, this, "-" ) ]
466  | unarynotexp;
467  unarynotexp =
468  ch_p('!') >> atomicexpression[
469  boost::bind( &ExpressionParser::seen_unary, this, "!" ) ]
470  | atomicexpression;
471 
472  // note the order is important: commonparser.identifier throws a
473  // useful "cannot use x as identifier" error if it fails, so we
474  // must first show all non-identifier rules.
475  atomicexpression = (
476  // A parenthesis group.
477  groupexp
478  // or a time expression
479  | time_expression
480  // or a constant or user-defined value..
481  | value_expression
482  | constructor_expression
483  | call_expression
484  // or an index or dot expression
485  ) >> *( dotexp | indexexp);
486 
487  constructor_expression = my_guard( constrparser.parser()[ boost::bind(&ExpressionParser::seenconstructor, this)])[&fail_rule];
488 
489  // if it's value.keyword then pass it on to the call_expression.
490  value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &fail_rule ]
491  [ bind( &ExpressionParser::seenvalue, this ) ];
492  call_expression = my_guard( datacallparser.parser() )[&fail_rule]
493  [bind( &ExpressionParser::seendatacall, this ) ];
494  // take index of an atomicexpression
495  indexexp =
496  (ch_p('[') >> expression[bind(&ExpressionParser::seen_index, this)] >> expect_close( ch_p( ']') ) );
497 
498  dotexp =
499  ( ch_p('.') >> commonparser.identifier[ boost::bind(&ExpressionParser::seen_dotmember, this, _1, _2)]);
500 
501  // needs no semantic action, its result is already on top of
502  // the stack, where it should be..
503  groupexp = '(' >> expression >> close_brace;
504 
505  // the day i find a clean way to temporarily disable 'eol' skipping, a lot of
506  // grammar will look better...
507  time_expression =
508  (str_p("time")>>eps_p(~commonparser.identchar | eol_p | end_p ))[bind(&ExpressionParser::seentimeexpr, this)]
509  |
510  ( (eps_p[boost::lambda::var(commonparser.skipeol) = false] >> uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
511  >> (str_p( "s" ) | "ms" | "us" | "ns" )[boost::lambda::var(commonparser.skipeol) = true][boost::bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ])
512  | (eps_p[boost::lambda::var(commonparser.skipeol) = true] >> nothing_p) // eps_p succeeds always, then fail.
513  )
514  ; // enable skipeol.
515 
516 // >> expect_timespec( (( str_p( ">=" ) | ">" )
517 // |
518 // (str_p("<=") | "<")[bind( &ExpressionParser::inverttime, this)])
519 // >> time_spec);
520 
521 // time_spec =
522 // ( uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
523 // >>
524 // ( str_p( "s" ) | "ms" | "us" | "ns" )[
525 // bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ] ) | expression[bind(&ExpressionParser::seentimeexpr, this)];
526 
527  }
528 
529  void ExpressionParser::inverttime()
530  {
531  _invert_time = true;
532  }
533 
534  void ExpressionParser::seentimeexpr()
535  {
536  parsestack.push( new DataSourceTime() );
537 
538 // DataSourceBase::shared_ptr res = parsestack.top();
539 // parsestack.pop();
540 // DataSource<double>::shared_ptr dres = dynamic_cast<DataSource<double>*>( res.get() );
541 // if ( !dres )
542 // throw parse_exception_semantic_error("Expected time in seconds but expression is not a floating point number.");
543 // DataSourceBase::shared_ptr dsb( new DataSourceCondition( new ConditionDSDuration( dres, _invert_time ) ) );
544 // _invert_time = false;
545 // parsestack.push( dsb );
546  }
547 
548  void ExpressionParser::seentimeunit( iter_t begin, iter_t end)
549  {
550  // the string starting at begin, ending at end is either ms, us,
551  // ns or s, so we only need to check the first letter...
552  // Convert to seconds...
553  TimeService::Seconds total = 0;
554  switch( *begin )
555  {
556  case 's': total = TimeService::Seconds(tsecs);
557  break;
558  case 'm': total = tsecs / 1000.0;
559  break;
560  case 'u': total = tsecs / 1000000.0;
561  break;
562  case 'n': total = tsecs / 1000000000.0;
563  break;
564  default:
565  std::string arg(begin, end);
566  throw parse_exception_semantic_error("Expected time expression 's', 'ms', 'us' or 'ns' after integer value, got "+arg);
567  }
568 
569  parsestack.push( new ConstantDataSource<double>( total ) );
570 
571 // DataSourceBase::shared_ptr dsb( new DataSourceCondition(
572 // new ConditionDuration( total, _invert_time ) ) );
573 // _invert_time = false;
574 // parsestack.push( dsb );
575  }
576 
577  void ExpressionParser::seentimespec( int n )
578  {
579  tsecs = n;
580  }
581 
582  void ExpressionParser::seenvalue()
583  {
584  DataSourceBase::shared_ptr ds = valueparser.lastParsed();
585  parsestack.push( ds );
586  }
587 
588  void ExpressionParser::seendatacall()
589  {
590  DataSourceBase::shared_ptr n( datacallparser.getParseResult() );
591  parsestack.push( n );
592  mhandle = datacallparser.getParseHandle();
593  mcmdcnd = datacallparser.getParseCmdResult();
594  }
595 
596  void ExpressionParser::seenconstructor()
597  {
598  DataSourceBase::shared_ptr n( constrparser.getParseResult() );
599  parsestack.push( n );
600  }
601 
603  {
604  // if parsestack is not empty, then something went wrong, someone
605  // threw an exception, so we clean up..
606  while ( !parsestack.empty() )
607  parsestack.pop();
608  }
609 
611  {
612  return expression;
613  }
614 
616  {
617  assert( !parsestack.empty() );
618  return parsestack.top();
619  }
620 
622  {
623  assert( !parsestack.empty() );
624  return mcmdcnd;
625  }
626 
627  boost::shared_ptr<AttributeBase> ExpressionParser::getHandle()
628  {
629  assert( !parsestack.empty() );
630  return mhandle;
631  }
632 
633  void ExpressionParser::seen_unary( const std::string& op )
634  {
635  DataSourceBase::shared_ptr arg( parsestack.top() );
636  parsestack.pop();
638  opreg->applyUnary( op, arg.get() );
639  if ( ! ret )
640  throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op +
641  "\" to " + arg->getType() +"." );
642  parsestack.push( ret );
643  }
644 
645  void ExpressionParser::seen_dotmember( iter_t s, iter_t f )
646  {
647  std::string member(s,f);
648  // inspirired on seen_unary
649  DataSourceBase::shared_ptr arg( parsestack.top() );
650  parsestack.pop();
651  DataSourceBase::shared_ptr ret = arg->getMember(member);
652  if ( ! ret )
653  throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member +
654  "\"." );
655  parsestack.push( ret );
656  }
657 
658  void ExpressionParser::seen_binary( const std::string& op )
659  {
660  DataSourceBase::shared_ptr arg1( parsestack.top() );
661  parsestack.pop();
662  DataSourceBase::shared_ptr arg2( parsestack.top() );
663  parsestack.pop();
664 
665  // Arg2 is the first (!) argument, as it was pushed on the stack
666  // first.
668  opreg->applyBinary( op, arg2.get(), arg1.get() );
669  if ( ! ret )
670  throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op +
671  " "+arg1->getType() +"." );
672  parsestack.push( ret );
673  }
674 
675  void ExpressionParser::seen_assign()
676  {
677  DataSourceBase::shared_ptr arg1( parsestack.top() );
678  parsestack.pop(); // right hand side
679  DataSourceBase::shared_ptr arg2( parsestack.top() );
680  parsestack.pop(); // left hand side
681 
682  // hack to drop-in a new instance of SendHandle:
683  if (arg2->getTypeName() == "SendHandle" && mhandle) {
684 // cout << "Trying to replace SendHandle/..."<<endl;
686  for( ConfigurationInterface::AttributeObjects::iterator it = attrs.begin(); it != attrs.end(); ++it) {
687  if ( (*it)->getDataSource() == arg2 ) { // since the parsestack only saves the DSB, we need to do lookup by DSB and not by name :-(
688 // cout << "Found !"<<endl;
689  string name = (*it)->getName();
690  context->attributes()->removeAttribute(name);
691  // This aliasing may happen only once for each var SendHandle. Since 'arg1' is not assignable, a next assigning will fail.
692  if ( dynamic_cast<ValueDataSource<SendStatus>*>(mhandle->getDataSource().get() ) ) {
693  // This goes quite far: we also wrap the SH DataSource in a collect such that evaluating it does not cause a reset()+send(), but merely returns the SendStatus:
694  context->attributes()->setValue( new SendHandleAlias( name,
695  mhandle->getFactory()->produceCollect(std::vector<DataSourceBase::shared_ptr>(1,arg1), new ValueDataSource<bool>(false)),
696  mhandle->getFactory() ) );
697  parsestack.push( arg1 ); // effectively aliases RHS to lhs. Don't use the SendHandleAlias since it would not do the reset()+send().
698  return;
699  }
700  AttributeBase* var = mhandle->clone();
701  var->setName( name ); // fill in the final handle name.
702  context->attributes()->setValue( var );
703  arg2 = var->getDataSource(); // frees up dummy and puts real one in place.
704  break;
705  }
706  }
707  }
708 
710  ActionInterface* act = 0;
711  try {
712  act = arg2->updateAction( arg1.get() );
713  } catch(...) { // bad assignment
714  throw parse_exception_fatal_semantic_error( "Incompatible types. Cannot assign: "+ arg2->getType() +" = " +
715  " "+arg1->getType() +"." );
716  }
717  if (!act)
718  throw parse_exception_fatal_semantic_error( "2:Cannot assign constant (or returned) variable of types: "+ arg2->getType() +" = " +
719  " "+arg1->getType() );
720  // only try this if not unknown_t.
721  if (arg2->getTypeInfo()->getTypeName() != "unknown_t")
722  ret = arg2->getTypeInfo()->buildActionAlias(act, arg2);
723  if (!ret) { // no type info !
724  ret = new DataSourceCommand( act ); // fall back into the old behavior of returning a boolean.
725  }
726  parsestack.push( ret );
727  }
728 
729  void ExpressionParser::seen_index()
730  {
731  DataSourceBase::shared_ptr arg1( parsestack.top() );
732  parsestack.pop();
733  DataSourceBase::shared_ptr arg2( parsestack.top() );
734  parsestack.pop();
735 
736  // Arg2 is the first (!) argument, as it was pushed on the stack
737  // first.
738  DataSourceBase::shared_ptr ret = arg2->getMember( arg1, 0 );
739  if ( ! ret )
740  throw parse_exception_fatal_semantic_error( "Illegal use of []: "+ arg2->getType() +"[ "
741  +arg1->getType() +" ]." );
742  parsestack.push( ret );
743  }
744 
746  {
747  mcmdcnd = 0;
748  parsestack.pop();
749  }
750 }
bool setValue(base::AttributeBase *ab)
Transfer the ownership of an attribute to the repository.
std::vector< base::DataSourceBase::shared_ptr > result()
Get the parsed internal::DataSource&#39;s.
DataSource is a base class representing a generic way to read data of type T.
Definition: DataSource.hpp:94
virtual result_t get() const =0
Return the data as type T.
rule_t tidentifier
recursive template def.
std::string object()
Returns the last matching object name.
Definition: PeerParser.cpp:235
DataCallParser(ExpressionParser &p, CommonParser &cp, TaskContext *pc, ExecutionEngine *caller)
ConfigurationInterface * attributes()
Returns the attributes of this TaskContext as an ConfigurationInterface.
void reset()
After reset, peer() == current context and object() == "this".
Definition: PeerParser.cpp:151
This interface represents the concept of a condition which can be evaluated and return true or false...
STL namespace.
bool skipeol
Saves eol skipping state.
A internal::DataSource which returns the time elapsed since the last reset in Seconds.
parse_exception class that is used for various semantic errors for which it was not worth defining a ...
virtual DataSourceBase::shared_ptr getDataSource() const =0
Return a internal::DataSource which contains the same contents.
base::DataSourceBase::shared_ptr getDataSource() const
Return a internal::DataSource which contains the same contents.
This is a parser that you construct to parse a set of arguments.
ConditionInterface * getCmdResult()
base::DataSourceBase * getParseResult()
void removeAttribute(const std::string &name)
Remove an attribute from the repository.
This class contains some very common parser definitions.
TaskContext * peer()
Returns the last matching peer.
Definition: PeerParser.cpp:225
This class builds on upon construction all expression operators known to Orocos.
Definition: Operators.hpp:107
An execution engine serialises (executes one after the other) the execution of all commands...
rule_t & locator()
The locator tries to go as far as possible in the peer-to-object path and will never throw...
Definition: PeerParser.cpp:220
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
void seen_type_name(iter_t begin, iter_t end)
scanner< iter_t, scanner_pol_t > scanner_t
OperationInterfacePart * getFactory() const
How we parse: this parser works like a stack-based RPN calculator.
An attribute is a minimalistic, named placeholder for data.
boost::shared_ptr< base::AttributeBase > getHandle()
In case the parsed result returns a SendHandle, ask the parser to also create a handle for it...
AttributeObjects const & getValues() const
Returns all attributes in this repository.
A DataSource which is used to execute an action and then return the value of another DataSource...
rule_t type_name
See notassertingidentifier, but in lexeme parsing mode.
ServicePtr taskObject()
Returns the last matching Service or zero if not found.
Definition: PeerParser.cpp:230
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
base::DataSourceBase::shared_ptr getResult()
rule< scanner_t > rule_t
A class for representing a user type, and which can build instances of that type. ...
Definition: TypeInfo.hpp:67
ConditionInterface * getParseCmdResult()
TypeInfoRepository::shared_ptr Types()
Obtain a pointer to the global type system.
Definition: Types.cpp:48
base::DataSourceBase * getParseResult()
Keeps track of a DataSource which has a SendHandle and the factory for creating the collect functions...
A Command which evaluates a base::DataSourceBase and always returns true.
virtual base::DataSourceBase::shared_ptr produceCollect(const std::vector< base::DataSourceBase::shared_ptr > &args, internal::DataSource< bool >::shared_ptr blocking) const =0
Create a DataSource for collecting the results of a Send.
ExpressionParser(TaskContext *pc, ExecutionEngine *caller, CommonParser &common_parser)
parse_exception class that is used for fatal semantic errors for which it was not worth defining a pr...
A DataSource which holds a constant value and returns it in its get() method.
double Seconds
The type used to store SI unit time keeping.
Definition: TimeService.hpp:41
A class that wraps a Command in a internal::DataSource<bool> interface.
std::vector< base::AttributeBase * > AttributeObjects
A vector containing pointers to all attribute objects stored in this repository.
ConstructorParser(ExpressionParser &p, CommonParser &cp)
The TaskContext is the C++ representation of an Orocos component.
Definition: TaskContext.hpp:93
Exception thrown when a factory is requested to create an object, but a wrong argument type was given...
Exception thrown when a factory is requested to create an object but the wrong number of arguments wa...
boost::intrusive_ptr< DataSourceBase > shared_ptr
Use this type to store a pointer to a DataSourceBase.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
our_pos_iter_t iter_t
A simple, yet very useful DataSource, which keeps a value, and returns it in its get() method...
Definition: DataSources.hpp:60
A DataSource that collects the result of a CmdFunction.
const base::DataSourceBase::shared_ptr lastParsed() const
boost::shared_ptr< SendHandleAlias > getParseHandle()
static RTT_API Service::shared_ptr Instance()
virtual const std::string & getName() const
Returns the name of this TaskContext.
void setName(std::string const &new_name)
Get the name of this instance.
Definition: Attribute.cpp:64