Orocos Real-Time Toolkit  2.8.3
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 "../internal/GlobalService.hpp"
42 
43 #include "DataSourceTime.hpp"
44 #include "../TaskContext.hpp"
45 #include "PeerParser.hpp"
46 #include "../types/Types.hpp"
47 #include "SendHandleAlias.hpp"
48 
49 #include <boost/lambda/lambda.hpp>
50 
51 #include <boost/bind.hpp>
52 #include <boost/ref.hpp>
53 #include "rtt-scripting-config.h"
54 #include <iostream>
55 
56 namespace RTT
57 {
58  using boost::bind;
59  using boost::ref;
60 
61  using namespace detail;
62  using namespace std;
63 
64  namespace {
65  boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
66  boost::spirit::classic::assertion<std::string> expect_close("Closing brace expected ( or could not find out what this line means ).");
67  boost::spirit::classic::assertion<std::string> expect_type("Unknown type. Please specify a type.");
68  boost::spirit::classic::assertion<std::string> expect_expr("Expected a valid expression.");
69  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
70  boost::spirit::classic::assertion<std::string> expect_init("Expected an initialisation value of the value.");
71  boost::spirit::classic::assertion<std::string> expect_comma("Expected the ',' separator after expression.");
72  boost::spirit::classic::assertion<std::string> expect_timespec("Expected a time specification (e.g. > 10s or > varname ) after 'time' .");
73 
74  guard<std::string> my_guard;
75  }
76 
77 
78 
80  : mcaller( caller ? caller : c->engine()), mis_send(false), commonparser(cp), expressionparser( p ),
81  peerparser( c, cp, false ) // accept partial paths
82  {
83  BOOST_SPIRIT_DEBUG_RULE( datacall );
84  BOOST_SPIRIT_DEBUG_RULE( arguments );
85  BOOST_SPIRIT_DEBUG_RULE( peerpath );
86  BOOST_SPIRIT_DEBUG_RULE( object );
87  BOOST_SPIRIT_DEBUG_RULE( method );
88 
89  // this parser uses a neat boost.spirit trick to avoid keeping
90  // loads of stacks for all parsing data ( this parser needs to be
91  // reentrant because it can be called while parsing an argument of
92  // a datacall, which has itself been called while parsing an
93  // argument of a datacall... ). Boost.Spirit allows you to change
94  // the parser that a rule points to at runtime, so we only create
95  // the parser just before it's going to be used, when we know what
96  // arguments we want.. See the ArgumentsParser doc for more
97  // details..
98  peerpath = peerparser.locator();
99  object= (commonparser.identifier >> ".")[boost::bind(&DataCallParser::seenobjectname, this, _1, _2)];
100  method= ( commonparser.keyword | expect_ident(commonparser.tidentifier))[boost::bind( &DataCallParser::seenmethodname, this, _1, _2 ) ]; // may be send, call or method name.
101  datacall =
102  ( peerpath >> !object >> method[ boost::bind( &DataCallParser::seendataname, this ) ] >> !arguments)[ boost::bind( &DataCallParser::seendatacall, this ) ];
103  }
104 
105  void DataCallParser::seensend() {
106  mis_send = true;
107  }
108 
109  void DataCallParser::seenobjectname( iter_t begin, iter_t end )
110  {
111  std::string name( begin, end );
112  mobject = name.substr(0, name.length() - 1);
113  };
114 
115  void DataCallParser::seenmethodname( iter_t begin, iter_t end )
116  {
117  std::string name( begin, end );
118  if ( name == "send") {
119  mis_send = true;
120  mmethod = mobject;
121  mobject.clear();
122  } else {
123  mis_send = false;
124  mmethod = name;
125  }
126 // cout << "seenmethodname "<< mobject << "." << mmethod<<endl;
127  };
128 
129  void DataCallParser::seendataname()
130  {
131  // re-init mobject, might have been cleared during parsing of send().
132  mobject = peerparser.object();
133  TaskContext* peer = peerparser.peer();
134  Service::shared_ptr ops = peerparser.taskObject();
135  peerparser.reset();
136 // cout << "seendataname "<< mobject << "." << mmethod<<endl;
137  if (true) {
138  // it ain't...
139  // set the proper object name again in case of a send()
140  if (mis_send && ops)
141  mobject = ops->getName();
142 // cout << "DCP saw method "<< mmethod <<" of object "<<mobject<<" of peer "<<peer->getName()<<endl;
143  // Check sanity of what we parsed:
144  if (mmethod != "collect" && mmethod != "collectIfDone" ) {
145  if ( ops == 0 || (mobject != "this" && ops->getName() != mobject ) ) {
146  throw parse_exception_no_such_component( peer->getName(), mobject);
147  }
148  // Check if method exists on current object:
149  if ( ops->hasMember(mmethod) == false ) {
150  // Check if it is a method of the global service:
151  if ( ops == peerparser.taskObject() && GlobalService::Instance()->hasMember(mmethod) ) {
152  mobject = "GlobalService";
153  ops = GlobalService::Instance();
154  } else {
155  if ( ops == peerparser.taskObject() && ops->hasService("scripting") && ops->provides("scripting")->hasMember(mmethod) ) {
156  mobject = "scripting";
157  ops = ops->provides("scripting");
158  } else {
159  //DumpObject( peer );
160  if ( mobject != "this" )
161  throw parse_exception_no_such_method_on_component( mobject, mmethod );
162  else
163  throw parse_exception_no_such_method_on_component( peer->getName(), mmethod );
164  }
165  }
166  }
167  }
168  }
169 
170  // create an argument parser for the call..
171  // Store everything in the ArgumentsParser ! This DataCallParser instance is recursively called !
172  ArgumentsParser* argspar =
173  new ArgumentsParser( expressionparser, peer, ops,
174  mobject, mmethod );
175  // we no longer need these two..
176  mobject.clear();
177  mmethod.clear();
178 
179  // keep hold of the argspar, we're still going to need it after
180  // it's done its work.. ( in seendatacall(), that is.. )
181  argparsers.push( argspar );
182 
183  // set the arguments parser to the parser provided by the
184  // ArgumentsParser we just created..
185  arguments = argspar->parser();
186  }
187 
188  void DataCallParser::seendatacall()
189  {
190  ArgumentsParser* argspar = argparsers.top();
191  argparsers.pop();
192  std::string obj = argspar->objectname();
193  std::string meth = argspar->methodname();
194  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
195  Service::shared_ptr peer = argspar->object();
196  delete argspar;
197  assert(peer && "peer may never be null.");
198 // cout << "seendatacall "<< mobject << "." << mmethod<<endl;
199 
200  if ( true ) {
201  // plain method or collect/collectIfDone
202 
203  Service::shared_ptr ops = peer;
204  // we already checked for the existence of this object and method
205  // in seendataname()..
206  peerparser.reset();
207 
208  try {
209  if ( (meth == "collect" || meth == "collectIfDone") && !ops->hasMember(mmethod) ) {
210  if ( ops->hasAttribute(obj) ) {
211  SendHandleAlias* sha = dynamic_cast<SendHandleAlias*>( peer->getValue(obj) );
212  if (sha) {
213  // add SendHandle DS for Collect:
214  args.insert( args.begin(), sha->getDataSource() );
215  if (meth == "collect")
216  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(true) );// blocking
217  else
218  ret = sha->getFactory()->produceCollect(args, new ValueDataSource<bool>(false) );// non-blocking
219  return;
220  }
221  }
222  throw parse_exception_fatal_semantic_error( obj + "."+meth +": "+ obj +" is not a valid SendHandle object.");
223  }
224  if (!mis_send) {
225  ret = ops->produce( meth, args, mcaller );
226  mhandle.reset();
227  } else {
228  ret = ops->produceSend( meth, args, mcaller );
229  mhandle.reset( new SendHandleAlias( meth, ops->produceHandle(meth), ops->getPart(meth)) );
230  }
231  }
232  catch( const wrong_number_of_args_exception& e )
233  {
235  (obj, meth, e.wanted, e.received );
236  }
237  catch( const wrong_types_of_args_exception& e )
238  {
240  (obj, meth, e.whicharg, e.expected_, e.received_ );
241  }
242  catch( const std::exception& e)
243  {
244  throw parse_exception_fatal_semantic_error("While calling "+obj+"."+meth+": "+e.what());
245  }
246  }
247  assert( ret.get() );
248  }
249 
251  {
252  // if argparsers is not empty, then something went wrong during
253  // the parsing ( someone threw an exception ), and we're
254  // responsible for cleaning up the argparsers we created..
255  while ( ! argparsers.empty() )
256  {
257  delete argparsers.top();
258  argparsers.pop();
259  };
260  }
261 
263  : commonparser(cp), expressionparser( p )
264  {
265  BOOST_SPIRIT_DEBUG_RULE( type_name );
266  BOOST_SPIRIT_DEBUG_RULE( arguments );
267 
268  type_name =
269  ( commonparser.type_name[ boost::bind( &ConstructorParser::seen_type_name, this, _1, _2 ) ] >> !arguments)[ boost::bind( &ConstructorParser::seen_constructor, this ) ];
270  }
271 
273  {
274  // if argparsers is not empty, then something went wrong during
275  // the parsing ( someone threw an exception ), and we're
276  // responsible for cleaning up the argparsers we created..
277  while ( ! argparsers.empty() )
278  {
279  delete argparsers.top();
280  argparsers.pop();
281  };
282  }
283 
284 
286  {
287  std::string name( begin, end );
288  TypeInfo* type = Types()->type( name );
289  if ( type == 0 )
290  throw_(iter_t(), "\"" + name + "\" is an unknown type...");
291 
292  ArgumentsParser* argspar =
293  new ArgumentsParser( expressionparser, 0, Service::shared_ptr(), name, "" );
294 
295  // keep hold of the argspar, we're still going to need it after
296  // it's done its work.. ( in seen_constructor(), that is.. )
297  argparsers.push( argspar );
298 
299  // set the arguments parser to the parser provided by the
300  // ArgumentsParser we just created..
301  arguments = argspar->parser();
302 
303  }
304 
306  {
307  ArgumentsParser* argspar = argparsers.top();
308  argparsers.pop();
309  std::string obj = argspar->objectname();
310  std::vector<DataSourceBase::shared_ptr> args = argspar->result();
311  delete argspar;
312 
313  ret = TypeInfoRepository::Instance()->type( obj )->construct( args );
314 
315  if (!ret) {
316  throw parse_exception_no_such_constructor( obj, args );
317  }
318 
319  }
320 
322  static void abort_rule(const string& reason) {
323  throw_(iter_t(), reason);
324  }
325 
326  static error_status<> fail_rule(scanner_t const& scan, parser_error<std::string, iter_t>&e )
327  {
328  return error_status<>( error_status<>::fail );
329  }
333  : datacallparser( *this, cp, pc, caller ),
334  constrparser(*this, cp),
335  commonparser( cp ),
336  valueparser( pc, cp ),
337  _invert_time(false),
338  opreg( OperatorRepository::Instance() ),
339  context(pc)
340  {
341  BOOST_SPIRIT_DEBUG_RULE( expression );
342  BOOST_SPIRIT_DEBUG_RULE( unarynotexp );
343  BOOST_SPIRIT_DEBUG_RULE( unaryminusexp );
344  BOOST_SPIRIT_DEBUG_RULE( unaryplusexp );
345  BOOST_SPIRIT_DEBUG_RULE( div_or_mul );
346  BOOST_SPIRIT_DEBUG_RULE( modexp );
347  BOOST_SPIRIT_DEBUG_RULE( plus_or_min );
348  BOOST_SPIRIT_DEBUG_RULE( smallereqexp );
349  BOOST_SPIRIT_DEBUG_RULE( smallerexp );
350  BOOST_SPIRIT_DEBUG_RULE( greatereqexp );
351  BOOST_SPIRIT_DEBUG_RULE( greaterexp );
352  BOOST_SPIRIT_DEBUG_RULE( equalexp );
353  BOOST_SPIRIT_DEBUG_RULE( notequalexp );
354  BOOST_SPIRIT_DEBUG_RULE( orexp );
355  BOOST_SPIRIT_DEBUG_RULE( andexp );
356  BOOST_SPIRIT_DEBUG_RULE( ifthenelseexp );
357  BOOST_SPIRIT_DEBUG_RULE( groupexp );
358  BOOST_SPIRIT_DEBUG_RULE( dotexp );
359  BOOST_SPIRIT_DEBUG_RULE( atomicexpression );
360  BOOST_SPIRIT_DEBUG_RULE( time_expression );
361  BOOST_SPIRIT_DEBUG_RULE( time_spec );
362  BOOST_SPIRIT_DEBUG_RULE( indexexp );
363  BOOST_SPIRIT_DEBUG_RULE( comma );
364  BOOST_SPIRIT_DEBUG_RULE( close_brace );
365  BOOST_SPIRIT_DEBUG_RULE( value_expression );
366  BOOST_SPIRIT_DEBUG_RULE( call_expression );
367  BOOST_SPIRIT_DEBUG_RULE( constructor_expression );
368 
369  comma = expect_comma( ch_p(',') );
370  close_brace = expect_close( ch_p(')') );
371  expression = assignexp;
372 
373  // We parse expressions without regard of the types. First we
374  // parse the expressions, then we worry about whether what the
375  // user says is actually valid. You can try to add up two
376  // booleans, and the parser will parse it, but it will notice
377  // you're writing bogus when it tries to pass it to an operator
378  // structure from Operators.hpp
379 
380  // TODO: implement the ifthenelse operator ?
381  assignexp = andexp >> *( ch_p( '=' ) >> eps_p(~ch_p( '=' )) // prevent parsing first '=' of "=="
382  >> assignexp)[ bind( &ExpressionParser::seen_assign, this)];
383  andexp =
384  orexp >> *( ( str_p( "&&" ) ) >> orexp[
385  boost::bind( &ExpressionParser::seen_binary, this, "&&" ) ] );
386  orexp =
387  notequalexp >> *( ( str_p( "||" ) ) >> notequalexp[
388  boost::bind( &ExpressionParser::seen_binary, this, "||" ) ] );
389  notequalexp =
390  equalexp >> *( "!=" >> equalexp[
391  boost::bind( &ExpressionParser::seen_binary, this, "!=" ) ] );
392  equalexp =
393  greatereqexp
394  >> *( "==" >> greatereqexp[
395  boost::bind( &ExpressionParser::seen_binary, this, "==" ) ] );
396  greatereqexp =
397  greaterexp
398  >> *( ">=" >> greaterexp[
399  boost::bind( &ExpressionParser::seen_binary, this, ">=" ) ] );
400  greaterexp =
401  smallereqexp
402  >> *( '>' >> smallereqexp[
403  boost::bind( &ExpressionParser::seen_binary, this, ">" ) ] );
404  smallereqexp =
405  smallerexp
406  >> *( "<=" >> smallerexp[
407  boost::bind( &ExpressionParser::seen_binary, this, "<=" ) ] );
408  smallerexp =
409  plus_or_min >> *( '<' >> plus_or_min[
410  boost::bind( &ExpressionParser::seen_binary, this, "<" ) ] );
411 
412  plus_or_min =
413  modexp >> *( ('-' >> modexp[
414  boost::bind( &ExpressionParser::seen_binary, this, "-" ) ] )
415  | ('+' >> modexp[
416  boost::bind( &ExpressionParser::seen_binary, this, "+" ) ] ) );
417 
418  modexp =
419  div_or_mul >> *( '%' >> div_or_mul[
420  boost::bind( &ExpressionParser::seen_binary, this, "%" ) ] );
421  div_or_mul =
422  unaryplusexp >> *( ('/' >> unaryplusexp[
423  boost::bind( &ExpressionParser::seen_binary, this, "/" ) ] )
424  | ('*' >> unaryplusexp[
425  boost::bind( &ExpressionParser::seen_binary, this, "*" ) ] ) );
426 
427  unaryplusexp =
428  '+' >> unaryminusexp[
429  boost::bind( &ExpressionParser::seen_unary, this, "+" ) ]
430  | unaryminusexp;
431  unaryminusexp =
432  '-' >> unarynotexp[
433  boost::bind( &ExpressionParser::seen_unary, this, "-" ) ]
434  | unarynotexp;
435  unarynotexp =
436  ch_p('!') >> atomicexpression[
437  boost::bind( &ExpressionParser::seen_unary, this, "!" ) ]
438  | atomicexpression;
439 
440  // note the order is important: commonparser.identifier throws a
441  // useful "cannot use x as identifier" error if it fails, so we
442  // must first show all non-identifier rules.
443  atomicexpression = (
444  // A parenthesis group.
445  groupexp
446  // or a time expression
447  | time_expression
448  // or a constant or user-defined value..
449  | value_expression
450  | constructor_expression
451  | call_expression
452  // or an index or dot expression
453  ) >> *( dotexp | indexexp);
454 
455  constructor_expression = my_guard( constrparser.parser()[ boost::bind(&ExpressionParser::seenconstructor, this)])[&fail_rule];
456 
457  // if it's value.keyword then pass it on to the call_expression.
458  value_expression = my_guard( valueparser.parser() >> !('.' >> commonparser.keyword[boost::bind(&abort_rule,"Rule must be handled by datacallparser.")]))[ &fail_rule ]
459  [ bind( &ExpressionParser::seenvalue, this ) ];
460  call_expression = my_guard( datacallparser.parser() )[&fail_rule]
461  [bind( &ExpressionParser::seendatacall, this ) ];
462  // take index of an atomicexpression
463  indexexp =
464  (ch_p('[') >> expression[bind(&ExpressionParser::seen_index, this)] >> expect_close( ch_p( ']') ) );
465 
466  dotexp =
467  ( ch_p('.') >> commonparser.identifier[ boost::bind(&ExpressionParser::seen_dotmember, this, _1, _2)]);
468 
469  // needs no semantic action, its result is already on top of
470  // the stack, where it should be..
471  groupexp = '(' >> expression >> close_brace;
472 
473  // the day i find a clean way to temporarily disable 'eol' skipping, a lot of
474  // grammar will look better...
475  time_expression =
476  (str_p("time")>>eps_p(~commonparser.identchar | eol_p | end_p ))[bind(&ExpressionParser::seentimeexpr, this)]
477  |
478  ( (eps_p[boost::lambda::var(commonparser.skipeol) = false] >> uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
479  >> (str_p( "s" ) | "ms" | "us" | "ns" )[boost::lambda::var(commonparser.skipeol) = true][boost::bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ])
480  | (eps_p[boost::lambda::var(commonparser.skipeol) = true] >> nothing_p) // eps_p succeeds always, then fail.
481  )
482  ; // enable skipeol.
483 
484 // >> expect_timespec( (( str_p( ">=" ) | ">" )
485 // |
486 // (str_p("<=") | "<")[bind( &ExpressionParser::inverttime, this)])
487 // >> time_spec);
488 
489 // time_spec =
490 // ( uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]
491 // >>
492 // ( str_p( "s" ) | "ms" | "us" | "ns" )[
493 // bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ] ) | expression[bind(&ExpressionParser::seentimeexpr, this)];
494 
495  };
496 
497  void ExpressionParser::inverttime()
498  {
499  _invert_time = true;
500  }
501 
502  void ExpressionParser::seentimeexpr()
503  {
504  parsestack.push( new DataSourceTime() );
505 
506 // DataSourceBase::shared_ptr res = parsestack.top();
507 // parsestack.pop();
508 // DataSource<double>::shared_ptr dres = dynamic_cast<DataSource<double>*>( res.get() );
509 // if ( !dres )
510 // throw parse_exception_semantic_error("Expected time in seconds but expression is not a floating point number.");
511 // DataSourceBase::shared_ptr dsb( new DataSourceCondition( new ConditionDSDuration( dres, _invert_time ) ) );
512 // _invert_time = false;
513 // parsestack.push( dsb );
514  }
515 
516  void ExpressionParser::seentimeunit( iter_t begin, iter_t end)
517  {
518  // the string starting at begin, ending at end is either ms, us,
519  // ns or s, so we only need to check the first letter...
520  // Convert to seconds...
521  TimeService::Seconds total = 0;
522  switch( *begin )
523  {
524  case 's': total = TimeService::Seconds(tsecs);
525  break;
526  case 'm': total = tsecs / 1000.0;
527  break;
528  case 'u': total = tsecs / 1000000.0;
529  break;
530  case 'n': total = tsecs / 1000000000.0;
531  break;
532  default:
533  std::string arg(begin, end);
534  throw parse_exception_semantic_error("Expected time expression 's', 'ms', 'us' or 'ns' after integer value, got "+arg);
535  };
536 
537  parsestack.push( new ConstantDataSource<double>( total ) );
538 
539 // DataSourceBase::shared_ptr dsb( new DataSourceCondition(
540 // new ConditionDuration( total, _invert_time ) ) );
541 // _invert_time = false;
542 // parsestack.push( dsb );
543  }
544 
545  void ExpressionParser::seentimespec( int n )
546  {
547  tsecs = n;
548  }
549 
550  void ExpressionParser::seenvalue()
551  {
552  DataSourceBase::shared_ptr ds = valueparser.lastParsed();
553  parsestack.push( ds );
554  }
555 
556  void ExpressionParser::seendatacall()
557  {
558  DataSourceBase::shared_ptr n( datacallparser.getParseResult() );
559  parsestack.push( n );
560  mhandle = datacallparser.getParseHandle();
561  }
562 
563  void ExpressionParser::seenconstructor()
564  {
565  DataSourceBase::shared_ptr n( constrparser.getParseResult() );
566  parsestack.push( n );
567  }
568 
570  {
571  // if parsestack is not empty, then something went wrong, someone
572  // threw an exception, so we clean up..
573  while ( !parsestack.empty() )
574  parsestack.pop();
575  }
576 
578  {
579  return expression;
580  }
581 
583  {
584  assert( !parsestack.empty() );
585  return parsestack.top();
586  }
587 
588  boost::shared_ptr<AttributeBase> ExpressionParser::getHandle()
589  {
590  assert( !parsestack.empty() );
591  return mhandle;
592  }
593 
594  void ExpressionParser::seen_unary( const std::string& op )
595  {
596  DataSourceBase::shared_ptr arg( parsestack.top() );
597  parsestack.pop();
599  opreg->applyUnary( op, arg.get() );
600  if ( ! ret )
601  throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op +
602  "\" to " + arg->getType() +"." );
603  parsestack.push( ret );
604  }
605 
606  void ExpressionParser::seen_dotmember( iter_t s, iter_t f )
607  {
608  std::string member(s,f);
609  // inspirired on seen_unary
610  DataSourceBase::shared_ptr arg( parsestack.top() );
611  parsestack.pop();
612  DataSourceBase::shared_ptr ret = arg->getMember(member);
613  if ( ! ret )
614  throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member +
615  "\"." );
616  parsestack.push( ret );
617  }
618 
619  void ExpressionParser::seen_binary( const std::string& op )
620  {
621  DataSourceBase::shared_ptr arg1( parsestack.top() );
622  parsestack.pop();
623  DataSourceBase::shared_ptr arg2( parsestack.top() );
624  parsestack.pop();
625 
626  // Arg2 is the first (!) argument, as it was pushed on the stack
627  // first.
629  opreg->applyBinary( op, arg2.get(), arg1.get() );
630  if ( ! ret )
631  throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op +
632  " "+arg1->getType() +"." );
633  parsestack.push( ret );
634  }
635 
636  void ExpressionParser::seen_assign()
637  {
638  DataSourceBase::shared_ptr arg1( parsestack.top() );
639  parsestack.pop(); // right hand side
640  DataSourceBase::shared_ptr arg2( parsestack.top() );
641  parsestack.pop(); // left hand side
642 
643  // hack to drop-in a new instance of SendHandle:
644  if (arg2->getTypeName() == "SendHandle" && mhandle) {
645 // cout << "Trying to replace SendHandle/..."<<endl;
647  for( ConfigurationInterface::AttributeObjects::iterator it = attrs.begin(); it != attrs.end(); ++it) {
648  if ( (*it)->getDataSource() == arg2 ) { // since the parsestack only saves the DSB, we need to do lookup by DSB and not by name :-(
649 // cout << "Found !"<<endl;
650  string name = (*it)->getName();
651  context->attributes()->removeAttribute(name);
652  AttributeBase* var = mhandle->clone();
653  var->setName( name ); // fill in the final handle name.
654  context->attributes()->setValue( var );
655  arg2 = var->getDataSource(); // frees up dummy and puts real one in place.
656  break;
657  }
658  }
659  }
660 
662  ActionInterface* act = 0;
663  try {
664  act = arg2->updateAction( arg1.get() );
665  } catch(...) { // bad assignment
666  throw parse_exception_fatal_semantic_error( "Incompatible types. Cannot assign: "+ arg2->getType() +" = " +
667  " "+arg1->getType() +"." );
668  }
669  if (!act)
670  throw parse_exception_fatal_semantic_error( "2:Cannot assign constant (or returned) variable of types: "+ arg2->getType() +" = " +
671  " "+arg1->getType() );
672  // only try this if not unknown_t.
673  if (arg2->getTypeInfo()->getTypeName() != "unknown_t")
674  ret = arg2->getTypeInfo()->buildActionAlias(act, arg2);
675  if (!ret) { // no type info !
676  ret = new DataSourceCommand( act ); // fall back into the old behavior of returning a boolean.
677  }
678  parsestack.push( ret );
679  }
680 
681  void ExpressionParser::seen_index()
682  {
683  DataSourceBase::shared_ptr arg1( parsestack.top() );
684  parsestack.pop();
685  DataSourceBase::shared_ptr arg2( parsestack.top() );
686  parsestack.pop();
687 
688  // Arg2 is the first (!) argument, as it was pushed on the stack
689  // first.
690  DataSourceBase::shared_ptr ret = arg2->getMember( arg1, 0 );
691  if ( ! ret )
692  throw parse_exception_fatal_semantic_error( "Illegal use of []: "+ arg2->getType() +"[ "
693  +arg1->getType() +" ]." );
694  parsestack.push( ret );
695  }
696 
698  {
699  parsestack.pop();
700  }
701 }
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.
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
STL namespace.
bool skipeol
Saves eol skipping state.
A internal::DataSource which returns the time elapsed since the last reset in Seconds.
boost::shared_ptr< base::AttributeBase > getParseHandle()
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.
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.
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:66
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...
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:51
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
const base::DataSourceBase::shared_ptr lastParsed() const
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