$search
00001 /*************************************************************************** 00002 tag: Peter Soetens Wed Jan 18 14:11:40 CET 2006 FunctionGraphBuilder.cxx 00003 00004 FunctionGraphBuilder.cxx - description 00005 ------------------- 00006 begin : Wed January 18 2006 00007 copyright : (C) 2006 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.be 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 00040 #include "FunctionGraphBuilder.hpp" 00041 #include "CommandComposite.hpp" 00042 #include "../base/AttributeBase.hpp" 00043 #include "../internal/DataSource.hpp" 00044 //#include "parse_exception.hpp" 00045 #include "../FactoryExceptions.hpp" 00046 #include "GraphCopier.hpp" 00047 00048 #include "CommandNOP.hpp" 00049 #include "ConditionFalse.hpp" 00050 #include "ConditionTrue.hpp" 00051 #include "ConditionTrue.hpp" 00052 #include <boost/graph/copy.hpp> 00053 #include <utility> 00054 00055 #include <iostream> 00056 00057 namespace RTT { 00058 using namespace detail; 00059 using namespace boost; 00060 using namespace std; 00061 00062 00063 00064 00065 FunctionGraphBuilder::FunctionGraphBuilder() 00066 : graph( 0 ) 00067 { 00068 } 00069 00070 FunctionGraphBuilder::~FunctionGraphBuilder() 00071 { 00072 } 00073 00074 FunctionGraphPtr FunctionGraphBuilder::startFunction(const std::string& fname) 00075 { 00076 // next node should be 'empty'/ not used here. 00077 // a function is to be constructed, it will unload when it stops/errors 00078 func.reset( new FunctionGraph( fname, true ) ); 00079 graph = &func->getGraph(); 00080 build = func->startNode(); 00081 next = add_vertex( *graph ); 00082 put( vertex_exec, *graph, next, VertexNode::normal_node ); 00083 return func; 00084 } 00085 00086 void FunctionGraphBuilder::returnFunction( ConditionInterface* cond, int line ) 00087 { 00088 // connect the build node to the exitNode under a condition, 00089 // for example, the build implicit term condition. 00090 add_edge(build, func->exitNode(), EdgeCondition(cond), *graph); 00091 } 00092 00093 FunctionGraphPtr FunctionGraphBuilder::getFunction() 00094 { 00095 return func; 00096 } 00097 00098 FunctionGraphPtr FunctionGraphBuilder::endFunction( int endline ) 00099 { 00100 // the map contains _references_ to all vertex_command properties 00101 boost::property_map<Graph, vertex_command_t>::type 00102 cmap = get(vertex_command, *graph); 00103 cmap[func->exitNode()].setLineNumber( endline ); 00104 00105 // A return statement is obligatory, so the returnFunction has 00106 // already connected the build node to exitNode of the function. 00107 // the end of the statement will proceedToNext 00108 // remove the empty next nodes. 00109 remove_vertex( build, *graph ); 00110 remove_vertex( next, *graph ); 00111 00112 func->finish(); 00113 func->reset(); 00114 00115 FunctionGraphPtr tfunc = func; 00116 func.reset(); 00117 return tfunc; 00118 } 00119 00120 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::addCommand( ConditionInterface* cond, ActionInterface* com ) 00121 { 00122 add_edge(build, next, EdgeCondition(cond), *graph); 00123 build = next; 00124 setCommand(com); 00125 next = add_vertex( *graph ); 00126 put( vertex_exec, *graph, next, VertexNode::normal_node ); 00127 return next; 00128 } 00129 00130 void FunctionGraphBuilder::addConditionEdge( ConditionInterface* cond, CommandNode vert ) 00131 { 00132 add_edge(build, vert, EdgeCondition(cond), *graph); 00133 } 00134 00135 void FunctionGraphBuilder::closeConditionEdge( CommandNode vert, ConditionInterface* cond ) 00136 { 00137 add_edge(vert, build, EdgeCondition(cond), *graph); 00138 } 00139 00140 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::moveTo( CommandNode _build, CommandNode _next, int linenumber ) 00141 { 00142 this->setLineNumber( linenumber ); 00143 CommandNode old = build; 00144 build = _build; 00145 next = _next; 00146 return old; 00147 } 00148 00149 ActionInterface* FunctionGraphBuilder::getCommand( CommandNode cn ) 00150 { 00151 // the map contains _references_ to all vertex_command properties 00152 boost::property_map<Graph, vertex_command_t>::type 00153 cmap = get(vertex_command, *graph); 00154 // access the one of build 00155 return cmap[cn].getCommand(); 00156 } 00157 00158 void FunctionGraphBuilder::setCommand( ActionInterface* comm ) 00159 { 00160 this->setCommand(build, comm); 00161 } 00162 00163 void FunctionGraphBuilder::setCommand(CommandNode cn, ActionInterface* comm ) 00164 { 00165 // the map contains _references_ to all vertex_command properties 00166 boost::property_map<Graph, vertex_command_t>::type 00167 cmap = get(vertex_command, *graph); 00168 // access the one of build 00169 delete cmap[cn].setCommand( comm ); 00170 } 00171 00172 void FunctionGraphBuilder::setName(const std::string& pname) { 00173 func->setName(pname); 00174 } 00175 00176 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::proceedToNext( ConditionInterface* cond, int this_line ) 00177 { 00178 add_edge(build, next, EdgeCondition(cond), *graph); 00179 return proceedToNext( this_line ); 00180 } 00181 00182 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::proceedToNext( int this_line ) 00183 { 00184 if ( this_line ) 00185 this->setLineNumber( this_line ); 00186 build = next; 00187 next = add_vertex( *graph ); 00188 put(vertex_exec, *graph, next, VertexNode::normal_node ); 00189 return build; 00190 } 00191 00192 void FunctionGraphBuilder::connectToNext( CommandNode v, ConditionInterface* cond ) 00193 { 00194 add_edge( v, next, EdgeCondition(cond), *graph); 00195 } 00196 00197 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::buildNode() const 00198 { 00199 return build; 00200 } 00201 00202 size_t FunctionGraphBuilder::buildEdges() const 00203 { 00204 return out_degree( build, *graph ); 00205 } 00206 00207 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::nextNode() const 00208 { 00209 return next; 00210 } 00211 00212 void FunctionGraphBuilder::setLineNumber( int line ) 00213 { 00214 boost::property_map<Graph, vertex_command_t>::type 00215 cmap = get(vertex_command, *graph); 00216 cmap[build].setLineNumber( line ); 00217 } 00218 00219 00220 template< class _Map > 00221 struct finder { 00222 typedef FunctionGraphBuilder::Vertex first_argument_type ; 00223 typedef std::pair<_Map, int> second_argument_type ; 00224 typedef bool result_type; 00225 bool operator()(const FunctionGraphBuilder::Vertex& v, 00226 const std::pair<_Map, int>& to_find ) const 00227 { 00228 // return : Is this the node with the given property ? 00229 return to_find.first[v] == to_find.second; 00230 } 00231 }; 00232 00233 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::appendFunction( ConditionInterface* cond, FunctionGraphPtr fn, 00234 std::vector<DataSourceBase::shared_ptr> fnargs ) 00235 { 00239 // Do not move build inhere ! 00240 // copy FunctionGraph's graph into the current *graph, add an edge with 00241 // the condition. Connect the exitNode() of the function with 00242 // the next node. 00243 00244 // The reason to reindex the vertexes of source graph is 00245 // to silence valgrinds warnings about uninitialised values 00246 // in the following piece of code. Technically, copy_graph 00247 // does not need it. 00248 boost::property_map<Graph, vertex_index_t>::type indexmap = 00249 get( vertex_index, *graph ); 00250 boost::graph_traits<Graph>::vertex_iterator v, vend; 00251 int index = 0; 00252 for ( tie( v, vend ) = vertices( *graph ); v != vend; ++v ) 00253 indexmap[*v] = index++; 00254 00255 // check nb of arguments: 00256 std::vector<AttributeBase*> origlist = fn->getArguments(); 00257 if ( fnargs.size() != origlist.size() ) { 00258 #ifndef ORO_EMBEDDED 00259 throw wrong_number_of_args_exception( origlist.size(), fnargs.size() ); 00260 #else 00261 return buildNode(); 00262 #endif 00263 } 00264 00265 // make a deep copy of the function : 00266 std::map<const DataSourceBase*, DataSourceBase*> replacementdss; 00267 std::vector<AttributeBase*> newlist; 00268 for (unsigned int i=0; i < origlist.size(); ++i) 00269 newlist.push_back( origlist[i]->copy( replacementdss, false ) ); // args are not instantiated. 00270 // newlist contains the DS which need initialisations : 00271 00272 // create commands that init all the args : 00273 CommandComposite* icom= new CommandComposite(); 00274 std::vector<DataSourceBase::shared_ptr>::const_iterator dit = fnargs.begin(); 00275 std::vector<AttributeBase*>::const_iterator tit = newlist.begin(); 00276 #ifndef ORO_EMBEDDED 00277 try { 00278 for (; dit != fnargs.end(); ++dit, ++tit) 00279 icom->add( (*tit)->getDataSource()->updateAction( dit->get() ) ); 00280 } 00281 catch( const bad_assignment& ) { 00282 // cleanup allocated memory 00283 for (unsigned int i=0; i < newlist.size(); ++i) 00284 delete newlist[i]; 00285 delete icom; 00286 int parnb = (dit - fnargs.begin()); 00287 throw wrong_types_of_args_exception(parnb, (*tit)->getDataSource()->getType() ,(*dit)->getType() ); 00288 } 00289 #else 00290 for (; dit != fnargs.end(); ++dit, ++tit) { 00291 ActionInterface* ret = (*tit)->getDataSource()->updateAction( dit->get() ); 00292 if (ret) 00293 icom->add( ret ); 00294 else { 00295 // cleanup allocated memory 00296 for (unsigned int i=0; i < newlist.size(); ++i) 00297 delete newlist[i]; 00298 delete icom; 00299 return buildNode(); 00300 } 00301 } 00302 #endif 00303 // set the init command on the build node 00304 //assert( build not used by other than NOP ) 00305 assert( dynamic_cast<CommandNOP*>( this->getCommand(build) )); 00306 this->setCommand( icom ); 00307 00308 boost::copy_graph( fn->getGraph(), *graph, 00309 boost::vertex_copy( GraphVertexCopier( fn->getGraph(), *graph, replacementdss ) ). 00310 edge_copy( GraphEdgeCopier( fn->getGraph(), *graph, replacementdss ) ) ); 00311 00312 // cleanup newlist, the (var)DS's are stored in the assignCommand 00313 for (unsigned int i=0; i < newlist.size(); ++i) 00314 delete newlist[i]; 00315 00316 // the subgraph has been copied but is now 'floating' in the current graph. 00317 // we search func start and exit points and connect them to 00318 // the current graph. 00319 00320 // domi: it would be cleaner if a function would keep a 00321 // reference to its enter and exit point, and we would use the 00322 // copy_graph orig_to_copy map to find the corresponding nodes 00323 // in the copy... 00324 graph_traits<Graph>::vertex_iterator v1,v2, vc; 00325 tie(v1,v2) = vertices(*graph); 00326 boost::property_map<Graph, vertex_exec_t>::type 00327 vmap = get(vertex_exec, *graph); 00328 00329 // // test not initialised value. 00330 // vc = v1; 00331 // while (vc != v2) { 00332 // std::cerr << int( vmap[*vc] )<<std::endl; 00333 // ++vc; 00334 // } 00335 // std::cerr<<std::endl; 00336 // // test foo : 00337 // tie(v1,v2) = vertices(fn->getGraph()); 00338 // vmap = get(vertex_exec, fn->getGraph()); 00339 // vc = v1; 00340 // while (vc != v2) { 00341 // std::cerr << int( vmap[*vc] )<<std::endl; 00342 // ++vc; 00343 // } 00344 00345 00346 Vertex funcStart=* 00347 find_if(v1, v2, 00348 bind2nd( finder<boost::property_map<Graph, vertex_exec_t>::type>() , 00349 std::make_pair( vmap, int(VertexNode::func_start_node)) ) ); 00350 Vertex funcExit=* 00351 find_if(v1, v2, 00352 bind2nd( finder<boost::property_map<Graph, vertex_exec_t>::type>() , 00353 std::make_pair( vmap, int(VertexNode::func_exit_node)) ) ); 00354 00355 // reset their special meanings. 00356 vmap[funcStart] = VertexNode::normal_node; 00357 vmap[funcExit] = VertexNode::normal_node; 00358 // connect the graph. 00359 addConditionEdge( cond, funcStart ); 00360 connectToNext( funcExit, new ConditionTrue ); 00361 00362 return funcExit; 00363 // // try to solve call in function bug with arguments 00364 // boost::property_map<Graph, vertex_command_t>::type 00365 // cmap = get(vertex_command, *graph); 00366 // return proceedToNext( cmap[funcExit].getLineNumber() ); 00367 } 00368 00369 FunctionGraphBuilder::CommandNode FunctionGraphBuilder::setFunction( FunctionGraphPtr fn, 00370 std::vector<DataSourceBase::shared_ptr> fnargs ) 00371 { 00380 return appendFunction( new ConditionTrue, fn, fnargs) ; 00381 } 00382 00383 void FunctionGraphBuilder::startIfStatement( ConditionInterface* cond, int linenumber ) 00384 { 00385 // push all relevant nodes on the branch_stack. 00386 // endIf and endElse will pop them 00387 00388 // * next will become the first node of the succeeding if statement 00389 // * after_else_node will become the node after the if block is finished 00390 // and the else block is finished. 00391 // * else_node is the first node of a failing if statement (this may be _any_statement, thus also an if) 00392 CommandNode else_node = add_vertex( *graph ); 00393 put(vertex_exec, *graph, else_node, VertexNode::normal_node ); 00394 branch_stack.push( else_node ); 00395 CommandNode after_else_node = add_vertex( *graph ); 00396 put(vertex_exec, *graph, after_else_node, VertexNode::normal_node ); 00397 branch_stack.push( after_else_node ); 00398 //branch_stack.push( build ); 00399 00400 // add edge from build to next 00401 addConditionEdge( cond, next ); 00402 // add edge from build to 'after_else_node' 00403 addConditionEdge( new ConditionTrue(), else_node ); 00404 proceedToNext(linenumber); 00405 } 00406 00407 void FunctionGraphBuilder::endIfBlock(int linenumber){ 00408 // this is called after a proceedToNext of the last statement of 00409 // the if block. 00410 // Connect end of if block with after_else_node 00411 CommandNode after_else_node = branch_stack.top(); 00412 addConditionEdge( new ConditionTrue(), after_else_node ); 00413 branch_stack.pop(); 00414 // make else_node build, next remains. 00415 moveTo( branch_stack.top(), next, linenumber ); 00416 branch_stack.pop(); 00417 // store again ! 00418 branch_stack.push( after_else_node ); 00419 } 00420 00421 // Else : can be empty and is then a plain proceed to next. 00422 void FunctionGraphBuilder::endElseBlock(int linenumber) { 00423 // after_else_node is on top of stack 00424 CommandNode after_else_node = branch_stack.top(); 00425 branch_stack.pop(); 00426 addConditionEdge( new ConditionTrue(), after_else_node ); 00427 // make after_else_node build 00428 moveTo( after_else_node, next, linenumber ); 00429 } 00430 00431 void FunctionGraphBuilder::startWhileStatement( ConditionInterface* cond, int linenumber ) 00432 { 00433 // very analogous to the if statement, but there is no else part 00434 // and we stack the first commandnode to be able to close the loop. 00435 CommandNode after_while_node = add_vertex( *graph ); 00436 put(vertex_exec, *graph, after_while_node, VertexNode::normal_node ); 00437 branch_stack.push( after_while_node ); 00438 break_stack.push( after_while_node ); 00439 branch_stack.push( build ); 00440 // add edge from build to next if condition == true 00441 addConditionEdge( cond, next ); 00442 // if condition fails, go from build to 'after_while_node' 00443 addConditionEdge( new ConditionTrue(), after_while_node ); 00444 proceedToNext(linenumber); 00445 } 00446 00447 void FunctionGraphBuilder::endWhileBlock(int linenumber) 00448 { 00449 CommandNode start_of_while = branch_stack.top(); 00450 branch_stack.pop(); 00451 // go from build back to start (and check there the condition). 00452 addConditionEdge( new ConditionTrue(), start_of_while ); 00453 CommandNode after_while_node = branch_stack.top(); 00454 branch_stack.pop(); 00455 break_stack.pop(); 00456 moveTo( after_while_node, next, linenumber ); 00457 } 00458 00459 bool FunctionGraphBuilder::inLoop() 00460 { 00461 return break_stack.size() != 0; 00462 } 00463 00464 bool FunctionGraphBuilder::breakLoop() 00465 { 00466 if ( !inLoop() ) 00467 return false; 00468 00469 // go from build to last nested exit point. 00470 addConditionEdge( new ConditionTrue(), break_stack.top() ); 00471 return true; 00472 } 00473 00474 #if 0 00475 void FunctionGraphBuilder::prependCommand( ActionInterface* command, int line_nr ) 00476 { 00477 CommandNode previousstart = start; 00478 start = add_vertex( program ); 00479 boost::property_map<Graph, vertex_exec_t>::type 00480 vmap = get(vertex_exec, program); 00481 put( vmap, start, get( vmap, previousstart ) ); 00482 put( vmap, previousstart, VertexNode::normal_node ); 00483 boost::property_map<Graph, vertex_command_t>::type 00484 cmap = get( vertex_command, program ); 00485 VertexNode vnode( command ); 00486 vnode.setLineNumber( line_nr ); 00487 put( cmap, start, vnode ); 00488 add_edge(start, previousstart, EdgeCondition(new ConditionTrue), program); 00489 if ( build == previousstart ) 00490 build = start; 00491 00492 // now let's reindex the vertices... 00493 boost::property_map<Graph, vertex_index_t>::type indexmap = 00494 get( vertex_index, *graph ); 00495 boost::graph_traits<Graph>::vertex_iterator v, vend; 00496 int index = 0; 00497 for ( tie( v, vend ) = vertices( *graph ); v != vend; ++v ) 00498 indexmap[*v] = index++; 00499 } 00500 #endif 00501 00502 } 00503