FunctionGraphBuilder.cpp
Go to the documentation of this file.
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 


rtt
Author(s): RTT Developers
autogenerated on Thu Jan 2 2014 11:35:21