Orocos Real-Time Toolkit
2.5.0
|
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon May 10 19:10:37 CEST 2004 ProgramGraphParser.cxx 00003 00004 ProgramGraphParser.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 "ProgramGraphParser.hpp" 00031 #include "ArgumentsParser.hpp" 00032 00033 #include "CommandNOP.hpp" 00034 #include "CommandDataSource.hpp" 00035 #include "ConditionTrue.hpp" 00036 #include "../Logger.hpp" 00037 #include "DataSourceCondition.hpp" 00038 00039 #include "ConditionComposite.hpp" 00040 #include "ConditionFalse.hpp" 00041 #include "ConditionOnce.hpp" 00042 #include "CommandComposite.hpp" 00043 #include "CommandBinary.hpp" 00044 00045 #include "TryCommand.hpp" 00046 #include "FunctionFactory.hpp" 00047 #include "../TaskContext.hpp" 00048 #include "../internal/GlobalService.hpp" 00049 00050 #include <iostream> 00051 #include <boost/bind.hpp> 00052 #include <boost/lambda/lambda.hpp> 00053 00054 #ifdef WIN32 00055 #ifdef NDEBUG 00056 #pragma optimize( "", off) 00057 #endif 00058 #endif 00059 00060 namespace RTT 00061 { 00062 using namespace boost; 00063 using namespace detail; 00064 00065 00066 00067 namespace { 00068 boost::spirit::classic::assertion<std::string> expect_opencurly("Open curly brace '{' expected."); 00069 boost::spirit::classic::assertion<std::string> expect_closecurly("Closing curly brace '}' expected in statement block (or could not find out what this line means)."); 00070 boost::spirit::classic::assertion<std::string> expect_closefunction("Closing curly brace '}' expected at end of program or function (or could not find out what this line means)."); 00071 boost::spirit::classic::assertion<std::string> expect_open("Open brace '(' expected."); 00072 boost::spirit::classic::assertion<std::string> expect_close("Closing brace ')' expected."); 00073 boost::spirit::classic::assertion<std::string> expect_comma("Expected a comma separator."); 00074 boost::spirit::classic::assertion<std::string> expect_ident("Expected a valid identifier."); 00075 boost::spirit::classic::assertion<std::string> expect_semicolon("Semicolon ';' expected after statement."); 00076 boost::spirit::classic::assertion<std::string> expect_condition("Expected a boolean expression ( a condition )."); 00077 boost::spirit::classic::assertion<std::string> expect_expression("Expected an expression."); 00078 boost::spirit::classic::assertion<std::string> expect_command("Expected a command after 'do'."); 00079 boost::spirit::classic::assertion<std::string> expect_nl("Expected a newline after statement."); 00080 boost::spirit::classic::assertion<std::string> expect_eof("Invalid input in file."); 00081 boost::spirit::classic::assertion<std::string> expect_term("No valid termination claues found in do ... until { } block."); 00082 } 00083 00084 00085 ProgramGraphParser::ProgramGraphParser( iter_t& positer, TaskContext* t, ExecutionEngine* caller, CommonParser& cp) 00086 : rootc( t ),context(), fcontext(0), mpositer( positer ), 00087 mcallfunc(), 00088 implcond(0), mcondition(0), try_cond(0), 00089 commonparser(cp), 00090 conditionparser( rootc, caller, cp ), 00091 valuechangeparser( rootc, cp, t->provides(), caller ), 00092 expressionparser( rootc, caller, cp ), 00093 argsparser(0), 00094 peerparser(rootc, commonparser), 00095 program_builder( new FunctionGraphBuilder() ), 00096 for_init_command(0), 00097 exportf(false),globalf(false), 00098 ln_offset(0) 00099 { 00100 // putting the code in setup() works around a GCC 4.1 bug. 00101 this->setup(); 00102 this->setup2(); 00103 } 00104 00105 ProgramGraphParser::~ProgramGraphParser() { 00106 // necessary in case we were used outside of our parse() methods. 00107 // we also try to remove the service, because the user will call programParserResult() 00108 // to do cleanup himself, in which case this becomes a no-op. 00109 cleanup(true); 00110 } 00111 00112 void ProgramGraphParser::setup() { 00113 BOOST_SPIRIT_DEBUG_RULE( newline ); 00114 BOOST_SPIRIT_DEBUG_RULE( openbrace ); 00115 BOOST_SPIRIT_DEBUG_RULE( closebrace ); 00116 BOOST_SPIRIT_DEBUG_RULE( opencurly ); 00117 BOOST_SPIRIT_DEBUG_RULE( closecurly ); 00118 BOOST_SPIRIT_DEBUG_RULE( semicolon ); 00119 BOOST_SPIRIT_DEBUG_RULE( condition ); 00120 BOOST_SPIRIT_DEBUG_RULE( terminationclause ); 00121 BOOST_SPIRIT_DEBUG_RULE( jumpdestination ); 00122 BOOST_SPIRIT_DEBUG_RULE( terminationpart ); 00123 BOOST_SPIRIT_DEBUG_RULE( dostatement ); 00124 BOOST_SPIRIT_DEBUG_RULE( trystatement ); 00125 BOOST_SPIRIT_DEBUG_RULE( catchpart ); 00126 BOOST_SPIRIT_DEBUG_RULE( statement ); 00127 BOOST_SPIRIT_DEBUG_RULE( line ); 00128 BOOST_SPIRIT_DEBUG_RULE( content ); 00129 BOOST_SPIRIT_DEBUG_RULE( program ); 00130 BOOST_SPIRIT_DEBUG_RULE( production ); 00131 BOOST_SPIRIT_DEBUG_RULE( valuechange ); 00132 BOOST_SPIRIT_DEBUG_RULE( function ); 00133 BOOST_SPIRIT_DEBUG_RULE( functions ); 00134 BOOST_SPIRIT_DEBUG_RULE( arguments ); 00135 BOOST_SPIRIT_DEBUG_RULE( returnstatement ); 00136 BOOST_SPIRIT_DEBUG_RULE( funcstatement ); 00137 BOOST_SPIRIT_DEBUG_RULE( continuepart ); 00138 BOOST_SPIRIT_DEBUG_RULE( callpart ); 00139 BOOST_SPIRIT_DEBUG_RULE( returnpart ); 00140 BOOST_SPIRIT_DEBUG_RULE( ifstatement ); 00141 BOOST_SPIRIT_DEBUG_RULE( whilestatement ); 00142 BOOST_SPIRIT_DEBUG_RULE( forstatement ); 00143 BOOST_SPIRIT_DEBUG_RULE( breakstatement ); 00144 BOOST_SPIRIT_DEBUG_RULE( ifblock ); 00145 BOOST_SPIRIT_DEBUG_RULE( funcargs ); 00146 00147 //newline = ch_p( '\n' ); 00148 openbrace = expect_open( ch_p('(') ); 00149 closebrace = expect_close( ch_p(')') ); 00150 opencurly = expect_opencurly( ch_p('{') ); 00151 closecurly = expect_closecurly( ch_p('}') ); 00152 semicolon = expect_semicolon( ch_p(';') ); 00153 condition = expect_condition( conditionparser.parser()[ boost::bind(&ProgramGraphParser::seencondition, this) ] ); 00154 00155 // program is the production rule of this grammar. The 00156 // production rule is the rule that the entire input should be 00157 // matched by... This line basically means that we're finished 00158 // ;) 00159 // Zero or n functions can precede the program. 00160 production = *( program | function )[boost::bind(&ProgramGraphParser::programtext,this, _1, _2)] >> expect_eof(end_p) ; 00161 00162 // a function is very similar to a program, but it also has a name 00163 function = ( 00164 // optional visibility qualifiers: 00165 !( keyword_p( "export" )[boost::bind(&ProgramGraphParser::exportdef, this)] | keyword_p( "global" )[boost::bind(&ProgramGraphParser::globaldef, this)] | keyword_p("local") ) 00166 >> (keyword_p( "function" ) | commonparser.notassertingidentifier[boost::bind( &ProgramGraphParser::seenreturntype, this, _1, _2)]) 00167 >> expect_ident( commonparser.identifier[ boost::bind( &ProgramGraphParser::functiondef, this, _1, _2 ) ] ) 00168 >> !funcargs 00169 >> opencurly 00170 >> content 00171 >> expect_closefunction( ch_p('}') )[ boost::bind( &ProgramGraphParser::seenfunctionend, this ) ] 00172 ); 00173 00174 // the function's definition args : 00175 funcargs = ch_p('(') >> ( !str_p("void") >> ch_p(')') | (( 00176 valuechangeparser.bareDefinitionParser()[boost::bind(&ProgramGraphParser::seenfunctionarg, this)] 00177 >> *(ch_p(',')>> valuechangeparser.bareDefinitionParser()[boost::bind(&ProgramGraphParser::seenfunctionarg, this)]) ) 00178 >> closebrace )); 00179 00180 // a program looks like "program { content }". 00181 program = 00182 keyword_p( "program" ) 00183 >> expect_ident( commonparser.identifier[ boost::bind( &ProgramGraphParser::programdef, this, _1, _2 ) ] ) 00184 >> opencurly 00185 >> content 00186 >> expect_closefunction( ch_p('}') )[ boost::bind( &ProgramGraphParser::seenprogramend, this ) ]; 00187 00188 // the content of a program can be any number of lines 00189 content = *line; 00190 00191 // a line can be empty or contain a statement. Empty is 00192 // necessary, because comment's are skipped, but newline's 00193 // aren't. So a line like "/* very interesting comment 00194 // */\n" will reach us as simply "\n".. 00195 //line = !( statement ) >> eol_p; 00196 line = statement[boost::bind(&ProgramGraphParser::noskip_eol, this )] >> commonparser.eos[boost::bind(&ProgramGraphParser::skip_eol, this )]; 00197 00198 statement = valuechange | trystatement | funcstatement | returnstatement | ifstatement | whilestatement | forstatement | breakstatement | dostatement; 00199 00200 valuechange = valuechangeparser.parser()[ boost::bind( &ProgramGraphParser::seenvaluechange, this ) ]; 00201 00202 // take into account deprecated 'do' and 'set' 00203 dostatement = !keyword_p("do") >> !keyword_p("set") >> !keyword_p("call") >> 00204 ( 00205 ( keyword_p("yield") | keyword_p("nothing"))[boost::bind(&ProgramGraphParser::seenyield,this)] 00206 | expressionparser.parser()[ boost::bind(&ProgramGraphParser::seenstatement,this) ] 00207 ); 00208 00209 // a try statement: "try xxx catch { stuff to do once on any error} " 00210 trystatement = 00211 keyword_p("try") 00212 >> expect_command ( expressionparser.parser()[ boost::bind( &ProgramGraphParser::seentrystatement, this ) ] ) 00213 >> !catchpart; 00214 00215 } 00216 00217 void ProgramGraphParser::initBodyParser(const std::string& name, Service::shared_ptr stck, int offset) { 00218 ln_offset = offset; 00219 assert(program_builder != 0 ); 00220 program_builder->startFunction(name); 00221 this->setStack( stck ); 00222 this->clearParseState(); 00223 } 00224 00225 rule_t& ProgramGraphParser::programParser() { 00226 return program; 00227 } 00228 00229 rule_t& ProgramGraphParser::functionParser() { 00230 return function; 00231 } 00232 00233 rule_t& ProgramGraphParser::bodyParser() { 00234 // content is the bodyparser of a program or function 00235 return content; 00236 } 00237 00238 rule_t& ProgramGraphParser::statementParser() { 00239 // line is the statement parser of a program or function 00240 return line; 00241 } 00242 00243 ProgramInterfacePtr ProgramGraphParser::programParserResult() { 00244 ProgramInterfacePtr result; 00245 if (program_list.empty()) 00246 return result; 00247 program_text = "Bug: Program Text to be set by Parser."; 00248 // set the program text in each program : 00249 program_list.front()->setText( program_text ); 00250 result=program_list.front(); 00251 this->cleanup(false); 00252 program_list.clear(); 00253 return result; 00254 } 00255 00256 ProgramInterfacePtr ProgramGraphParser::bodyParserResult() { 00257 00258 // store the variables in the program's taskcontext object. 00259 valuechangeparser.store( context ); 00260 valuechangeparser.reset(); 00261 00262 // Fake a 'return' statement at the last line. 00263 program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00264 program_builder->proceedToNext( mpositer.get_position().line - ln_offset); 00265 return program_builder->endFunction( mpositer.get_position().line - ln_offset ); 00266 } 00267 00268 // ProgramInterfacePtr ProgramGraphParser::statementParserResult() { 00269 // 00270 // // Fake a 'return' statement at the last line. 00271 // program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00272 // program_builder->proceedToNext( mpositer.get_position().line - ln_offset); 00273 // return program_builder->getFunction(); 00274 // } 00275 00276 void ProgramGraphParser::setStack(Service::shared_ptr st) { 00277 context = st; 00278 valuechangeparser.load(context); 00279 } 00280 00281 void ProgramGraphParser::clearParseState() { 00282 exportf = false; 00283 rettype.clear(); 00284 } 00285 00286 void ProgramGraphParser::startofprogram() 00287 { 00288 } 00289 00290 void ProgramGraphParser::programdef( iter_t begin, iter_t end ) 00291 { 00292 // Now that we got the name, set everything up: 00293 00294 std::string def(begin, end); 00295 00296 if ( rootc->provides()->hasService( def ) ) 00297 throw parse_exception_semantic_error("Service with name '" + def + "' already present in task '"+rootc->getName()+"'."); 00298 00299 FunctionGraphPtr pi(program_builder->startFunction( def )); 00300 // ptsk becomes the owner of pi. 00301 ProgramServicePtr ptsk(new ProgramService( pi, rootc )); 00302 pi->setProgramService(ptsk); 00303 pi->setUnloadOnStop( false ); // since we assign a service, set this to false. 00304 context = ptsk; 00305 rootc->provides()->addService( ptsk ); 00306 } 00307 00308 void ProgramGraphParser::programtext( iter_t begin, iter_t end ) 00309 { 00310 // we set it in the parse() function. It is set to the whole script such that line numbers are correct. 00311 //program_text = std::string(begin, end); 00312 } 00313 00314 void ProgramGraphParser::exportdef() 00315 { 00316 exportf = true; 00317 } 00318 00319 void ProgramGraphParser::globaldef() 00320 { 00321 globalf = true; 00322 } 00323 00324 void ProgramGraphParser::seenreturntype( iter_t begin, iter_t end ) 00325 { 00326 rettype = std::string(begin, end); 00327 } 00328 void ProgramGraphParser::functiondef( iter_t begin, iter_t end ) 00329 { 00330 // store the function in our map for later 00331 // referencing. 00332 std::string funcdef(begin, end); 00333 // store the function in the TaskContext current.__functions 00334 // TaskContext* __f = rootc->getPeer("__functions"); 00335 // if ( __f == 0 ) { 00336 // // install the __functions if not yet present. 00337 // __f = new TaskContext("__functions", rootc->engine() ); 00338 // rootc->connectPeers( __f ); 00339 // } 00340 00341 // if ( __f->hasPeer( funcdef ) ) 00342 // only redefining a function twice in the same file is an error. If the function 00343 // was already added to the scripting or component interface before, we replace it 00344 // and warn about it in seenfunctionend(): 00345 if ( mfuncs.count( funcdef ) ) 00346 throw parse_exception_semantic_error("function " + funcdef + " redefined."); 00347 00348 AttributeBase* retarg = 0; 00349 if ( !rettype.empty() && rettype != "void") { 00350 TypeInfo* type = TypeInfoRepository::Instance()->type( rettype ); 00351 if ( type == 0 ) 00352 throw_( iter_t(), "Return type '" + rettype + "' for function '"+ funcdef +"' is an unknown type." ); 00353 retarg = type->buildAttribute("result"); 00354 } 00355 00356 mfuncs[funcdef] = program_builder->startFunction( funcdef ); 00357 program_builder->getFunction()->setResult( retarg ); 00358 00359 rettype.clear(); 00360 00361 // Connect the new function to the relevant contexts. 00362 // 'fun' acts as a stack for storing variables. 00363 fcontext = new TaskContext(funcdef, rootc->engine() ); 00364 context = fcontext->provides(); 00365 } 00366 00367 void ProgramGraphParser::seenfunctionarg() 00368 { 00369 // the ValueChangeParser stores each variable in the 00370 // current stack's repository, but we need to inform the 00371 // FunctionGraph itself about its arguments. 00372 program_builder->getFunction()->addArgument( valuechangeparser.lastDefinedValue()->clone() ); 00373 valuechangeparser.clear(); 00374 } 00375 00376 void ProgramGraphParser::seenfunctionend() 00377 { 00378 // Fake a 'return' statement at the last line. 00379 program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00380 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); 00381 boost::shared_ptr<ProgramInterface> mfunc = program_builder->endFunction( mpositer.get_position().line - ln_offset ); 00382 00383 // export the function in the context's interface. 00384 if (exportf) { 00385 std::map<const DataSourceBase*, DataSourceBase*> dummy; 00386 FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command. 00387 if (rootc->provides()->hasMember( mfunc->getName() ) ) 00388 log(Warning) << "Redefining function '"<< rootc->getName() << "." << mfunc->getName() << "': only new programs will use this new function." <<endlog(); 00389 rootc->provides()->add(mfunc->getName(), cfi ); 00390 Logger::log() << Logger::Info << "Exported Function '" << mfunc->getName() << "' added to task '"<< rootc->getName() << "'" <<Logger::endl; 00391 } 00392 // attach the function to the global service interface. 00393 else if (globalf){ 00394 std::map<const DataSourceBase*, DataSourceBase*> dummy; 00395 FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command. 00396 if (GlobalService::Instance()->provides()->hasMember( mfunc->getName() ) ) 00397 log(Warning) << "Redefining function '"<< GlobalService::Instance()->getName() << "."<< mfunc->getName() << "': only new programs will use this new function." <<endlog(); 00398 GlobalService::Instance()->provides()->add(mfunc->getName(), cfi ); 00399 Logger::log() << Logger::Debug << "Seen Function '" << mfunc->getName() << "' for Global Service." <<Logger::endl; 00400 } else { 00401 std::map<const DataSourceBase*, DataSourceBase*> dummy; 00402 FunctionFactory* cfi = new FunctionFactory(ProgramInterfacePtr(mfunc->copy(dummy)), rootc->engine() ); // execute in the processor which has the command. 00403 if (rootc->provides("scripting")->hasMember( mfunc->getName() ) ) 00404 log(Warning) << "Redefining function '"<< rootc->getName() << ".scripting."<< mfunc->getName() << "': only new programs will use this new function." <<endlog(); 00405 rootc->provides("scripting")->add(mfunc->getName(), cfi ); 00406 Logger::log() << Logger::Debug << "Seen Function '" << mfunc->getName() << "' for scripting service of '"<< rootc->getName() << "'" <<Logger::endl; 00407 } 00408 00409 00410 delete fcontext; 00411 fcontext = 0; 00412 context.reset(); 00413 00414 // reset 00415 exportf = false; globalf = false; 00416 00417 valuechangeparser.reset(); 00418 } 00419 00420 void ProgramGraphParser::seencondition() 00421 { 00422 mcondition = conditionparser.getParseResult(); 00423 assert( mcondition ); 00424 00425 // leaves the condition in the parser, if we want to use 00426 // getParseResultAsCommand(); 00427 // mcondition is only used with seen*label statements, 00428 // when the command and condition are associated, 00429 // not in the branching where the evaluation of the 00430 // condition is the command. 00431 } 00432 00433 void ProgramGraphParser::seenreturnstatement() 00434 { 00435 // return statement can happen in program and in a function 00436 program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00437 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); 00438 } 00439 00440 void ProgramGraphParser::seenreturnvalue() 00441 { 00442 AttributeBase* ar =program_builder->getFunction()->getResult(); 00443 if ( ar == 0) { 00444 throw parse_exception_syntactic_error("Returning a value in a function returning (void)."); 00445 } 00446 DataSourceBase::shared_ptr expr = expressionparser.getResult().get(); 00447 expressionparser.dropResult(); 00448 try { 00449 ActionInterface* assigncomm = ar->getDataSource()->updateAction( expr.get() ); 00450 // assign the return value to the return argument. 00451 program_builder->setCommand( assigncomm ); 00452 program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset ); 00453 } 00454 catch(...) { 00455 // catch exception from updateAction. 00456 throw parse_exception_syntactic_error("Could not convert '" + expr->getType() + "' to '"+ ar->getDataSource()->getType() +"' in return statement."); 00457 } 00458 } 00459 00460 void ProgramGraphParser::seenbreakstatement() 00461 { 00462 if ( program_builder->inLoop() ) { 00463 program_builder->breakLoop(); 00464 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); 00465 } else 00466 throw parse_exception_syntactic_error("Illegal use of 'break'. Can only be used within for and while loops."); 00467 } 00468 00469 void ProgramGraphParser::seenfuncidentifier( iter_t begin, iter_t end ) 00470 { 00471 // store the part after 'call' 00472 std::string fname(begin, end); 00473 if ( mfuncs.count(fname) == 0 ) 00474 throw parse_exception_semantic_error("calling function " + fname + " but it is not defined ( remove the 'call' keyword )."); 00475 if ( fname == program_builder->getFunction()->getName() ) 00476 throw parse_exception_semantic_error("calling function " + fname + " recursively is not allowed."); 00477 00478 mcallfunc = mfuncs[ fname ]; 00479 00480 // Parse the function's args in the programs context. 00481 argsparser = new ArgumentsParser( expressionparser, rootc, rootc->provides(), 00482 "this", fname ); 00483 arguments = argsparser->parser(); 00484 00485 } 00486 00487 void ProgramGraphParser::seencallfuncargs() 00488 { 00489 callfnargs = argsparser->result(); 00490 } 00491 00492 void ProgramGraphParser::seencallfuncstatement() 00493 { 00494 log(Warning) << " 'call' has been deprecated. Please remove this keyword." << endlog(); 00495 // This function is called if the 'call func' is outside 00496 // a termination clause. 00497 00498 // add it to the main program line of execution. 00499 assert( mcallfunc ); 00500 try 00501 { 00502 program_builder->setFunction( mcallfunc, callfnargs ); 00503 // only delete parser, when the args are used. 00504 delete argsparser; 00505 argsparser = 0; 00506 callfnargs.clear(); 00507 } 00508 catch( const wrong_number_of_args_exception& e ) 00509 { 00510 throw parse_exception_wrong_number_of_arguments 00511 ( rootc->getName(), mcallfunc->getName(), e.wanted, e.received ); 00512 } 00513 catch( const wrong_types_of_args_exception& e ) 00514 { 00515 throw parse_exception_wrong_type_of_argument 00516 ( rootc->getName(), mcallfunc->getName(), e.whicharg, e.expected_, e.received_ ); 00517 } 00518 catch( ... ) 00519 { 00520 assert( false ); 00521 } 00522 00523 // The exit node of the function is already connected 00524 // to program->nextNode(). 00525 program_builder->proceedToNext(mpositer.get_position().line - ln_offset); 00526 } 00527 00528 void ProgramGraphParser::skip_eol() { 00529 commonparser.skipeol = true; 00530 } 00531 00532 void ProgramGraphParser::noskip_eol() { 00533 commonparser.skipeol = false; 00534 } 00535 00536 void ProgramGraphParser::startcatchpart() { 00537 // we saved the try_cond in the previous try statement, 00538 // now process like it said if ( try_cond ) then {...} 00539 assert( try_cond ); 00540 program_builder->startIfStatement( try_cond, mpositer.get_position().line - ln_offset ); 00541 try_cond = 0; 00542 } 00543 00544 void ProgramGraphParser::seencatchpart() { 00545 this->endifblock(); 00546 this->endifstatement(); // there is no 'else' part, so close the statement 00547 } 00548 00549 void ProgramGraphParser::seenifstatement() { 00550 assert(mcondition); 00551 // transform the evaluation in a command, and pass the result 00552 // as a condition 00553 std::pair<ActionInterface*, ConditionInterface*> comcon; 00554 comcon = conditionparser.getParseResultAsCommand(); 00555 program_builder->setCommand( comcon.first ); 00556 program_builder->startIfStatement( comcon.second, mpositer.get_position().line - ln_offset ); 00557 00558 // we did not need this. 00559 delete mcondition; 00560 mcondition = 0; 00561 } 00562 00563 void ProgramGraphParser::endifblock() { 00564 program_builder->endIfBlock(mpositer.get_position().line - ln_offset); 00565 } 00566 00567 00568 void ProgramGraphParser::endifstatement() { 00569 program_builder->endElseBlock(mpositer.get_position().line - ln_offset); 00570 } 00571 00572 void ProgramGraphParser::seenwhilestatement() { 00573 // analogous to seenifstatement 00574 // the evaluation is a command. 00575 assert(mcondition); 00576 std::pair<ActionInterface*, ConditionInterface*> comcon; 00577 comcon = conditionparser.getParseResultAsCommand(); 00578 program_builder->setCommand( comcon.first ); 00579 program_builder->startWhileStatement( comcon.second, mpositer.get_position().line - ln_offset ); 00580 00581 delete mcondition; 00582 mcondition = 0; 00583 } 00584 00585 void ProgramGraphParser::endwhilestatement() { 00586 program_builder->endWhileBlock(mpositer.get_position().line - ln_offset); 00587 } 00588 00589 00590 void ProgramGraphParser::seenforinit() 00591 { 00592 // the for loop is different from the while and if branch 00593 // structures in that it places an init command before the loop. 00594 ActionInterface* ac = 0; 00595 std::vector<ActionInterface*> acv = valuechangeparser.assignCommands(); 00596 // and not forget to reset().. 00597 valuechangeparser.clear(); 00598 if ( acv.size() == 1) { 00599 ac = acv.front(); 00600 } 00601 else if (acv.size() > 1) { 00602 ac = new CommandComposite( acv ); 00603 } 00604 for_init_command = ac; 00605 } 00606 00607 void ProgramGraphParser::seenforinit_expr() 00608 { 00609 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00610 expressionparser.dropResult(); 00611 for_init_command = new CommandDataSource( expr ); 00612 } 00613 00614 void ProgramGraphParser::seenforincr() 00615 { 00616 DataSourceBase::shared_ptr expr = expressionparser.getResult(); 00617 expressionparser.dropResult(); 00618 for_incr_command.push( new CommandDataSource( expr ) ); 00619 } 00620 00621 void ProgramGraphParser::seenemptyforincr() 00622 { 00623 for_incr_command.push( 0 ); 00624 } 00625 00626 void ProgramGraphParser::seenforstatement() { 00627 assert( mcondition ); 00628 00629 // first insert the initialisation command. 00630 if ( for_init_command ) 00631 { 00632 program_builder->setCommand( for_init_command ); 00633 program_builder->proceedToNext( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00634 } 00635 for_init_command = 0; 00636 00637 // A for is nothing more than a while loop... 00638 std::pair<ActionInterface*, ConditionInterface*> comcon; 00639 comcon = conditionparser.getParseResultAsCommand(); 00640 program_builder->setCommand( comcon.first ); 00641 program_builder->startWhileStatement( comcon.second, mpositer.get_position().line - ln_offset ); 00642 delete mcondition; 00643 mcondition = 0; 00644 } 00645 00646 void ProgramGraphParser::endforstatement() { 00647 // the last statement is a _conditional_ increment of the 'counter' 00648 ActionInterface* incr = for_incr_command.top(); 00649 for_incr_command.pop(); 00650 // is null or an action to increment 00651 if ( incr ) 00652 { 00653 program_builder->setCommand( incr ); 00654 // Since a valuechange does not add edges, we use this variant 00655 // to create one. 00656 program_builder->proceedToNext( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00657 } 00658 program_builder->endWhileBlock(mpositer.get_position().line - ln_offset); 00659 } 00660 00661 void ProgramGraphParser::seenprogramend() 00662 { 00663 // Fake a 'return' statement at the last line. 00664 program_builder->returnFunction( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00665 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); 00666 program_list.push_back(program_builder->endFunction( mpositer.get_position().line - ln_offset ) ); 00667 00668 // store the variables in the program's taskcontext object. 00669 valuechangeparser.store( context ); 00670 valuechangeparser.reset(); 00671 } 00672 00673 std::vector< ProgramInterfacePtr > ProgramGraphParser::parse( iter_t& begin, iter_t end ) 00674 { 00675 // end is not used ! 00676 iter_t begin_copy = begin; 00677 //skip_parser_t skip_parser = SKIP_PARSER; 00678 //iter_pol_t iter_policy( skip_parser ); 00679 iter_pol_t iter_policy( ( comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser.skipper ) ); 00680 scanner_pol_t policies( iter_policy ); 00681 scanner_t scanner( begin, end, policies ); 00682 program_list.clear(); 00683 00684 // todo :Add a universal collect/collectIfDone/ret(sendh, args) operationfactoryparts. 00685 //rootc->add("collect",&ProgramGraphParser::collectHandler, this) 00686 00687 try { 00688 if ( ! production.parse( scanner ) ) 00689 { 00690 // This gets shown if we didn't even get the chance to throw an exception : 00691 cleanup(true); 00692 throw file_parse_exception(new parse_exception_syntactic_error( " no valid input found." ), 00693 mpositer.get_position().file, mpositer.get_position().line, 00694 mpositer.get_position().column ); 00695 } 00696 program_text = std::string( begin_copy, begin ); // begin is by reference. 00697 // set the program text in each program : 00698 for (std::vector<FunctionGraphPtr>::iterator it= program_list.begin();it!=program_list.end();++it) 00699 (*it)->setText( program_text ); 00700 this->cleanup(false); 00701 std::vector<ProgramInterfacePtr> result; 00702 for (std::vector<FunctionGraphPtr>::iterator it= program_list.begin();it!=program_list.end();++it) 00703 result.push_back( *it ); 00704 program_list.clear(); 00705 return result; 00706 } 00707 catch( const parser_error<std::string, iter_t>& e ) 00708 { 00709 cleanup(true); 00710 program_list.clear(); 00711 throw file_parse_exception( 00712 new parse_exception_syntactic_error( e.descriptor ), 00713 mpositer.get_position().file, mpositer.get_position().line, 00714 mpositer.get_position().column ); 00715 00716 } 00717 // Catch our Orocos exceptions 00718 catch( const parse_exception& e ) 00719 { 00720 cleanup(true); 00721 program_list.clear(); 00722 throw file_parse_exception( 00723 e.copy(), mpositer.get_position().file, 00724 mpositer.get_position().line, mpositer.get_position().column ); 00725 } 00726 } 00727 00728 std::vector< ProgramInterfacePtr > ProgramGraphParser::parseFunction( iter_t& begin, iter_t end ) 00729 { 00730 // end is not used ! 00731 iter_t begin_copy = begin; 00732 //skip_parser_t skip_parser = SKIP_PARSER; 00733 //iter_pol_t iter_policy( skip_parser ); 00734 iter_pol_t iter_policy( ( comment_p( "#" ) | comment_p( "//" ) | comment_p( "/*", "*/" ) | (space_p - eol_p) | commonparser.skipper ) ); 00735 scanner_pol_t policies( iter_policy ); 00736 scanner_t scanner( begin, end, policies ); 00737 00738 std::vector< ProgramInterfacePtr > function_list; 00739 00740 try { 00741 if ( ! functions.parse( scanner ) ) 00742 { 00743 // This gets shown if we didn't even get the chance to throw an exception : 00744 cleanup(false); 00745 throw file_parse_exception(new parse_exception_syntactic_error( " no valid input found." ), 00746 mpositer.get_position().file, mpositer.get_position().line, 00747 mpositer.get_position().column ); 00748 } 00749 program_text = std::string( begin_copy, begin ); // begin is by reference. 00750 // set the program text in each function : 00751 for (funcmap::iterator it= mfuncs.begin();it!=mfuncs.end();++it) { 00752 it->second->setText( program_text ); // set text. 00753 function_list.push_back( it->second ); 00754 } 00755 00756 this->cleanup(false); 00757 return function_list; 00758 } 00759 // Catch Boost::Spirit exceptions 00760 catch( const parser_error<std::string, iter_t>& e ) 00761 { 00762 cleanup(false); 00763 throw file_parse_exception( 00764 new parse_exception_syntactic_error( e.descriptor ), 00765 mpositer.get_position().file, mpositer.get_position().line, 00766 mpositer.get_position().column ); 00767 00768 } 00769 // Catch our Orocos exceptions 00770 catch( const parse_exception& e ) 00771 { 00772 cleanup(false); 00773 throw file_parse_exception( 00774 e.copy(), mpositer.get_position().file, 00775 mpositer.get_position().line, mpositer.get_position().column ); 00776 } 00777 } 00778 00779 void ProgramGraphParser::cleanup(bool unload_service) 00780 { 00781 if (unload_service && rootc && context) 00782 rootc->provides()->removeService( context->getName() ); 00783 // after an exception, we can be in any state, so cleanup 00784 // all temp objects. 00785 delete argsparser; 00786 argsparser = 0; 00787 delete implcond; 00788 implcond = 0; 00789 delete mcondition; 00790 mcondition = 0; 00791 delete try_cond; 00792 try_cond = 0; 00793 delete for_init_command; 00794 for_init_command = 0; 00795 while (!for_incr_command.empty() ) { 00796 delete for_incr_command.top(); 00797 for_incr_command.pop(); 00798 } 00799 // cleanup all functions : 00800 delete fcontext; 00801 fcontext = 0; 00802 exportf = false; globalf = false; 00803 rettype.clear(); 00804 if ( rootc == 0) 00805 return; 00806 // TaskContext* __f = rootc->getPeer("__functions"); 00807 // if ( __f != 0 ) { 00808 // // first remove rootc from __f itself 00809 // rootc->disconnectPeers( __f->getName() ); 00810 // delete __f; 00811 // } 00812 while ( ! mfuncs.empty() ) { 00813 mfuncs.erase( mfuncs.begin() ); 00814 } 00815 context.reset(); 00816 00817 valuechangeparser.reset(); 00818 conditionparser.reset(); 00819 peerparser.reset(); 00820 } 00821 00822 void ProgramGraphParser::seentrystatement() 00823 { 00824 // a try expression/method call. 00825 ActionInterface* command; 00826 DataSourceBase::shared_ptr expr = expressionparser.getResult().get(); 00827 expressionparser.dropResult(); 00828 DataSource<bool>* bexpr = dynamic_cast<DataSource<bool>*>(expr.get()); 00829 if (bexpr == 0) { 00830 // if not returning a bool, the try is useless. 00831 command = new CommandDataSource( expr ); 00832 try_cond = new ConditionFalse(); // never execute catch part. 00833 program_builder->setCommand(command); 00834 } else { 00835 command = new CommandDataSourceBool( bexpr ); 00836 00837 // try-wrap the asyn or dispatch command, store the result in try_cond. 00838 TryCommand* trycommand = new TryCommand( command ); 00839 // returns true if failure : 00840 TryCommandResult* tryresult = new TryCommandResult( trycommand->result(), true ); 00841 program_builder->setCommand( trycommand ); 00842 try_cond = tryresult; // save try_cond for catch part (ie true if failure) 00843 } 00844 if ( program_builder->buildEdges() == 0 ) 00845 program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset ); 00846 else 00847 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); // we get the data from commandparser 00848 } 00849 00850 void ProgramGraphParser::seenstatement() 00851 { 00852 // an expression/method call (former do). 00853 DataSourceBase::shared_ptr expr = expressionparser.getResult().get(); 00854 expressionparser.dropResult(); 00855 DataSource<bool>* bexpr = dynamic_cast<DataSource<bool>*>(expr.get()); 00856 if (bexpr) 00857 program_builder->setCommand( new CommandDataSourceBool( bexpr ) ); 00858 else 00859 program_builder->setCommand( new CommandDataSource( expr ) ); 00860 if ( program_builder->buildEdges() == 0 ) 00861 program_builder->proceedToNext( new ConditionTrue(), mpositer.get_position().line - ln_offset ); 00862 else 00863 program_builder->proceedToNext( mpositer.get_position().line - ln_offset ); 00864 } 00865 00866 void ProgramGraphParser::seenyield() 00867 { 00868 // a yield branch 00869 program_builder->setCommand( new CommandNOP ); 00870 program_builder->proceedToNext( new ConditionOnce(false), mpositer.get_position().line - ln_offset ); 00871 } 00872 00873 void ProgramGraphParser::seenvaluechange() 00874 { 00875 // some value changes generate a command, we need to add it to 00876 // the program. 00877 ActionInterface* ac = 0; 00878 std::vector<ActionInterface*> acv = valuechangeparser.assignCommands(); 00879 // and not forget to reset().. 00880 valuechangeparser.clear(); 00881 if ( acv.size() == 1) { 00882 ac = acv.front(); 00883 } 00884 else if (acv.size() > 1) { 00885 ac = new CommandComposite(acv); 00886 } 00887 if (ac) { 00888 program_builder->setCommand( ac ); 00889 // Since a valuechange does not add edges, we use this variant 00890 // to create one. 00891 program_builder->proceedToNext( new ConditionTrue, mpositer.get_position().line - ln_offset ); 00892 } 00893 } 00894 00895 void ProgramGraphParser::seencallfunclabel( iter_t begin, iter_t end ) 00896 { 00897 // Used for "call xyz" 00898 // lookup mcallfunc 00899 seenfuncidentifier( begin, end ); 00900 00901 assert( mcondition ); 00902 assert( mcallfunc ); 00903 program_builder->appendFunction( mcondition, mcallfunc, callfnargs); 00904 mcondition = 0; 00905 00906 } 00907 00908 void ProgramGraphParser::seencontinue( ) 00909 { 00910 // @todo complete the impl for for/while loops. 00911 // Used for "continue" 00912 assert ( mcondition ); 00913 00914 // connect to next node under given condition. 00915 program_builder->addConditionEdge( mcondition, program_builder->nextNode() ); 00916 00917 mcondition = 0; 00918 } 00919 }