$search
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 StateGraphParser.cxx 00003 00004 StateGraphParser.cxx - description 00005 ------------------- 00006 begin : Mon May 10 2004 00007 copyright : (C) 2004 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.ac.be 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU Lesser General Public * 00013 * License as published by the Free Software Foundation; either * 00014 * version 2.1 of the License, or (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00019 * Lesser General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation, Inc., 59 Temple Place, * 00024 * Suite 330, Boston, MA 02111-1307 USA * 00025 * * 00026 ***************************************************************************/ 00027 00028 #include "parser-debug.hpp" 00029 #include "parse_exception.hpp" 00030 #include "StateGraphParser.hpp" 00031 #include "CommonParser.hpp" 00032 #include "ConditionParser.hpp" 00033 #include "ConditionCompare.hpp" 00034 #include "ConditionComposite.hpp" 00035 #include "ConditionCache.hpp" 00036 #include "ConditionBoolDataSource.hpp" 00037 #include "ValueChangeParser.hpp" 00038 #include "ProgramGraphParser.hpp" 00039 #include "PeerParser.hpp" 00040 #include "ArgumentsParser.hpp" 00041 #include "StateMachineBuilder.hpp" 00042 #include "../TaskContext.hpp" 00043 #include "StateMachineService.hpp" 00044 00045 #include "CommandComposite.hpp" 00046 #include "../internal/Exceptions.hpp" 00047 #include "../base/AttributeBase.hpp" 00048 #include "ConditionTrue.hpp" 00049 #include "ConditionInvert.hpp" 00050 #include "StateDescription.hpp" 00051 #include "ParsedStateMachine.hpp" 00052 00053 #include <iostream> 00054 #include <functional> 00055 #include <algorithm> 00056 #include <boost/bind.hpp> 00057 #include <boost/lambda/lambda.hpp> 00058 #include <boost/call_traits.hpp> 00059 #include <iostream> 00060 #include <memory> 00061 #include "../internal/mystd.hpp" 00062 00063 namespace RTT 00064 { 00065 using namespace boost; 00066 using namespace detail; 00067 using boost::bind; 00068 00069 using namespace std; 00070 00071 namespace { 00072 enum GraphSyntaxErrors 00073 { 00074 state_expected, 00075 handle_expected, 00076 transition_expected, 00077 }; 00078 00079 boost::spirit::classic::assertion<GraphSyntaxErrors> expect_state(state_expected); 00080 boost::spirit::classic::assertion<GraphSyntaxErrors> expect_handle(handle_expected); 00081 boost::spirit::classic::assertion<GraphSyntaxErrors> expect_transition(transition_expected); 00082 boost::spirit::classic::assertion<std::string> expect_end("Ending '}' expected ( or could not find out what this line means )."); 00083 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 )."); 00084 boost::spirit::classic::assertion<std::string> expect_if("Wrongly formatted \"if ... then select\" clause."); 00085 boost::spirit::classic::assertion<std::string> expect_select("'select' statement required after emty transition program."); 00086 boost::spirit::classic::assertion<std::string> expect_select_ident("'select' requires a valid state name."); 00087 boost::spirit::classic::assertion<std::string> expect_comma("Expected a comma separator."); 00088 boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier."); 00089 boost::spirit::classic::assertion<std::string> expect_event_or_if("Expected an event name or an if clause in transition statement."); 00090 boost::spirit::classic::assertion<std::string> expect_open("Open brace expected."); 00091 boost::spirit::classic::assertion<std::string> expect_eof("Invalid input in file."); 00092 boost::spirit::classic::assertion<std::string> expect_eol("Newline expected at end of statement."); 00093 boost::spirit::classic::assertion<std::string> expect_semicolon("Semi colon expected after statement."); 00094 boost::spirit::classic::assertion<std::string> expect_open_parenth( "Open parenthesis expected." ); 00095 boost::spirit::classic::assertion<std::string> expect_close_parenth( "Open parenthesis expected." ); 00096 boost::spirit::classic::assertion<std::string> expect_eventselect("'select' statement required after event or transition program."); 00097 boost::spirit::classic::assertion<std::string> expect_eventargs("Could not parse arguments after event."); 00098 } 00099 00100 00101 StateGraphParser::StateGraphParser( iter_t& positer, 00102 TaskContext* tc, ExecutionEngine* tcaller, CommonParser* cp ) 00103 : context( tc ), 00104 caller( tcaller ), 00105 mpositer( positer ), 00106 ln_offset(0), 00107 curtemplate(), 00108 curinstantiatedmachine(), 00109 curmachinebuilder( 0 ), 00110 curinitialstateflag( false ), 00111 curfinalstateflag( false ), 00112 curstate( 0 ), 00113 curnonprecstate( 0 ), 00114 progParser( 0 ), 00115 elsestate(0), 00116 curcondition( 0 ), 00117 isroot(false), 00118 selectln(0), 00119 evname(""), 00120 commonparser( cp ), 00121 conditionparser( new ConditionParser( context, caller, *commonparser ) ), 00122 valuechangeparser( new ValueChangeParser(context, *commonparser, context->provides(), caller) ), 00123 expressionparser( new ExpressionParser(context, caller, *commonparser) ), 00124 argsparser(0), 00125 peerparser( new PeerParser(context, *commonparser, true) ) // full-path peer parser for events. 00126 { 00127 BOOST_SPIRIT_DEBUG_RULE( production ); 00128 BOOST_SPIRIT_DEBUG_RULE( body ); 00129 BOOST_SPIRIT_DEBUG_RULE( rootmachineinstantiation ); 00130 BOOST_SPIRIT_DEBUG_RULE( statemachine ); 00131 BOOST_SPIRIT_DEBUG_RULE( machineinstantiation ); 00132 BOOST_SPIRIT_DEBUG_RULE( statemachinecontent ); 00133 BOOST_SPIRIT_DEBUG_RULE( varline ); 00134 BOOST_SPIRIT_DEBUG_RULE( state ); 00135 BOOST_SPIRIT_DEBUG_RULE( vardec ); 00136 BOOST_SPIRIT_DEBUG_RULE( subMachinedecl ); 00137 BOOST_SPIRIT_DEBUG_RULE( statecontent ); 00138 BOOST_SPIRIT_DEBUG_RULE( statecontentline ); 00139 BOOST_SPIRIT_DEBUG_RULE( entry ); 00140 BOOST_SPIRIT_DEBUG_RULE( preconditions ); 00141 BOOST_SPIRIT_DEBUG_RULE( precondition ); 00142 BOOST_SPIRIT_DEBUG_RULE( handle ); 00143 BOOST_SPIRIT_DEBUG_RULE( transitions ); 00144 BOOST_SPIRIT_DEBUG_RULE( transition ); 00145 BOOST_SPIRIT_DEBUG_RULE( exit ); 00146 BOOST_SPIRIT_DEBUG_RULE( transline ); 00147 BOOST_SPIRIT_DEBUG_RULE( eventline ); 00148 BOOST_SPIRIT_DEBUG_RULE( ifbranch ); 00149 BOOST_SPIRIT_DEBUG_RULE( elsebranch ); 00150 BOOST_SPIRIT_DEBUG_RULE( progselect ); 00151 BOOST_SPIRIT_DEBUG_RULE( program ); 00152 BOOST_SPIRIT_DEBUG_RULE( selector ); 00153 BOOST_SPIRIT_DEBUG_RULE( machineinstarguments ); 00154 BOOST_SPIRIT_DEBUG_RULE( machineinstargument ); 00155 BOOST_SPIRIT_DEBUG_RULE( machinememvar ); 00156 BOOST_SPIRIT_DEBUG_RULE( machinevariable ); 00157 BOOST_SPIRIT_DEBUG_RULE( machineparam ); 00158 BOOST_SPIRIT_DEBUG_RULE( machineconstant ); 00159 BOOST_SPIRIT_DEBUG_RULE( machinealias ); 00160 BOOST_SPIRIT_DEBUG_RULE( subMachinevarchange ); 00161 00162 storeOffset(); 00163 00164 production = *body >> expect_eof(end_p); 00165 00166 body = statemachine[ boost::bind( &StateGraphParser::seenstatemachineend, this ) ][boost::bind( &StateGraphParser::saveText, this, _1, _2)] 00167 | rootmachineinstantiation; 00168 00169 00170 rootmachineinstantiation = 00171 keyword_p("RootMachine")[boost::bind (&StateGraphParser::startrootmachineinstantiation, this) ] 00172 >> machineinstantiation[ boost::bind( &StateGraphParser::seenrootmachineinstantiation, this ) ]; 00173 00174 statemachine = 00175 keyword_p("StateMachine") //[boost::bind( &StateGraphParser::storeOffset, this)] 00176 >> expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seenstatemachinename, this, _1, _2 )] ) 00177 >> expect_open( ch_p( '{' ) ) 00178 >> statemachinecontent 00179 >> expect_end( ch_p( '}' ) ); 00180 00181 // Zero or more declarations and Zero or more states. Once a state is encountered, no more global transitions may be defined. 00182 statemachinecontent = *( varline | transitions | transition) >> *( varline | state); 00183 00184 varline = vardec[lambda::var(commonparser->skipeol) = false] >> commonparser->eos[lambda::var(commonparser->skipeol) = true]; 00185 00186 vardec = subMachinedecl | machinememvar | machineparam; 00187 00188 machinememvar = ( machineconstant | machinevariable | machinealias )[boost::bind( &StateGraphParser::seenmachinevariable, this )]; 00189 machineconstant = valuechangeparser->constantDefinitionParser(); 00190 machinevariable = valuechangeparser->variableDefinitionParser(); 00191 machinealias = valuechangeparser->aliasDefinitionParser(); 00192 00193 machineparam = valuechangeparser->paramDefinitionParser()[boost::bind( &StateGraphParser::seenmachineparam, this )]; 00194 00195 subMachinedecl = keyword_p("SubMachine") 00196 >> machineinstantiation[boost::bind( &StateGraphParser::seensubMachineinstantiation, this )]; 00197 00198 machineinstantiation = 00199 expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seenmachinetypename, this, _1, _2 )] ) 00200 >> expect_ident( commonparser->identifier[ boost::bind( &StateGraphParser::seeninstmachinename, this, _1, _2 )] ) 00201 >> ( ! ( ch_p( '(' ) 00202 >> !machineinstarguments 00203 >> expect_close_parenth( ch_p( ')' ) ) ) )[ boost::bind( &StateGraphParser::seenmachineinstantiation, this )]; 00204 00205 machineinstarguments = 00206 machineinstargument >> *( ',' >> machineinstargument ); 00207 00208 machineinstargument = 00209 commonparser->identifier[ boost::bind( &StateGraphParser::seenmachineinstargumentname, this, _1, _2 )] 00210 >> '=' 00211 >> expressionparser->parser()[ boost::bind( &StateGraphParser::seenmachineinstargumentvalue, this )]; 00212 00213 state = 00214 !( keyword_p( "initial" )[boost::bind( &StateGraphParser::seeninitialstate,this )] 00215 | keyword_p( "final" )[boost::bind( &StateGraphParser::seenfinalstate,this )] ) 00216 >> keyword_p( "state" ) 00217 >> expect_ident(commonparser->identifier[ boost::bind( &StateGraphParser::statedef, this, _1, _2 ) ]) 00218 >> expect_open(ch_p( '{' )) 00219 >> statecontent 00220 >> expect_end_of_state(ch_p( '}' ))[ boost::bind( &StateGraphParser::seenstateend, this ) ]; 00221 00222 // the content of a program can be any number of lines 00223 // a line is not strictly defined in the sense of text-line. 00224 statecontent = *statecontentline; 00225 00226 // a state can contain various programs and variable definitions 00227 statecontentline = 00228 entry 00229 | preconditions 00230 | run 00231 | handle 00232 | transitions 00233 | transition 00234 | exit 00235 | (machinememvar[lambda::var(commonparser->skipeol) = false] >> commonparser->eos[lambda::var(commonparser->skipeol) = true]); 00236 00237 precondition = keyword_p( "precondition") 00238 >> conditionparser->parser()[ boost::bind( &StateGraphParser::seenprecondition, this)] ; 00239 00240 preconditions = (keyword_p( "preconditions" )[ boost::bind( &StateGraphParser::inpreconditions, this )] 00241 >> expect_open( ch_p( '{' )) 00242 >> *transline[boost::bind(&StateGraphParser::seenendcondition,this)] 00243 >> expect_end( ch_p( '}' ) )[ 00244 boost::bind( &StateGraphParser::seenpreconditions, this )]) | precondition; 00245 00246 entry = keyword_p( "entry" )[ boost::bind( &StateGraphParser::inprogram, this, "entry" )] 00247 >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[ 00248 boost::bind( &StateGraphParser::seenentry, this )]; 00249 00250 run = keyword_p( "run" )[ boost::bind( &StateGraphParser::inprogram, this, "run" )] 00251 >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[ 00252 boost::bind( &StateGraphParser::seenrun, this )]; 00253 00254 exit = keyword_p( "exit" )[ boost::bind( &StateGraphParser::inprogram, this, "exit" )] 00255 >> expect_open(ch_p('{')) >> programBody >> expect_end(ch_p('}'))[ 00256 boost::bind( &StateGraphParser::seenexit, this )]; 00257 00258 handle = keyword_p( "handle" )[ boost::bind( &StateGraphParser::inprogram, this, "handle" )] 00259 >> expect_open(ch_p('{'))>> programBody >> expect_end(ch_p('}'))[ 00260 boost::bind( &StateGraphParser::seenhandle, this )]; 00261 00262 // formal: 00263 // transition [event] [[ {program} ][ select s]] | [ if c then ][ {program} ][select s][ else [ {program} ][select s]] 00264 // parsed: 00265 // transition [ [if c then ][ {program} ][select s][ else [ {program} ][select s]]] 00266 // | [ event [[ {program} ][ select s]] | [ if c then ][ {program} ][select s][ else [ {program} ][select s]] ] 00267 // rules: 00268 // transition = "transition" >> (transline | eventline) 00269 // transline = progselect 00270 // | (ifbranch >> !elsebranch) 00271 // eventline = eventname >> transline 00272 // progselect = (selector | (program >> !selector)) 00273 // ifbranch = "if" >> c >> "then" >> progselect 00274 // elsebranch = "else" >> progselect 00275 // selector = "select" >> ... 00276 // program = "{" >> ... 00277 // 00278 00279 // old transition statements 00280 // the order of rule "transition" vs "transitions" is important 00281 transitions = ( keyword_p( "transitions" ) 00282 >> expect_open(ch_p('{')) 00283 >> *((transline|eventline)[boost::bind(&StateGraphParser::seenendcondition,this)]) 00284 >> expect_end(ch_p('}')) ); 00285 00286 // new transition statements 00287 transition = keyword_p("transition") >> expect_event_or_if( transline | eventline )[boost::bind(&StateGraphParser::seenendcondition,this)]; 00288 transline = progselect | (ifbranch >> !elsebranch); 00289 00290 // @todo: capturing events are only on local ports ?!. 00291 eventline = commonparser->identifier[ boost::bind( &StateGraphParser::seeneventname, this,_1,_2)] 00293 >> expect_eventargs(argslist[ boost::bind( &StateGraphParser::seeneventargs, this)]) 00294 >> expect_eventselect(transline[ boost::bind( &StateGraphParser::seeneventtrans, this)]); 00295 00296 progselect = selector | (program >> (selector | eps_p[boost::bind( &StateGraphParser::noselect, this )] )); 00297 // | eps_p[boost::bind( &StateGraphParser::noselect, this )] ); // if eos fails skipeol stays false !, see clear() ! 00298 00299 ifbranch = keyword_p( "if") >> conditionparser->parser()[ boost::bind( &StateGraphParser::seencondition, this)] 00300 >> !keyword_p( "then" ) 00301 >> progselect; 00302 elsebranch = keyword_p("else")[boost::bind( &StateGraphParser::seenelse, this )] 00303 >> progselect; 00304 00305 program = 00306 ch_p('{')[ boost::bind( &StateGraphParser::inprogram, this, "transition" )] 00307 >> programBody 00308 >> expect_end(ch_p('}'))[boost::bind( &StateGraphParser::seentransprog, this )]; 00309 00310 selector = keyword_p( "select" ) >> expect_select_ident(( commonparser->identifier[ boost::bind( &StateGraphParser::seenselect, this, _1, _2) ] 00311 >> *(keyword_p("or") >> commonparser->identifier[ boost::bind( &StateGraphParser::seenselect, this, _1, _2) ]) 00312 )[lambda::var(commonparser->skipeol) = false] 00313 >> commonparser->eos[lambda::var(commonparser->skipeol) = true]); 00314 00315 } 00316 00317 rule_t& StateGraphParser::parser() { 00318 return body; 00319 } 00320 00321 ParsedStateMachinePtr StateGraphParser::getParserResult() { 00322 ParsedStateMachinePtr ret; 00323 if ( rootmachines.empty() ) 00324 return ret; 00325 std::vector<ParsedStateMachinePtr> vret = values( rootmachines ); 00326 rootmachines.clear(); 00327 return vret.front(); 00328 } 00329 00330 00331 void StateGraphParser::seeninitialstate() 00332 { 00333 curinitialstateflag = true; 00334 } 00335 00336 void StateGraphParser::seenfinalstate() 00337 { 00338 curfinalstateflag = true; 00339 } 00340 00341 void StateGraphParser::statedef( iter_t s, iter_t f) 00342 { 00343 assert( !curstate ); 00344 00345 std::string def(s, f); 00346 if ( curtemplate->getState( def ) != 0 ) 00347 { 00348 assert( dynamic_cast<StateDescription*>( curtemplate->getState( def ) ) ); 00349 StateDescription* existingstate = static_cast<StateDescription*>( curtemplate->getState( def ) ); 00350 if ( existingstate->isDefined() ) 00351 ORO_THROW(parse_exception_semantic_error("state " + def + " redefined.") ); 00352 else 00353 curstate = existingstate; 00354 curstate->setEntryPoint( mpositer.get_position().line - ln_offset ); 00355 } 00356 else 00357 { 00358 curstate = new StateDescription(def, mpositer.get_position().line - ln_offset ); // create an empty state 00359 curtemplate->addState( curstate ); 00360 } 00361 00362 } 00363 00364 void StateGraphParser::seenstateend() 00365 { 00366 if ( curinitialstateflag ) 00367 { 00368 if ( curtemplate->getInitialState() ) 00369 ORO_THROW(parse_exception_semantic_error( "Attempt to define more than one initial state." )); 00370 else curtemplate->setInitialState( curstate ); 00371 } 00372 if ( curfinalstateflag ) 00373 { 00374 if ( curtemplate->getFinalState() ) 00375 ORO_THROW(parse_exception_semantic_error( "Attempt to define more than one final state." )); 00376 else curtemplate->setFinalState( curstate ); 00377 } 00378 00379 assert( curstate ); 00380 curstate->setDefined( true ); 00381 curstate = 0; 00382 curinitialstateflag = false; 00383 curfinalstateflag = false; 00384 // clear all port-triggered transitions for this state. 00385 cur_port_events.clear(); 00386 } 00387 00388 void StateGraphParser::inprogram(const std::string& name) 00389 { 00390 // setup the progParser to parse the program body, 00391 // dynamically assign this parser to body. 00392 assert( progParser != 0 ); 00393 // program name, stack, line offset. 00394 //cerr << "SGP : Stack is " << curobject->getName() <<endl; 00395 progParser->initBodyParser( name, curobject, ln_offset ); 00396 00397 programBody = progParser->bodyParser(); 00398 } 00399 00400 ProgramInterfacePtr StateGraphParser::finishProgram() 00401 { 00402 return progParser->bodyParserResult(); 00403 } 00404 00405 void StateGraphParser::seenentry() 00406 { 00407 if ( curstate->getEntryProgram() ) 00408 ORO_THROW( parse_exception_semantic_error( "Attempt to define entry twice in state "+ curstate->getName() )); 00409 curstate->setEntryProgram( finishProgram() ); 00410 } 00411 00412 void StateGraphParser::seenexit() 00413 { 00414 if ( curstate->getExitProgram() ) 00415 ORO_THROW( parse_exception_semantic_error( "Attempt to define exit twice in state "+ curstate->getName() )); 00416 curstate->setExitProgram( finishProgram() ); 00417 } 00418 00419 void StateGraphParser::seenhandle() 00420 { 00421 if ( curstate->getHandleProgram() ) 00422 ORO_THROW( parse_exception_semantic_error( "Attempt to define handle twice in state "+ curstate->getName() )); 00423 curstate->setHandleProgram( finishProgram() ); 00424 } 00425 00426 void StateGraphParser::seenrun() 00427 { 00428 if ( curstate->getRunProgram() ) 00429 ORO_THROW( parse_exception_semantic_error( "Attempt to define run twice in state "+ curstate->getName() )); 00430 curstate->setRunProgram( finishProgram() ); 00431 } 00432 00433 void StateGraphParser::seentransprog() 00434 { 00435 transProgram = finishProgram(); 00436 } 00437 00438 void StateGraphParser::seenelseprog() 00439 { 00440 // reuse transProgram to store else progr. See seenselect(). 00441 //transProgram = finishProgram(); 00442 //transProgram->setProgramProcessor(curtemplate->getService()->engine()->programs()); 00443 } 00444 00445 void StateGraphParser::seenelse() 00446 { 00447 assert( curcondition); 00448 curcondition = new ConditionInvert( curcondition ); 00449 } 00450 00451 void StateGraphParser::seencondition() 00452 { 00453 assert( !curcondition ); 00454 curcondition = conditionparser->getParseResult(); 00455 assert( curcondition ); 00456 conditionparser->reset(); 00457 selectln = mpositer.get_position().line - ln_offset; 00458 } 00459 00460 void StateGraphParser::seeneventname(iter_t s, iter_t f) 00461 { 00462 evname = string(s,f); 00463 00464 // seenselect() will use evname to see if event is causing transition 00465 assert(evname.length()); 00466 peer = peerparser->taskObject(); 00467 peerparser->reset(); 00468 00469 // check if it's an operation: 00470 if (peer->hasOperation(evname) ) { 00471 argsparser = 00472 new ArgumentsParser( *expressionparser, context, peer->provides(), 00473 evname, "callback" ); 00474 } else { 00475 // check if it's a port. 00476 if ( peer->hasService(evname) == false || peer->provides(evname)->hasOperation("read") == false) { 00477 if (curstate) 00478 ORO_THROW( parse_exception_fatal_semantic_error("In state "+curstate->getName()+": InputPort or Operation "+evname+" not found in Task "+peer->getName() )); 00479 else 00480 ORO_THROW( parse_exception_fatal_semantic_error("In statemachine: InputPort or Operation "+evname+" not found in Task "+peer->getName() )); 00481 } 00482 argsparser = 00483 new ArgumentsParser( *expressionparser, context, peer->provides(evname), 00484 evname, "read" ); 00485 } 00486 00487 argslist = argsparser->parser(); 00488 } 00489 00490 void StateGraphParser::seeneventargs() 00491 { 00492 evargs = argsparser->result(); 00493 delete argsparser; 00494 argsparser = 0; 00495 } 00496 00497 void StateGraphParser::noselect() 00498 { 00499 // if omitted, implicitly re-enter current state. 00500 if (curstate) 00501 doselect( curstate->getName() ); 00502 else 00503 doselect(""); // global events/transitions 00504 } 00505 00506 void StateGraphParser::seenselect( iter_t s, iter_t f) 00507 { 00508 std::string state_id(s,f); 00509 doselect(state_id); 00510 } 00511 00512 void StateGraphParser::doselect( const std::string& state_id ) 00513 { 00514 StateInterface* next_state = 0; 00515 if ( !state_id.empty() ) { 00516 if ( curtemplate->getState( state_id ) != 0 ) 00517 { 00518 next_state = curtemplate->getState( state_id ); 00519 } 00520 else 00521 { 00522 next_state = new StateDescription(state_id, 1); // create an empty state 00523 curtemplate->addState( next_state ); 00524 } 00525 assert( next_state ); 00526 } 00527 00528 // this transition has a lower priority than the previous one 00529 if ( selectln == 0) 00530 selectln = mpositer.get_position().line - ln_offset; 00531 00532 if (evname.empty()) { 00533 if (curcondition == 0) 00534 curcondition = new ConditionTrue; 00535 } else if ( peer->provides(evname) && peer->provides(evname)->hasOperation("read") ) { // is a port 00536 try { 00537 assert(peer->provides(evname)); // checked in seeneventname() 00538 ConditionInterface* evcondition = 0; 00539 if ( global_port_events.count(evname) ){ 00540 // clone the cached condition in order to avoid a second read on the port. 00541 evcondition = new ConditionBoolDataSource( global_port_events[evname]->getResult().get() ); 00542 } else 00543 if ( cur_port_events.count(evname) ){ 00544 // clone the cached condition in order to avoid a second read on the port. 00545 evcondition = new ConditionBoolDataSource( cur_port_events[evname]->getResult().get() ); 00546 } else { 00547 // combine the implicit 'read(arg) == NewData' with the guard, if any. 00548 DataSourceBase::shared_ptr read_dsb = peer->provides(evname)->produce("read", evargs, context->engine() ); 00549 DataSource<FlowStatus>* read_ds = dynamic_cast<DataSource<FlowStatus>*>(read_dsb.get()); 00550 assert(read_ds); 00551 evcondition = new ConditionCompare<FlowStatus,std::equal_to<FlowStatus> >( new ConstantDataSource<FlowStatus>(NewData), read_ds ); 00552 if (curstate) { 00553 cur_port_events[evname] = new ConditionCache( evcondition ); // caches result until reset(). 00554 evcondition = cur_port_events[evname]->clone(); 00555 } else { 00556 //global event: 00557 global_port_events[evname] = new ConditionCache( evcondition ); // caches result until reset(). 00558 evcondition = global_port_events[evname]->clone(); 00559 } 00560 } 00561 if (curcondition == 0) { 00562 curcondition = evcondition; 00563 } else { 00564 curcondition = new ConditionBinaryCompositeAND( evcondition, curcondition ); 00565 } 00566 } 00567 catch( const wrong_number_of_args_exception& e ) 00568 { 00569 throw parse_exception_wrong_number_of_arguments 00570 ( peer->getName(), evname + ".read", e.wanted, e.received ); 00571 } 00572 catch( const wrong_types_of_args_exception& e ) 00573 { 00574 throw parse_exception_wrong_type_of_argument 00575 ( peer->getName(), evname + ".read", e.whicharg, e.expected_, e.received_ ); 00576 } 00577 elsestate = 0; 00578 elseProgram.reset(); 00579 } else { // is an operation 00580 assert( peer->provides()->hasMember(evname) ); 00581 bool res; 00582 if (curcondition == 0) 00583 curcondition = new ConditionTrue; 00584 00585 // if ( elsestate != 0) 00586 // res = curtemplate->createEventTransition( &(peer->eventService), evname, evargs, curstate, next_state, curcondition->clone() 00587 // else 00588 //cerr << "Registering "<<evname<<" handler for SM."<<endl; 00589 try { 00590 res = curtemplate->createEventTransition( peer->provides(), evname, evargs, curstate, next_state, curcondition->clone(), transProgram ); 00591 if (!res) 00592 throw parse_exception_fatal_semantic_error("StateMachine could not install a Signal Handler for Operation "+evname); 00593 } 00594 catch( const wrong_number_of_args_exception& e ) 00595 { 00596 throw parse_exception_wrong_number_of_arguments 00597 ( peer->getName(), evname, e.wanted, e.received ); 00598 } 00599 catch( const wrong_types_of_args_exception& e ) 00600 { 00601 throw parse_exception_wrong_type_of_argument 00602 ( peer->getName(), evname, e.whicharg, e.expected_, e.received_ ); 00603 } 00604 catch( ... ) 00605 { 00606 assert( false ); 00607 } 00608 00609 assert( res ); // checked in seeneventname() 00610 elsestate = 0; 00611 elseProgram.reset(); 00612 return; // we installed the Signal Handler ! 00613 } 00614 // finally, install the handler: 00615 curtemplate->transitionSet( curstate, next_state, curcondition->clone(), transProgram, rank--, selectln ); 00616 } 00617 00618 void StateGraphParser::seenendcondition() { 00619 delete curcondition; 00620 curcondition = 0; 00621 selectln = 0; 00622 transProgram.reset(); 00623 } 00624 00625 void StateGraphParser::seeneventtrans() { 00626 // cleanup all event related state. 00627 evname.clear(); 00628 evargs.clear(); 00629 } 00630 00631 void StateGraphParser::seenprecondition() 00632 { 00633 assert( !curcondition ); 00634 curcondition = conditionparser->getParseResult(); 00635 assert( curcondition ); 00636 conditionparser->reset(); 00637 selectln = mpositer.get_position().line - ln_offset; 00638 00639 curtemplate->preconditionSet(curstate, curcondition, selectln ); 00640 selectln = 0; 00641 curcondition = 0; 00642 } 00643 00644 00645 void StateGraphParser::seenstatemachineend() 00646 { 00647 assert( curtemplate ); 00648 assert( ! curstate ); 00649 00650 // reclaim the defined variables: 00651 00652 00653 // Check if the Initial and Final States are ok. 00654 if ( curtemplate->getInitialState() == 0 ) 00655 ORO_THROW( parse_exception_semantic_error("No initial state defined.")); 00656 if ( curtemplate->getFinalState() == 0 ) 00657 ORO_THROW( parse_exception_semantic_error("No final state defined.")); 00658 00659 if ( curtemplate->getStateList().empty() ) 00660 ORO_THROW( parse_exception_semantic_error("No states defined in this state machine !")); 00661 00662 // Check if all States are defined. 00663 vector<string> states = curtemplate->getStateList(); 00664 for( vector<string>::const_iterator it = states.begin(); it != states.end(); ++it) 00665 { 00666 assert( dynamic_cast<StateDescription*>( curtemplate->getState( *it ) ) ); 00667 StateDescription* sd = static_cast<StateDescription*>( curtemplate->getState( *it ) ); 00668 if ( !sd->isDefined() ) 00669 ORO_THROW( parse_exception_semantic_error("State " + *it + " not defined, but referenced to.")); 00670 } 00671 00672 // retrieve _all_ defined variables and parameters, store them and cleanup the 00673 // valuechangeparser. 00674 valuechangeparser->store( curtemplate->getService() ); 00675 valuechangeparser->reset(); 00676 00677 // prepend the commands for initialising the subMachine 00678 // variables.. 00679 assert( curtemplate->getInitCommand() == 0); 00680 if ( varinitcommands.size() > 1 ) 00681 { 00682 CommandComposite* comcom = new CommandComposite; 00683 for ( std::vector<ActionInterface*>::iterator i = varinitcommands.begin(); 00684 i != varinitcommands.end(); ++i ) 00685 comcom->add( *i ); 00686 curtemplate->setInitCommand( comcom ); 00687 } 00688 else if (varinitcommands.size() == 1 ) 00689 curtemplate->setInitCommand( *varinitcommands.begin() ); 00690 00691 varinitcommands.clear(); 00692 00693 // remove temporary subMachine peers from current task. 00694 for( StateMachine::ChildList::const_iterator it= curtemplate->getChildren().begin(); 00695 it != curtemplate->getChildren().end(); ++it ) { 00696 ParsedStateMachine* psc = dynamic_cast<ParsedStateMachine*>( it->get() ); 00697 if (psc) { 00698 // remove from parent 00699 context->provides()->removeService( psc->getService()->getName() ); 00700 } 00701 00702 } 00703 00704 // finally : 00705 curtemplate->finish(); 00706 00707 delete progParser; 00708 progParser = 0; 00709 00710 StateMachineBuilder* scb = new StateMachineBuilder( curtemplate ); 00711 machinebuilders[curmachinename] = scb; 00712 00713 // save curmachinename for saveText. 00714 curobject.reset(); 00715 curtemplate.reset(); 00716 } 00717 00718 std::vector<ParsedStateMachinePtr> StateGraphParser::parse( iter_t& begin, iter_t end ) 00719 { 00720 //skip_parser_t skip_parser = SKIP_PARSER; 00721 //iter_pol_t iter_policy( skip_parser ); 00722 //#define SKIP_PARSER 00723 iter_pol_t iter_policy( ( comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser->skipper ) ); 00724 scanner_pol_t policies( iter_policy ); 00725 scanner_t scanner( begin, end, policies ); 00726 00727 // reset the condition-transition priority. 00728 rank = 0; 00729 00730 this->storeOffset(); 00731 00732 try { 00733 if ( ! production.parse( scanner ) ) 00734 { 00735 // on error, we clear all remaining data, cause we can't 00736 // guarantee consistency... 00737 clear(); 00738 throw file_parse_exception( 00739 new parse_exception_syntactic_error( "Syntax error" ), 00740 mpositer.get_position().file, mpositer.get_position().line, 00741 mpositer.get_position().column ); 00742 } 00743 std::vector<ParsedStateMachinePtr> ret = values( rootmachines ); 00744 rootmachines.clear(); 00745 return ret; 00746 } 00747 catch( const parser_error<std::string, iter_t>& e ) 00748 { 00749 // on error, we clear all remaining data, cause we can't 00750 // guarantee consistency... 00751 clear(); 00752 throw file_parse_exception( 00753 new parse_exception_syntactic_error( e.descriptor ), 00754 mpositer.get_position().file, mpositer.get_position().line, 00755 mpositer.get_position().column ); 00756 } 00757 catch( const parser_error<GraphSyntaxErrors, iter_t>& ) 00758 { 00759 // on error, we clear all remaining data, cause we can't 00760 // guarantee consistency... 00761 clear(); 00762 throw file_parse_exception( 00763 new parse_exception_syntactic_error( "Expected one of: entry, handle, exit, transitions" ), 00764 mpositer.get_position().file, mpositer.get_position().line, 00765 mpositer.get_position().column ); 00766 } 00767 catch( const parse_exception& e ) 00768 { 00769 // on error, we clear all remaining data, cause we can't 00770 // guarantee consistency... 00771 clear(); 00772 throw file_parse_exception( 00773 e.copy(), mpositer.get_position().file, 00774 mpositer.get_position().line, mpositer.get_position().column ); 00775 } 00776 // catch( ... ) { 00777 // assert( false ); 00778 // } 00779 } 00780 00781 StateGraphParser::~StateGraphParser() { 00782 clear(); 00783 delete valuechangeparser; 00784 delete expressionparser; 00785 delete conditionparser; 00786 delete peerparser; 00787 } 00788 00789 void StateGraphParser::clear() { 00790 00791 // remove tmp vars from TaskContext 00792 valuechangeparser->reset(); 00793 00794 // in case of corrupt file, skipeol could have remained on false, 00795 // so make sure it is set correctly again 00796 commonparser->skipeol = true; 00797 selectln = 0; 00798 transProgram.reset(); 00799 elseProgram.reset(); 00800 delete argsparser; 00801 argsparser = 0; 00802 delete curcondition; 00803 curcondition = 0; 00804 // we own curstate, but not through this pointer... 00805 curstate = 0; 00806 delete curnonprecstate; 00807 curnonprecstate = 0; 00808 // we own curmachinebuilder, but not through this pointer... 00809 curmachinebuilder = 0; 00810 curinstantiatedmachine.reset(); 00811 // If non null, there was a parse-error, undo all : 00812 if ( curtemplate ) 00813 { 00814 00815 // remove temporary subMachine peers from current task. 00816 for( StateMachine::ChildList::const_iterator it= curtemplate->getChildren().begin(); 00817 it != curtemplate->getChildren().end(); ++it ) { 00818 ParsedStateMachine* psc = dynamic_cast<ParsedStateMachine*>( it->get() ); 00819 if (psc && psc->getService() ) { 00820 context->provides()->removeService( psc->getService()->getName() ); 00821 } 00822 } 00823 // remove all 'this' data factories 00824 curtemplate->getService()->clear(); 00825 00826 // will also delete all children : 00827 curtemplate.reset(); 00828 } 00829 // should be empty in most cases : 00830 for ( std::vector<ActionInterface*>::iterator i = varinitcommands.begin(); 00831 i != varinitcommands.end(); ++ i ) 00832 delete *i; 00833 varinitcommands.clear(); 00834 for ( std::vector<ActionInterface*>::iterator i = paraminitcommands.begin(); 00835 i != paraminitcommands.end(); ++ i ) 00836 delete *i; 00837 paraminitcommands.clear(); 00838 for ( machinebuilders_t::iterator i = machinebuilders.begin(); 00839 i != machinebuilders.end(); ++i ) 00840 delete i->second; 00841 machinebuilders.clear(); 00842 00843 } 00844 00845 void StateGraphParser::seenstatemachinename( iter_t begin, iter_t end ) { 00846 // the 'type' of the SC : 00847 curmachinename = std::string ( begin, end ); 00848 00849 // check if the type exists already : 00850 if ( machinebuilders.count( curmachinename ) != 0 ) 00851 ORO_THROW( parse_exception_semantic_error("StateMachine type " + curmachinename + " redefined.")); 00852 00853 curtemplate.reset(new ParsedStateMachine()); 00854 // Connect the new SC to the relevant machines. 00855 // 'sc' acts as a stack for storing variables. 00856 curobject.reset( new StateMachineService(curtemplate, context ) ); 00857 curobject->setName( curmachinename ); 00858 curtemplate->setService( curobject ); // store. 00859 00860 // we pass the plain file positer such that parse errors are 00861 // refering to correct file line numbers. 00862 progParser = new ProgramGraphParser(mpositer, context, caller, *commonparser); 00863 00864 // set the 'type' name : 00865 curtemplate->setName( curmachinename, false ); 00866 } 00867 00868 void StateGraphParser::storeOffset() { 00869 // stores the begining of a (possible) new statemachine definition. 00870 // start line number : 00871 ln_offset = mpositer.get_position().line - 1; 00872 // start of text : 00873 saveStartPos = mpositer; 00874 } 00875 00876 void StateGraphParser::saveText( iter_t begin, iter_t end ) { 00877 assert( curmachinename.length() != 0 ); 00878 //cerr << std::string(begin, end)<<endl; 00879 if ( machinebuilders.count( curmachinename ) == 0 ) 00880 return; // yes this might be possible 00881 // due to the shared-text implementation, we can set the text afterwards. 00882 machinebuilders[curmachinename]->item()->setText( std::string( saveStartPos, end) ); 00883 this->storeOffset(); 00884 } 00885 00886 void StateGraphParser::inpreconditions() { 00887 // we postpone the current state 00888 assert( curnonprecstate == 0 ); 00889 curnonprecstate = curstate->postponeState(); 00890 // add the postponed state in PSM : 00891 curtemplate->addState( curnonprecstate ); 00892 } 00893 00894 void StateGraphParser::seenpreconditions() { 00895 curtemplate->transitionSet( curstate, curnonprecstate, new ConditionTrue, rank--, mpositer.get_position().line - ln_offset ); 00896 curstate->setDefined( true ); 00897 curstate = curnonprecstate; 00898 curnonprecstate = 0; 00899 } 00900 00901 void StateGraphParser::startrootmachineinstantiation() { 00902 isroot = true; 00903 } 00904 00905 void StateGraphParser::seenrootmachineinstantiation() { 00906 // first reset the flag. 00907 isroot = false; 00908 if( rootmachines.find( curinstmachinename ) != rootmachines.end() ) 00909 ORO_THROW( parse_exception_semantic_error( "Root machine \"" + curinstmachinename + "\" already defined." )); 00910 rootmachines[curinstmachinename] = curinstantiatedmachine; 00911 00912 // recursively set the name of this SC and all subs : 00913 // furthermore, it adds the TC of each child as peer TC to the parent. 00914 curinstantiatedmachine->setName( curinstmachinename, true ); 00915 00916 // check if the type exists already : 00917 if ( context->provides()->hasService( curinstmachinename ) ) 00918 ORO_THROW( parse_exception_semantic_error("TaskContext '"+context->getName()+"' has already a Service named '" + curinstmachinename + "' .")); 00919 00920 // Transfer ownership to the owning task. 00921 context->provides()->addService( curinstantiatedmachine->getService() ); 00922 00923 curinstantiatedmachine.reset(); 00924 curinstmachinename.clear(); 00925 } 00926 00927 void StateGraphParser::seensubMachineinstantiation() { 00928 if ( find_if( curtemplate->getChildren().begin(), 00929 curtemplate->getChildren().end(), 00930 boost::bind( equal_to<string>(), boost::bind(&StateMachine::getName,_1), curinstmachinename )) != curtemplate->getChildren().end() ) 00931 ORO_THROW( parse_exception_semantic_error( "SubMachine \"" + curinstmachinename + "\" already defined." )); 00932 00933 // Since we parse in the task context, we must _temporarily_ 00934 // make each subMachine a peer of the task so that we can access 00935 // its methods. 00936 00937 // Warning: use context->unmountService() since curinstantiatedmachine must owns it. 00938 if ( !context->provides()->addService( curinstantiatedmachine->getService() ) ) 00939 ORO_THROW( parse_exception_semantic_error( 00940 "Name clash: name of instantiated machine \"" + curinstmachinename + 00941 "\" already used as object name in task '"+context->getName()+"'." )); 00942 00943 // SM child relation 00944 curtemplate->addChild( curinstantiatedmachine ); 00945 // sub-Service relation. 00946 curtemplate->getService()->addService( curinstantiatedmachine->getService() ); 00947 00948 curinstantiatedmachine->setName(curinstmachinename, false ); // not recursive ! 00949 00950 curinstantiatedmachine.reset(); 00951 curinstmachinename.clear(); 00952 } 00953 00954 void StateGraphParser::seenmachinetypename( iter_t begin, iter_t end ) { 00955 assert( curmachinebuilder == 0 ); 00956 std::string name( begin, end ); 00957 machinebuilders_t::iterator i = machinebuilders.find( name ); 00958 if ( i == machinebuilders.end() ) 00959 ORO_THROW( parse_exception_semantic_error( "StateMachine \"" + name + "\" not defined." )); 00960 curmachinebuilder = i->second; 00961 } 00962 00963 void StateGraphParser::seeninstmachinename( iter_t begin, iter_t end ) { 00964 assert( curmachinebuilder != 0 ); 00965 assert( curinstmachinename.empty() ); 00966 curinstmachinename = std::string( begin, end ); 00967 } 00968 00969 void StateGraphParser::seenmachineinstargumentname( iter_t begin, iter_t end ) { 00970 assert( curmachineinstargumentname.empty() ); 00971 std::string name( begin, end ); 00972 curmachineinstargumentname = name; 00973 } 00974 00975 void StateGraphParser::seenmachineinstargumentvalue() { 00976 DataSourceBase::shared_ptr value = expressionparser->getResult(); 00977 // let's not forget this... 00978 expressionparser->dropResult(); 00979 if ( curinstmachineparams.find( curmachineinstargumentname ) != curinstmachineparams.end() ) 00980 ORO_THROW( parse_exception_semantic_error( 00981 "In initialisation of StateMachine \"" + curinstmachinename + 00982 "\": Parameter \"" + curmachineinstargumentname +"\" initialised twice..." )); 00983 curinstmachineparams[curmachineinstargumentname] = value; 00984 curmachineinstargumentname.clear(); 00985 } 00986 00987 void StateGraphParser::seenmachineinstantiation() 00988 { 00989 // TODO : move this code to the ParsedStateMachine builder. 00990 00991 // Create a full depth copy (including subMachines) 00992 // if RootMachine, make special copy which fixes attributes such 00993 // that on subsequent copy() they keep pointing to same var. 00994 // use shared_ptr to release on throw's below. 00995 ParsedStateMachinePtr nsc( curmachinebuilder->build( isroot ) ); 00996 00997 // we stored the attributes which are params of nsc 00998 // in the build operation : 00999 machineparams_t params = nsc->getParameters(); 01000 01001 // first run over the given parameters to see if they all exist in 01002 // the context we're instantiating... 01003 for ( machineparamvalues_t::iterator i = curinstmachineparams.begin(); i != curinstmachineparams.end(); ++i ) 01004 { 01005 machineparams_t::iterator j = params.find( i->first ); 01006 if ( j == params.end() ) 01007 ORO_THROW( parse_exception_semantic_error( "No parameter \"" + i->first + "\" in this StateMachine." ) ); 01008 } 01009 01010 for ( machineparams_t::iterator i = params.begin(); i != params.end(); ++i ) 01011 { 01012 machineparamvalues_t::iterator j = curinstmachineparams.find( i->first ); 01013 if ( j == curinstmachineparams.end() ) 01014 ORO_THROW( parse_exception_semantic_error( 01015 "No value given for argument \"" + i->first + "\" in instantiation of this StateMachine." )); 01016 #ifndef ORO_EMBEDDED 01017 try { 01018 paraminitcommands.push_back( i->second->getDataSource()->updateAction( j->second.get() ) ); 01019 } 01020 catch( const bad_assignment& ) 01021 { 01022 throw parse_exception_semantic_error("Attempt to initialize parameter '"+i->first+"' with a value which is of a different type." ); 01023 } 01024 #else 01025 ActionInterface* ret = i->second->getDataSource()->updateAction( j->second.get()); 01026 if (ret) 01027 paraminitcommands.push_back( ret ); 01028 else 01029 return; 01030 #endif 01031 } 01032 01033 curinstantiatedmachine = nsc; 01034 01035 // prepend the commands for initialising the subMachine 01036 // parameters 01037 if ( paraminitcommands.size() > 0 ) 01038 { 01039 CommandComposite* comcom = new CommandComposite; 01040 for ( std::vector<ActionInterface*>::iterator i = paraminitcommands.begin(); 01041 i != paraminitcommands.end(); ++i ) 01042 comcom->add( *i ); 01043 // init the vars as last (if any), so that they can be inited by an expression containing the params : 01044 if ( curinstantiatedmachine->getInitCommand() ) 01045 comcom->add( curinstantiatedmachine->getInitCommand() ); 01046 curinstantiatedmachine->setInitCommand( comcom ); 01047 } 01048 paraminitcommands.clear(); 01049 01050 curmachinebuilder = 0; 01051 curinstmachineparams.clear(); 01052 01053 // set the TaskContext name to the instance name : 01054 curinstantiatedmachine->getService()->setName(curinstmachinename ); 01055 } 01056 01057 void StateGraphParser::seenmachinevariable() { 01058 std::vector<ActionInterface*> acv = valuechangeparser->assignCommands(); 01059 for(std::vector<ActionInterface*>::iterator it = acv.begin(); it!=acv.end(); ++it) 01060 varinitcommands.push_back( *it ); 01061 // this only clears the last parsed variables, not the 'store' (see reset()) 01062 valuechangeparser->clear(); 01063 } 01064 01065 void StateGraphParser::seenmachineparam() { 01066 std::vector<std::string> pnames = valuechangeparser->definedNames(); 01067 std::vector<AttributeBase*> tbases = valuechangeparser->definedValues(); 01068 assert( pnames.size() == tbases.size() ); 01069 for (unsigned int i = 0; i < pnames.size(); ++i) 01070 curtemplate->addParameter( pnames[i] , tbases[i] ); 01071 // this only clears the last parsed variables, not the 'store' (see reset()) 01072 valuechangeparser->clear(); 01073 } 01074 01075 01076 }