StateGraphParser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 StateGraphParser.cxx
3 
4  StateGraphParser.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 General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 #include "parser-debug.hpp"
39 #include "parse_exception.hpp"
40 #include "StateGraphParser.hpp"
41 #include "CommonParser.hpp"
42 #include "ConditionParser.hpp"
43 #include "ConditionCompare.hpp"
44 #include "ConditionComposite.hpp"
45 #include "ConditionCache.hpp"
47 #include "ValueChangeParser.hpp"
48 #include "ProgramGraphParser.hpp"
49 #include "PeerParser.hpp"
50 #include "ArgumentsParser.hpp"
51 #include "StateMachineBuilder.hpp"
52 #include "../TaskContext.hpp"
53 #include "StateMachineService.hpp"
54 
55 #include "CommandComposite.hpp"
56 #include "../internal/Exceptions.hpp"
57 #include "../base/AttributeBase.hpp"
58 #include "ConditionTrue.hpp"
59 #include "ConditionInvert.hpp"
60 #include "StateDescription.hpp"
61 #include "ParsedStateMachine.hpp"
62 
63 #include <iostream>
64 #include <functional>
65 #include <algorithm>
66 #include <boost/bind.hpp>
67 #include <boost/lambda/lambda.hpp>
68 #include <boost/call_traits.hpp>
69 #include <iostream>
70 #include <memory>
71 #include "../internal/mystd.hpp"
72 
73 namespace RTT
74 {
75  using namespace boost;
76  using namespace detail;
77  using boost::bind;
78 
79  using namespace std;
80 
81  namespace {
83  {
84  state_expected,
85  handle_expected,
86  transition_expected,
87  };
88 
89  boost::spirit::classic::assertion<GraphSyntaxErrors> expect_state(state_expected);
90  boost::spirit::classic::assertion<GraphSyntaxErrors> expect_handle(handle_expected);
91  boost::spirit::classic::assertion<GraphSyntaxErrors> expect_transition(transition_expected);
92  boost::spirit::classic::assertion<std::string> expect_end("Ending '}' expected ( or could not find out what this line means ).");
93  boost::spirit::classic::assertion<std::string> expect_end_of_state("Exptected ending '}' at end of state ( or could not find out what this line means ).");
94  boost::spirit::classic::assertion<std::string> expect_if("Wrongly formatted \"if ... then select\" clause.");
95  boost::spirit::classic::assertion<std::string> expect_select("'select' statement required after emty transition program.");
96  boost::spirit::classic::assertion<std::string> expect_select_ident("'select' requires a valid state name.");
97  boost::spirit::classic::assertion<std::string> expect_comma("Expected a comma separator.");
98  boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier.");
99  boost::spirit::classic::assertion<std::string> expect_event_or_if("Expected an event name or an if clause in transition statement.");
100  boost::spirit::classic::assertion<std::string> expect_open("Open brace expected.");
101  boost::spirit::classic::assertion<std::string> expect_eof("Invalid input in file.");
102  boost::spirit::classic::assertion<std::string> expect_eol("Newline expected at end of statement.");
103  boost::spirit::classic::assertion<std::string> expect_semicolon("Semi colon expected after statement.");
104  boost::spirit::classic::assertion<std::string> expect_open_parenth( "Open parenthesis expected." );
105  boost::spirit::classic::assertion<std::string> expect_close_parenth( "Open parenthesis expected." );
106  boost::spirit::classic::assertion<std::string> expect_eventselect("'select' statement required after event or transition program.");
107  boost::spirit::classic::assertion<std::string> expect_eventargs("Could not parse arguments after event.");
108  }
109 
110 
112  TaskContext* tc, ExecutionEngine* tcaller, CommonParser* cp )
113  : context( tc ),
114  caller( tcaller ),
115  mpositer( positer ),
116  ln_offset(0),
117  curtemplate(),
118  curinstantiatedmachine(),
119  curmachinebuilder( 0 ),
120  curinitialstateflag( false ),
121  curfinalstateflag( false ),
122  curstate( 0 ),
123  curnonprecstate( 0 ),
124  progParser( 0 ),
125  elsestate(0),
126  curcondition( 0 ),
127  isroot(false),
128  selectln(0),
129  evname(""),
130  commonparser( cp ),
131  conditionparser( new ConditionParser( context, caller, *commonparser ) ),
132  valuechangeparser( new ValueChangeParser(context, *commonparser, context->provides(), caller) ),
133  expressionparser( new ExpressionParser(context, caller, *commonparser) ),
134  argsparser(0),
135  peerparser( new PeerParser(context, *commonparser, true) ) // full-path peer parser for events.
136  {
137  BOOST_SPIRIT_DEBUG_RULE( production );
138  BOOST_SPIRIT_DEBUG_RULE( body );
139  BOOST_SPIRIT_DEBUG_RULE( rootmachineinstantiation );
140  BOOST_SPIRIT_DEBUG_RULE( statemachine );
141  BOOST_SPIRIT_DEBUG_RULE( machineinstantiation );
142  BOOST_SPIRIT_DEBUG_RULE( statemachinecontent );
143  BOOST_SPIRIT_DEBUG_RULE( varline );
144  BOOST_SPIRIT_DEBUG_RULE( state );
145  BOOST_SPIRIT_DEBUG_RULE( vardec );
146  BOOST_SPIRIT_DEBUG_RULE( subMachinedecl );
147  BOOST_SPIRIT_DEBUG_RULE( statecontent );
148  BOOST_SPIRIT_DEBUG_RULE( statecontentline );
149  BOOST_SPIRIT_DEBUG_RULE( entry );
150  BOOST_SPIRIT_DEBUG_RULE( preconditions );
151  BOOST_SPIRIT_DEBUG_RULE( precondition );
152  BOOST_SPIRIT_DEBUG_RULE( handle );
153  BOOST_SPIRIT_DEBUG_RULE( transitions );
154  BOOST_SPIRIT_DEBUG_RULE( transition );
155  BOOST_SPIRIT_DEBUG_RULE( exit );
156  BOOST_SPIRIT_DEBUG_RULE( transline );
157  BOOST_SPIRIT_DEBUG_RULE( eventline );
158  BOOST_SPIRIT_DEBUG_RULE( ifbranch );
159  BOOST_SPIRIT_DEBUG_RULE( elsebranch );
160  BOOST_SPIRIT_DEBUG_RULE( progselect );
161  BOOST_SPIRIT_DEBUG_RULE( program );
162  BOOST_SPIRIT_DEBUG_RULE( selector );
163  BOOST_SPIRIT_DEBUG_RULE( machineinstarguments );
164  BOOST_SPIRIT_DEBUG_RULE( machineinstargument );
165  BOOST_SPIRIT_DEBUG_RULE( machinememvar );
166  BOOST_SPIRIT_DEBUG_RULE( machinevariable );
167  BOOST_SPIRIT_DEBUG_RULE( machineparam );
168  BOOST_SPIRIT_DEBUG_RULE( machineconstant );
169  BOOST_SPIRIT_DEBUG_RULE( machinealias );
170  BOOST_SPIRIT_DEBUG_RULE( subMachinevarchange );
171 
172  storeOffset();
173 
174  production = *body >> expect_eof(end_p);
175 
176  body = statemachine[ boost::bind( &StateGraphParser::seenstatemachineend, this ) ][boost::bind( &StateGraphParser::saveText, this, _1, _2)]
178 
179 
181  keyword_p("RootMachine")[boost::bind (&StateGraphParser::startrootmachineinstantiation, this) ]
183 
184  statemachine =
185  keyword_p("StateMachine") //[boost::bind( &StateGraphParser::storeOffset, this)]
186  >> expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seenstatemachinename, this, _1, _2 )] )
187  >> expect_open( ch_p( '{' ) )
189  >> expect_end( ch_p( '}' ) );
190 
191  // Zero or more declarations and Zero or more states. Once a state is encountered, no more global transitions may be defined.
193 
194  varline = vardec[lambda::var(commonparser->skipeol) = false] >> commonparser->eos[lambda::var(commonparser->skipeol) = true];
195 
197 
202 
204 
205  subMachinedecl = keyword_p("SubMachine")
207 
209  expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seenmachinetypename, this, _1, _2 )] )
210  >> expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seeninstmachinename, this, _1, _2 )] )
211  >> ( ! ( ch_p( '(' )
213  >> expect_close_parenth( ch_p( ')' ) ) ) )[ boost::bind( &StateGraphParser::seenmachineinstantiation, this )];
214 
217 
220  >> '='
222 
223  state =
224  !( keyword_p( "initial" )[boost::bind( &StateGraphParser::seeninitialstate,this )]
225  | keyword_p( "final" )[boost::bind( &StateGraphParser::seenfinalstate,this )] )
226  >> keyword_p( "state" )
227  >> expect_ident(commonparser->identifier[ boost::bind( &StateGraphParser::statedef, this, _1, _2 ) ])
228  >> expect_open(ch_p( '{' ))
229  >> statecontent
230  >> expect_end_of_state(ch_p( '}' ))[ boost::bind( &StateGraphParser::seenstateend, this ) ];
231 
232  // the content of a program can be any number of lines
233  // a line is not strictly defined in the sense of text-line.
235 
236  // a state can contain various programs and variable definitions
238  entry
239  | preconditions
240  | run
241  | handle
242  | transitions
243  | transition
244  | exit
245  | (machinememvar[lambda::var(commonparser->skipeol) = false] >> commonparser->eos[lambda::var(commonparser->skipeol) = true]);
246 
247  precondition = keyword_p( "precondition")
248  >> conditionparser->parser()[ boost::bind( &StateGraphParser::seenprecondition, this)] ;
249 
250  preconditions = (keyword_p( "preconditions" )[ boost::bind( &StateGraphParser::inpreconditions, this )]
251  >> expect_open( ch_p( '{' ))
252  >> *transline[boost::bind(&StateGraphParser::seenendcondition,this)]
253  >> expect_end( ch_p( '}' ) )[
254  boost::bind( &StateGraphParser::seenpreconditions, this )]) | precondition;
255 
256  entry = keyword_p( "entry" )[ boost::bind( &StateGraphParser::inprogram, this, "entry" )]
257  >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[
258  boost::bind( &StateGraphParser::seenentry, this )];
259 
260  run = keyword_p( "run" )[ boost::bind( &StateGraphParser::inprogram, this, "run" )]
261  >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[
262  boost::bind( &StateGraphParser::seenrun, this )];
263 
264  exit = keyword_p( "exit" )[ boost::bind( &StateGraphParser::inprogram, this, "exit" )]
265  >> expect_open(ch_p('{')) >> programBody >> expect_end(ch_p('}'))[
266  boost::bind( &StateGraphParser::seenexit, this )];
267 
268  handle = keyword_p( "handle" )[ boost::bind( &StateGraphParser::inprogram, this, "handle" )]
269  >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[
270  boost::bind( &StateGraphParser::seenhandle, this )];
271 
272  // formal:
273  // transition [event] [[ {program} ][ select s]] | [ if c then ][ {program} ][select s][ else [ {program} ][select s]]
274  // parsed:
275  // transition [ [if c then ][ {program} ][select s][ else [ {program} ][select s]]]
276  // | [ event [[ {program} ][ select s]] | [ if c then ][ {program} ][select s][ else [ {program} ][select s]] ]
277  // rules:
278  // transition = "transition" >> (transline | eventline)
279  // transline = progselect
280  // | (ifbranch >> !elsebranch)
281  // eventline = eventname >> transline
282  // progselect = (selector | (program >> !selector))
283  // ifbranch = "if" >> c >> "then" >> progselect
284  // elsebranch = "else" >> progselect
285  // selector = "select" >> ...
286  // program = "{" >> ...
287  //
288 
289  // old transition statements
290  // the order of rule "transition" vs "transitions" is important
291  transitions = ( keyword_p( "transitions" )
292  >> expect_open(ch_p('{'))
293  >> *((transline|eventline)[boost::bind(&StateGraphParser::seenendcondition,this)])
294  >> expect_end(ch_p('}')) );
295 
296  // new transition statements
297  transition = keyword_p("transition") >> expect_event_or_if( transline | eventline )[boost::bind(&StateGraphParser::seenendcondition,this)];
299 
300  // @todo: capturing events are only on local ports ?!.
301  eventline =
302  !peerparser->parser() >> commonparser->identifier[ boost::bind( &StateGraphParser::seeneventname, this,_1,_2)]
303  >> expect_eventargs(argslist[ boost::bind( &StateGraphParser::seeneventargs, this)])
304  >> expect_eventselect(transline[ boost::bind( &StateGraphParser::seeneventtrans, this)]);
305 
306  progselect = selector | (program >> (selector | eps_p[boost::bind( &StateGraphParser::noselect, this )] ));
307  // | eps_p[boost::bind( &StateGraphParser::noselect, this )] ); // if eos fails skipeol stays false !, see clear() !
308 
309  ifbranch = keyword_p( "if") >> conditionparser->parser()[ boost::bind( &StateGraphParser::seencondition, this)]
310  >> !keyword_p( "then" )
311  >> progselect;
312  elsebranch = keyword_p("else")[boost::bind( &StateGraphParser::seenelse, this )]
313  >> progselect;
314 
315  program =
316  ch_p('{')[ boost::bind( &StateGraphParser::inprogram, this, "transition" )]
317  >> programBody
318  >> expect_end(ch_p('}'))[boost::bind( &StateGraphParser::seentransprog, this )];
319 
320  selector = keyword_p( "select" ) >> expect_select_ident(( commonparser->identifier[ boost::bind( &StateGraphParser::seenselect, this, _1, _2) ]
321  >> *(keyword_p("or") >> commonparser->identifier[ boost::bind( &StateGraphParser::seenselect, this, _1, _2) ])
322  )[lambda::var(commonparser->skipeol) = false]
323  >> commonparser->eos[lambda::var(commonparser->skipeol) = true]);
324 
325  }
326 
328  return body;
329  }
330 
333  if ( rootmachines.empty() )
334  return ret;
335  std::vector<ParsedStateMachinePtr> vret = values( rootmachines );
336  rootmachines.clear();
337  return vret.front();
338  }
339 
340 
342  {
343  curinitialstateflag = true;
344  }
345 
347  {
348  curfinalstateflag = true;
349  }
350 
352  {
353  assert( !curstate );
354 
355  std::string def(s, f);
356  if ( curtemplate->getState( def ) != 0 )
357  {
358  assert( dynamic_cast<StateDescription*>( curtemplate->getState( def ) ) );
359  StateDescription* existingstate = static_cast<StateDescription*>( curtemplate->getState( def ) );
360  if ( existingstate->isDefined() )
361  ORO_THROW(parse_exception_semantic_error("state " + def + " redefined.") );
362  else
363  curstate = existingstate;
364  curstate->setEntryPoint( mpositer.get_position().line - ln_offset );
365  }
366  else
367  {
368  curstate = new StateDescription(def, mpositer.get_position().line - ln_offset ); // create an empty state
369  curtemplate->addState( curstate );
370  }
371 
372  }
373 
375  {
376  if ( curinitialstateflag )
377  {
378  if ( curtemplate->getInitialState() )
379  ORO_THROW(parse_exception_semantic_error( "Attempt to define more than one initial state." ));
380  else curtemplate->setInitialState( curstate );
381  }
382  if ( curfinalstateflag )
383  {
384  if ( curtemplate->getFinalState() )
385  ORO_THROW(parse_exception_semantic_error( "Attempt to define more than one final state." ));
386  else curtemplate->setFinalState( curstate );
387  }
388 
389  assert( curstate );
390  curstate->setDefined( true );
391  curstate = 0;
392  curinitialstateflag = false;
393  curfinalstateflag = false;
394  // clear all port-triggered transitions for this state.
395  for (std::map<std::string,ConditionCache*>::iterator i = cur_port_events.begin();
396  i != cur_port_events.end(); ++i )
397  delete i->second;
398  cur_port_events.clear();
399  for (std::map<std::string,ConditionCache*>::iterator i = global_port_events.begin();
400  i != global_port_events.end(); ++i )
401  delete i->second;
402  global_port_events.clear();
403  }
404 
405  void StateGraphParser::inprogram(const std::string& name)
406  {
407  // setup the progParser to parse the program body,
408  // dynamically assign this parser to body.
409  assert( progParser != 0 );
410  // program name, stack, line offset.
411  //cerr << "SGP : Stack is " << curobject->getName() <<endl;
413 
415  }
416 
418  {
419  return progParser->bodyParserResult();
420  }
421 
423  {
424  if ( curstate->getEntryProgram() )
425  ORO_THROW( parse_exception_semantic_error( "Attempt to define entry twice in state "+ curstate->getName() ));
427  }
428 
430  {
431  if ( curstate->getExitProgram() )
432  ORO_THROW( parse_exception_semantic_error( "Attempt to define exit twice in state "+ curstate->getName() ));
434  }
435 
437  {
438  if ( curstate->getHandleProgram() )
439  ORO_THROW( parse_exception_semantic_error( "Attempt to define handle twice in state "+ curstate->getName() ));
441  }
442 
444  {
445  if ( curstate->getRunProgram() )
446  ORO_THROW( parse_exception_semantic_error( "Attempt to define run twice in state "+ curstate->getName() ));
448  }
449 
451  {
453  }
454 
456  {
457  // reuse transProgram to store else progr. See seenselect().
458  //transProgram = finishProgram();
459  //transProgram->setProgramProcessor(curtemplate->getService()->engine()->programs());
460  }
461 
463  {
464  assert( curcondition);
466  }
467 
469  {
470  assert( !curcondition );
472  assert( curcondition );
474  selectln = mpositer.get_position().line - ln_offset;
475  }
476 
478  {
479  evname = string(s,f);
480 
481  // seenselect() will use evname to see if event is causing transition
482  assert(evname.length());
484  peerparser->reset();
485 
486  // check if it's an operation:
487  if (peer->hasOperation(evname) ) {
488  argsparser =
490  evname, "callback" );
491  } else {
492  // check if it's a port.
493  if ( peer->hasService(evname) == false || peer->getService(evname)->hasOperation("read") == false) {
494  if (curstate)
495  ORO_THROW( parse_exception_fatal_semantic_error("In state "+curstate->getName()+": InputPort or Operation "+evname+" not found in Task "+peer->getName() ));
496  else
497  ORO_THROW( parse_exception_fatal_semantic_error("In statemachine: InputPort or Operation "+evname+" not found in Task "+peer->getName() ));
498  }
499  argsparser =
500  new ArgumentsParser( *expressionparser, context, peer->getService(evname),
501  evname, "read" );
502  }
503 
505  }
506 
508  {
509  evargs = argsparser->result();
510  delete argsparser;
511  argsparser = 0;
512  }
513 
515  {
516  // if omitted, implicitly re-enter current state.
517  if (curstate)
518  doselect( curstate->getName() );
519  else
520  doselect(""); // global events/transitions
521  }
522 
524  {
525  std::string state_id(s,f);
526  doselect(state_id);
527  }
528 
529  void StateGraphParser::doselect( const std::string& state_id )
530  {
531  StateInterface* next_state = 0;
532  if ( !state_id.empty() ) {
533  if ( curtemplate->getState( state_id ) != 0 )
534  {
535  next_state = curtemplate->getState( state_id );
536  }
537  else
538  {
539  next_state = new StateDescription(state_id, 1); // create an empty state
540  curtemplate->addState( next_state );
541  }
542  assert( next_state );
543  }
544 
545  // this transition has a lower priority than the previous one
546  if ( selectln == 0)
547  selectln = mpositer.get_position().line - ln_offset;
548 
549  if (evname.empty()) {
550  if (curcondition == 0)
552  } else if ( peer->hasService(evname) && peer->getService(evname)->hasOperation("read") ) { // is a port
553  try {
554  assert(peer->hasService(evname)); // checked in seeneventname()
555  ConditionInterface* evcondition = 0;
556  if ( global_port_events.count(evname) ){
557  // clone the cached condition in order to avoid a second read on the port.
558  evcondition = new ConditionBoolDataSource( global_port_events[evname]->getResult().get() );
559  } else
560  if ( cur_port_events.count(evname) ){
561  // clone the cached condition in order to avoid a second read on the port.
562  evcondition = new ConditionBoolDataSource( cur_port_events[evname]->getResult().get() );
563  } else {
564  // combine the implicit 'read(arg) == NewData' with the guard, if any.
565  DataSourceBase::shared_ptr read_dsb = peer->getService(evname)->produce("read", evargs, context->engine() );
566  DataSource<FlowStatus>* read_ds = dynamic_cast<DataSource<FlowStatus>*>(read_dsb.get());
567  assert(read_ds);
569  if (curstate) {
570  cur_port_events[evname] = new ConditionCache( evcondition ); // caches result until reset().
571  evcondition = cur_port_events[evname]->clone();
572  } else {
573  //global event:
574  global_port_events[evname] = new ConditionCache( evcondition ); // caches result until reset().
575  evcondition = global_port_events[evname]->clone();
576  }
577  }
578  if (curcondition == 0) {
579  curcondition = evcondition;
580  } else {
582  }
583  }
584  catch( const wrong_number_of_args_exception& e )
585  {
587  ( peer->getName(), evname + ".read", e.wanted, e.received );
588  }
589  catch( const wrong_types_of_args_exception& e )
590  {
592  ( peer->getName(), evname + ".read", e.whicharg, e.expected_, e.received_ );
593  }
594  elsestate = 0;
595  elseProgram.reset();
596  } else { // is an operation
597  assert( peer->provides()->hasMember(evname) );
598  bool res;
599  if (curcondition == 0)
601 
602  // if ( elsestate != 0)
603  // res = curtemplate->createEventTransition( &(peer->eventService), evname, evargs, curstate, next_state, curcondition->clone()
604  // else
605  //cerr << "Registering "<<evname<<" handler for SM."<<endl;
606  try {
607  res = curtemplate->createEventTransition( peer->provides(), caller, evname, evargs, curstate, next_state, curcondition->clone(), transProgram );
608  if (!res)
609  throw parse_exception_fatal_semantic_error("StateMachine could not install a Signal Handler for Operation "+evname);
610  }
611  catch( const wrong_number_of_args_exception& e )
612  {
614  ( peer->getName(), evname, e.wanted, e.received );
615  }
616  catch( const wrong_types_of_args_exception& e )
617  {
619  ( peer->getName(), evname, e.whicharg, e.expected_, e.received_ );
620  }
621  catch( const no_asynchronous_operation_exception& e )
622  {
623  throw parse_exception_fatal_semantic_error("StateMachine can't create EventTransition on Operation '" + evname + "' since it was not added with addEventOperation()." );
624  }
625  catch( ... )
626  {
627  assert( false );
628  }
629 
630  assert( res ); // checked in seeneventname()
631  elsestate = 0;
632  elseProgram.reset();
633  return; // we installed the Signal Handler !
634  }
635  // finally, install the handler:
636  curtemplate->transitionSet( curstate, next_state, curcondition->clone(), transProgram, rank--, selectln );
637  }
638 
640  delete curcondition;
641  curcondition = 0;
642  selectln = 0;
643  transProgram.reset();
644  }
645 
647  // cleanup all event related state.
648  evname.clear();
649  evargs.clear();
650  }
651 
653  {
654  assert( !curcondition );
656  assert( curcondition );
658  selectln = mpositer.get_position().line - ln_offset;
659 
660  curtemplate->preconditionSet(curstate, curcondition, selectln );
661  selectln = 0;
662  curcondition = 0;
663  }
664 
665 
667  {
668  assert( curtemplate );
669  assert( ! curstate );
670 
671  // reclaim the defined variables:
672 
673 
674  // Check if the Initial and Final States are ok.
675  if ( curtemplate->getInitialState() == 0 )
676  ORO_THROW( parse_exception_semantic_error("No initial state defined."));
677  if ( curtemplate->getFinalState() == 0 )
678  ORO_THROW( parse_exception_semantic_error("No final state defined."));
679 
680  if ( curtemplate->getStateList().empty() )
681  ORO_THROW( parse_exception_semantic_error("No states defined in this state machine !"));
682 
683  // Check if all States are defined.
684  vector<string> states = curtemplate->getStateList();
685  for( vector<string>::const_iterator it = states.begin(); it != states.end(); ++it)
686  {
687  assert( dynamic_cast<StateDescription*>( curtemplate->getState( *it ) ) );
688  StateDescription* sd = static_cast<StateDescription*>( curtemplate->getState( *it ) );
689  if ( !sd->isDefined() )
690  ORO_THROW( parse_exception_semantic_error("State " + *it + " not defined, but referenced to."));
691  }
692 
693  // retrieve _all_ defined variables and parameters, store them and cleanup the
694  // valuechangeparser.
695  valuechangeparser->store( curtemplate->getService() );
697 
698  // prepend the commands for initialising the subMachine
699  // variables..
700  assert( curtemplate->getInitCommand() == 0);
701  if ( varinitcommands.size() > 1 )
702  {
703  CommandComposite* comcom = new CommandComposite;
704  for ( std::vector<ActionInterface*>::iterator i = varinitcommands.begin();
705  i != varinitcommands.end(); ++i )
706  comcom->add( *i );
707  curtemplate->setInitCommand( comcom );
708  }
709  else if (varinitcommands.size() == 1 )
710  curtemplate->setInitCommand( *varinitcommands.begin() );
711 
712  varinitcommands.clear();
713 
714  // remove temporary subMachine peers from current task.
715  for( StateMachine::ChildList::const_iterator it= curtemplate->getChildren().begin();
716  it != curtemplate->getChildren().end(); ++it ) {
717  ParsedStateMachine* psc = dynamic_cast<ParsedStateMachine*>( it->get() );
718  if (psc) {
719  // remove from parent
720  context->provides()->removeService( psc->getService()->getName() );
721  }
722 
723  }
724 
725  // finally :
726  curtemplate->finish();
727 
728  delete progParser;
729  progParser = 0;
730 
733 
734  // save curmachinename for saveText.
735  curobject.reset();
736  curtemplate.reset();
737  }
738 
739  std::vector<ParsedStateMachinePtr> StateGraphParser::parse( iter_t& begin, iter_t end )
740  {
741  //skip_parser_t skip_parser = SKIP_PARSER;
742  //iter_pol_t iter_policy( skip_parser );
743  //#define SKIP_PARSER
744  skip_parser_t skip_parser = comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser->skipper;
745  iter_pol_t iter_policy( skip_parser );
746  scanner_pol_t policies( iter_policy );
747  scanner_t scanner( begin, end, policies );
748 
749  // reset the condition-transition priority.
750  rank = 0;
751 
752  this->storeOffset();
753 
754  try {
755  if ( ! production.parse( scanner ) )
756  {
757  // on error, we clear all remaining data, cause we can't
758  // guarantee consistency...
759  clear();
760  throw file_parse_exception(
761  new parse_exception_syntactic_error( "Syntax error" ),
762  mpositer.get_position().file, mpositer.get_position().line,
763  mpositer.get_position().column );
764  }
765  std::vector<ParsedStateMachinePtr> ret = values( rootmachines );
766  rootmachines.clear();
767  return ret;
768  }
769  catch( const parser_error<std::string, iter_t>& e )
770  {
771  // on error, we clear all remaining data, cause we can't
772  // guarantee consistency...
773  clear();
774  throw file_parse_exception(
775  new parse_exception_syntactic_error( e.descriptor ),
776  mpositer.get_position().file, mpositer.get_position().line,
777  mpositer.get_position().column );
778  }
779  catch( const parser_error<GraphSyntaxErrors, iter_t>& )
780  {
781  // on error, we clear all remaining data, cause we can't
782  // guarantee consistency...
783  clear();
784  throw file_parse_exception(
785  new parse_exception_syntactic_error( "Expected one of: entry, handle, exit, transitions" ),
786  mpositer.get_position().file, mpositer.get_position().line,
787  mpositer.get_position().column );
788  }
789  catch( const parse_exception& e )
790  {
791  // on error, we clear all remaining data, cause we can't
792  // guarantee consistency...
793  clear();
794  throw file_parse_exception(
795  e.copy(), mpositer.get_position().file,
796  mpositer.get_position().line, mpositer.get_position().column );
797  }
798 // catch( ... ) {
799 // assert( false );
800 // }
801  }
802 
804  clear();
805  delete valuechangeparser;
806  delete expressionparser;
807  delete conditionparser;
808  delete peerparser;
809  }
810 
812 
813  // remove tmp vars from TaskContext
815 
816  // in case of corrupt file, skipeol could have remained on false,
817  // so make sure it is set correctly again
818  commonparser->skipeol = true;
819  selectln = 0;
820  transProgram.reset();
821  elseProgram.reset();
822  delete argsparser;
823  argsparser = 0;
824  delete curcondition;
825  curcondition = 0;
826  // we own curstate, but not through this pointer...
827  curstate = 0;
828  delete curnonprecstate;
829  curnonprecstate = 0;
830  // we own curmachinebuilder, but not through this pointer...
831  curmachinebuilder = 0;
832  curinstantiatedmachine.reset();
833  // If non null, there was a parse-error, undo all :
834  if ( curtemplate )
835  {
836 
837  // remove temporary subMachine peers from current task.
838  for( StateMachine::ChildList::const_iterator it= curtemplate->getChildren().begin();
839  it != curtemplate->getChildren().end(); ++it ) {
840  ParsedStateMachine* psc = dynamic_cast<ParsedStateMachine*>( it->get() );
841  if (psc && psc->getService() ) {
842  context->provides()->removeService( psc->getService()->getName() );
843  }
844  }
845  // remove all 'this' data factories
846  curtemplate->getService()->clear();
847 
848  // will also delete all children :
849  curtemplate.reset();
850  }
851  // should be empty in most cases :
852  for ( std::vector<ActionInterface*>::iterator i = varinitcommands.begin();
853  i != varinitcommands.end(); ++ i )
854  delete *i;
855  varinitcommands.clear();
856  for ( std::vector<ActionInterface*>::iterator i = paraminitcommands.begin();
857  i != paraminitcommands.end(); ++ i )
858  delete *i;
859  paraminitcommands.clear();
860  for ( machinebuilders_t::iterator i = machinebuilders.begin();
861  i != machinebuilders.end(); ++i )
862  delete i->second;
863  machinebuilders.clear();
864  for (std::map<std::string,ConditionCache*>::iterator i = cur_port_events.begin();
865  i != cur_port_events.end(); ++i )
866  delete i->second;
867  cur_port_events.clear();
868  for (std::map<std::string,ConditionCache*>::iterator i = global_port_events.begin();
869  i != global_port_events.end(); ++i )
870  delete i->second;
871  global_port_events.clear();
872  }
873 
875  // the 'type' of the SC :
876  curmachinename = std::string ( begin, end );
877 
878  // check if the type exists already :
879  if ( machinebuilders.count( curmachinename ) != 0 )
880  ORO_THROW( parse_exception_semantic_error("StateMachine type " + curmachinename + " redefined."));
881 
882  curtemplate.reset(new ParsedStateMachine());
883  // Connect the new SC to the relevant machines.
884  // 'sc' acts as a stack for storing variables.
886  curobject->setName( curmachinename );
887  curtemplate->setService( curobject ); // store.
888 
889  // we pass the plain file positer such that parse errors are
890  // refering to correct file line numbers.
892 
893  // set the 'type' name :
894  curtemplate->setName( curmachinename, false );
895  }
896 
898  // stores the begining of a (possible) new statemachine definition.
899  // start line number :
900  ln_offset = mpositer.get_position().line - 1;
901  // start of text :
903  }
904 
906  assert( curmachinename.length() != 0 );
907  //cerr << std::string(begin, end)<<endl;
908  if ( machinebuilders.count( curmachinename ) == 0 )
909  return; // yes this might be possible
910  // due to the shared-text implementation, we can set the text afterwards.
911  machinebuilders[curmachinename]->item()->setText( std::string( saveStartPos, end) );
912  this->storeOffset();
913  }
914 
916  // we postpone the current state
917  assert( curnonprecstate == 0 );
919  // add the postponed state in PSM :
920  curtemplate->addState( curnonprecstate );
921  }
922 
924  curtemplate->transitionSet( curstate, curnonprecstate, new ConditionTrue, rank--, mpositer.get_position().line - ln_offset );
925  curstate->setDefined( true );
927  curnonprecstate = 0;
928  }
929 
931  isroot = true;
932  }
933 
935  // first reset the flag.
936  isroot = false;
937  if( rootmachines.find( curinstmachinename ) != rootmachines.end() )
938  ORO_THROW( parse_exception_semantic_error( "Root machine \"" + curinstmachinename + "\" already defined." ));
940 
941  // recursively set the name of this SC and all subs :
942  // furthermore, it adds the TC of each child as peer TC to the parent.
943  curinstantiatedmachine->setName( curinstmachinename, true );
944 
945  // check if the type exists already :
946  if ( context->provides()->hasService( curinstmachinename ) )
947  ORO_THROW( parse_exception_semantic_error("TaskContext '"+context->getName()+"' has already a Service named '" + curinstmachinename + "' ."));
948 
949  // Transfer ownership to the owning task.
950  context->provides()->addService( curinstantiatedmachine->getService() );
951 
952  curinstantiatedmachine.reset();
953  curinstmachinename.clear();
954  }
955 
957  if ( find_if( curtemplate->getChildren().begin(),
958  curtemplate->getChildren().end(),
959  boost::bind( equal_to<string>(), boost::bind(&StateMachine::getName,_1), curinstmachinename )) != curtemplate->getChildren().end() )
960  ORO_THROW( parse_exception_semantic_error( "SubMachine \"" + curinstmachinename + "\" already defined." ));
961 
962  // Since we parse in the task context, we must _temporarily_
963  // make each subMachine a peer of the task so that we can access
964  // its methods.
965 
966  // Warning: use context->unmountService() since curinstantiatedmachine must owns it.
967  if ( !context->provides()->addService( curinstantiatedmachine->getService() ) )
969  "Name clash: name of instantiated machine \"" + curinstmachinename +
970  "\" already used as object name in task '"+context->getName()+"'." ));
971 
972  // SM child relation
973  curtemplate->addChild( curinstantiatedmachine );
974  // sub-Service relation.
975  curtemplate->getService()->addService( curinstantiatedmachine->getService() );
976 
977  curinstantiatedmachine->setName(curinstmachinename, false ); // not recursive !
978 
979  curinstantiatedmachine.reset();
980  curinstmachinename.clear();
981  }
982 
984  assert( curmachinebuilder == 0 );
985  std::string name( begin, end );
986  machinebuilders_t::iterator i = machinebuilders.find( name );
987  if ( i == machinebuilders.end() )
988  ORO_THROW( parse_exception_semantic_error( "StateMachine \"" + name + "\" not defined." ));
989  curmachinebuilder = i->second;
990  }
991 
993  assert( curmachinebuilder != 0 );
994  assert( curinstmachinename.empty() );
995  curinstmachinename = std::string( begin, end );
996  }
997 
999  assert( curmachineinstargumentname.empty() );
1000  std::string name( begin, end );
1002  }
1003 
1006  // let's not forget this...
1010  "In initialisation of StateMachine \"" + curinstmachinename +
1011  "\": Parameter \"" + curmachineinstargumentname +"\" initialised twice..." ));
1014  }
1015 
1017  {
1018  // TODO : move this code to the ParsedStateMachine builder.
1019 
1020  // Create a full depth copy (including subMachines)
1021  // if RootMachine, make special copy which fixes attributes such
1022  // that on subsequent copy() they keep pointing to same var.
1023  // use shared_ptr to release on throw's below.
1025 
1026  // we stored the attributes which are params of nsc
1027  // in the build operation :
1028  machineparams_t params = nsc->getParameters();
1029 
1030  // first run over the given parameters to see if they all exist in
1031  // the context we're instantiating...
1032  for ( machineparamvalues_t::iterator i = curinstmachineparams.begin(); i != curinstmachineparams.end(); ++i )
1033  {
1034  machineparams_t::iterator j = params.find( i->first );
1035  if ( j == params.end() )
1036  ORO_THROW( parse_exception_semantic_error( "No parameter \"" + i->first + "\" in this StateMachine." ) );
1037  }
1038 
1039  for ( machineparams_t::iterator i = params.begin(); i != params.end(); ++i )
1040  {
1041  machineparamvalues_t::iterator j = curinstmachineparams.find( i->first );
1042  if ( j == curinstmachineparams.end() )
1044  "No value given for argument \"" + i->first + "\" in instantiation of this StateMachine." ));
1045 #ifndef ORO_EMBEDDED
1046  try {
1047  paraminitcommands.push_back( i->second->getDataSource()->updateAction( j->second.get() ) );
1048  }
1049  catch( const bad_assignment& )
1050  {
1051  throw parse_exception_semantic_error("Attempt to initialize parameter '"+i->first+"' with a value which is of a different type." );
1052  }
1053 #else
1054  ActionInterface* ret = i->second->getDataSource()->updateAction( j->second.get());
1055  if (ret)
1056  paraminitcommands.push_back( ret );
1057  else
1058  return;
1059 #endif
1060  }
1061 
1062  curinstantiatedmachine = nsc;
1063 
1064  // prepend the commands for initialising the subMachine
1065  // parameters
1066  if ( paraminitcommands.size() > 0 )
1067  {
1068  CommandComposite* comcom = new CommandComposite;
1069  for ( std::vector<ActionInterface*>::iterator i = paraminitcommands.begin();
1070  i != paraminitcommands.end(); ++i )
1071  comcom->add( *i );
1072  // init the vars as last (if any), so that they can be inited by an expression containing the params :
1073  if ( curinstantiatedmachine->getInitCommand() )
1074  comcom->add( curinstantiatedmachine->getInitCommand() );
1075  curinstantiatedmachine->setInitCommand( comcom );
1076  }
1077  paraminitcommands.clear();
1078 
1079  curmachinebuilder = 0;
1080  curinstmachineparams.clear();
1081 
1082  // set the TaskContext name to the instance name :
1083  curinstantiatedmachine->getService()->setName(curinstmachinename );
1084  }
1085 
1087  std::vector<ActionInterface*> acv = valuechangeparser->assignCommands();
1088  for(std::vector<ActionInterface*>::iterator it = acv.begin(); it!=acv.end(); ++it)
1089  varinitcommands.push_back( *it );
1090  // this only clears the last parsed variables, not the 'store' (see reset())
1092  }
1093 
1095  std::vector<std::string> pnames = valuechangeparser->definedNames();
1096  std::vector<AttributeBase*> tbases = valuechangeparser->definedValues();
1097  assert( pnames.size() == tbases.size() );
1098  for (unsigned int i = 0; i < pnames.size(); ++i)
1099  curtemplate->addParameter( pnames[i] , tbases[i] );
1100  // this only clears the last parsed variables, not the 'store' (see reset())
1102  }
1103 
1104 
1105 }
ProgramInterface * getHandleProgram() const
#define keyword_p(word)
std::vector< base::DataSourceBase::shared_ptr > result()
unsigned int selectln
are we instantiating a rootmachine ?
void setEntryProgram(ProgramInterfacePtr entry)
std::vector< base::AttributeBase * > definedValues()
void seenmachineinstargumentname(iter_t begin, iter_t end)
void saveText(iter_t begin, iter_t end)
ConditionInterface * getParseResult()
Service::shared_ptr provides()
#define ORO_THROW(x)
Definition: Exceptions.hpp:52
void setHandleProgram(ProgramInterfacePtr handle)
void setRunProgram(ProgramInterfacePtr run)
This interface represents the concept of a condition which can be evaluated and return true or false...
const std::string & getName() const
const std::string & getName() const
Get the name of this state.
Definition: mystd.hpp:163
bool skipeol
Saves eol skipping state.
This class represents a state with all actions stored in an external program.
StateGraphParser(iter_t &positer, TaskContext *tc, ExecutionEngine *caller, CommonParser *cp)
void statedef(iter_t s, iter_t f)
virtual ConditionInterface * clone() const =0
A Parser for Orocos Program Scripts.
boost::shared_ptr< ProgramInterface > ProgramInterfacePtr
virtual parse_exception * copy() const =0
void initBodyParser(const std::string &name, Service::shared_ptr stck, int offset)
This class contains some very common parser definitions.
machineparamvalues_t curinstmachineparams
std::map< std::string, base::AttributeBase * > machineparams_t
void doselect(const std::string &name)
std::map< std::string, ConditionCache * > global_port_events
ParsedStateMachinePtr curinstantiatedmachine
void store(Service::shared_ptr other)
scanner< iter_t, scanner_pol_t > scanner_t
ProgramInterface * getEntryProgram() const
ParsedStateMachinePtr getParserResult()
std::vector< base::ActionInterface * > varinitcommands
void inprogram(const std::string &name)
void setExitProgram(ProgramInterfacePtr exit)
skip_parser_iteration_policy< skip_parser_t > iter_pol_t
boost::shared_ptr< StateMachineService > getService() const
functor_parser< eol_skip_functor > skipper
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
std::vector< std::string > definedNames()
base::DataSourceBase::shared_ptr getResult()
rule< scanner_t > rule_t
StateMachineBuilder * curmachinebuilder
void seenmachinetypename(iter_t begin, iter_t end)
std::vector< base::DataSourceBase::shared_ptr > evargs
store line number of select&#39;s &#39;if&#39; statement.
boost::shared_ptr< StateMachineService > curobject
boost::shared_ptr< ProgramInterface > transProgram
std::map< std::string, ConditionCache * > cur_port_events
ProgramInterface * getRunProgram() const
boost_spirit::alternative< boost_spirit::alternative< boost_spirit::alternative< boost_spirit::alternative< boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::alternative< boost_spirit::eol_parser, boost_spirit::end_parser >, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme >, boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::alternative< boost_spirit::eol_parser, boost_spirit::end_parser >, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme > >, boost_spirit::confix_parser< boost_spirit::impl::string_as_parser::type, boost_spirit::kleene_star< boost_spirit::anychar_parser >, boost_spirit::impl::string_as_parser::type, boost_spirit::unary_parser_category, boost_spirit::non_nested, boost_spirit::is_lexeme > >, boost_spirit::difference< boost_spirit::space_parser, boost_spirit::eol_parser > >, boost_spirit::functor_parser< eol_skip_functor > > skip_parser_t
boost::shared_ptr< ProgramInterface > elseProgram
void seeneventname(iter_t s, iter_t f)
virtual void add(base::ActionInterface *com)
void seenstatemachinename(iter_t begin, iter_t end)
std::vector< base::ActionInterface * > assignCommands()
ParsedStateMachinePtr build(bool instantiate)
std::vector< typename MapT::mapped_type > values(const MapT &map)
Definition: mystd.hpp:140
boost::intrusive_ptr< DataSourceBase > shared_ptr
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:53
std::vector< base::ActionInterface * > paraminitcommands
our_pos_iter_t iter_t
void seeninstmachinename(iter_t begin, iter_t end)
boost::shared_ptr< ProgramInterface > finishProgram()
boost::shared_ptr< ParsedStateMachine > ParsedStateMachinePtr
scanner_policies< iter_pol_t > scanner_pol_t
Based on the software pattern &#39;composite&#39;, this class RTT_SCRIPTING_API allows composing command obje...
const ExecutionEngine * engine() const
Definition: TaskCore.hpp:306
ProgramInterface * getExitProgram() const
This class represents a stateMachine as a Service in the Orocos TaskContext system.
std::vector< ParsedStateMachinePtr > parse(iter_t &begin, iter_t end)
virtual const std::string & getName() const
void seenselect(iter_t s, iter_t f)


rtt
Author(s): RTT Developers
autogenerated on Fri Oct 25 2019 03:59:44