Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:11

0001 // Copyright 2004-9 Trustees of Indiana University
0002 
0003 // Distributed under the Boost Software License, Version 1.0.
0004 // (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //
0008 // read_graphviz_spirit.hpp -
0009 //   Initialize a model of the BGL's MutableGraph concept and an associated
0010 //  collection of property maps using a graph expressed in the GraphViz
0011 // DOT Language.
0012 //
0013 //   Based on the grammar found at:
0014 //   https://web.archive.org/web/20041213234742/http://www.graphviz.org/cvs/doc/info/lang.html
0015 //
0016 //   See documentation for this code at:
0017 //     http://www.boost.org/libs/graph/doc/read_graphviz.html
0018 //
0019 
0020 // Author: Ronald Garcia
0021 //
0022 
0023 #ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
0024 #define BOOST_READ_GRAPHVIZ_SPIRIT_HPP
0025 
0026 // Phoenix/Spirit set these limits to 3, but I need more.
0027 #define PHOENIX_LIMIT 6
0028 #define BOOST_SPIRIT_CLOSURE_LIMIT 6
0029 
0030 #include <boost/spirit/include/classic_multi_pass.hpp>
0031 #include <boost/spirit/include/classic_core.hpp>
0032 #include <boost/spirit/include/classic_confix.hpp>
0033 #include <boost/spirit/include/classic_distinct.hpp>
0034 #include <boost/spirit/include/classic_lists.hpp>
0035 #include <boost/spirit/include/classic_escape_char.hpp>
0036 #include <boost/spirit/include/classic_attribute.hpp>
0037 #include <boost/spirit/include/classic_dynamic.hpp>
0038 #include <boost/spirit/include/classic_actor.hpp>
0039 #include <boost/spirit/include/classic_closure.hpp>
0040 #include <boost/spirit/include/phoenix1.hpp>
0041 #include <boost/spirit/include/phoenix1_binders.hpp>
0042 #include <boost/ref.hpp>
0043 #include <boost/function/function2.hpp>
0044 #include <boost/type_traits/is_same.hpp>
0045 #include <boost/property_map/dynamic_property_map.hpp>
0046 #include <boost/graph/graph_traits.hpp>
0047 #include <boost/detail/workaround.hpp>
0048 #include <algorithm>
0049 #include <exception> // for std::exception
0050 #include <string>
0051 #include <vector>
0052 #include <set>
0053 #include <utility>
0054 #include <map>
0055 #include <boost/graph/graphviz.hpp>
0056 #include <boost/throw_exception.hpp>
0057 
0058 namespace phoenix
0059 {
0060 // Workaround:  std::map::operator[] uses a different return type than all
0061 // other standard containers.  Phoenix doesn't account for that.
0062 template < typename TK, typename T0, typename T1 >
0063 struct binary_operator< index_op, std::map< TK, T0 >, T1 >
0064 {
0065     typedef typename std::map< TK, T0 >::mapped_type& result_type;
0066     static result_type eval(std::map< TK, T0 >& container, T1 const& index)
0067     {
0068         return container[index];
0069     }
0070 };
0071 } // namespace phoenix
0072 
0073 namespace boost
0074 {
0075 namespace detail
0076 {
0077     namespace graph
0078     {
0079 
0080         /////////////////////////////////////////////////////////////////////////////
0081         // Application-specific type definitions
0082         /////////////////////////////////////////////////////////////////////////////
0083 
0084         typedef std::set< edge_t > edges_t;
0085         typedef std::set< node_t > nodes_t;
0086         typedef std::set< id_t > ids_t;
0087         typedef std::map< edge_t, ids_t > edge_map_t;
0088         typedef std::map< node_t, ids_t > node_map_t;
0089         typedef std::map< id_t, id_t > props_t;
0090         typedef std::map< id_t, props_t > subgraph_props_t;
0091         typedef boost::function2< void, id_t const&, id_t const& > actor_t;
0092         typedef std::vector< edge_t > edge_stack_t;
0093         typedef std::map< id_t, nodes_t > subgraph_nodes_t;
0094         typedef std::map< id_t, edges_t > subgraph_edges_t;
0095 
0096         /////////////////////////////////////////////////////////////////////////////
0097         // Stack frames used by semantic actions
0098         /////////////////////////////////////////////////////////////////////////////
0099         struct id_closure
0100         : boost::spirit::classic::closure< id_closure, node_t >
0101         {
0102             member1 name;
0103         };
0104 
0105         struct node_id_closure
0106         : boost::spirit::classic::closure< node_id_closure, node_t >
0107         {
0108             member1 name;
0109         };
0110 
0111         struct attr_list_closure
0112         : boost::spirit::classic::closure< attr_list_closure, actor_t >
0113         {
0114             member1 prop_actor;
0115         };
0116 
0117         struct property_closure
0118         : boost::spirit::classic::closure< property_closure, id_t, id_t >
0119         {
0120             member1 key;
0121             member2 value;
0122         };
0123 
0124         struct data_stmt_closure
0125         : boost::spirit::classic::closure< data_stmt_closure, nodes_t, nodes_t,
0126               edge_stack_t, bool, node_t >
0127         {
0128             member1 sources;
0129             member2 dests;
0130             member3 edge_stack;
0131             member4 saw_node;
0132             member5 active_node;
0133         };
0134 
0135         struct subgraph_closure
0136         : boost::spirit::classic::closure< subgraph_closure, nodes_t, edges_t,
0137               node_t >
0138         {
0139             member1 nodes;
0140             member2 edges;
0141             member3 name;
0142         };
0143 
0144         /////////////////////////////////////////////////////////////////////////////
0145         // Grammar and Actions for the DOT Language
0146         /////////////////////////////////////////////////////////////////////////////
0147 
0148         // Grammar for a dot file.
0149         struct dot_grammar
0150         : public boost::spirit::classic::grammar< dot_grammar >
0151         {
0152             mutate_graph& graph_;
0153             explicit dot_grammar(mutate_graph& graph) : graph_(graph) {}
0154 
0155             template < class ScannerT > struct definition
0156             {
0157 
0158                 definition(dot_grammar const& self)
0159                 : self(self), subgraph_depth(0), keyword_p("0-9a-zA-Z_")
0160                 {
0161                     using namespace boost::spirit::classic;
0162                     using namespace phoenix;
0163 
0164                     // RG - Future Work
0165                     // - Handle multi-line strings using \ line continuation
0166                     // - Make keywords case insensitive
0167                     ID = (lexeme_d[(
0168                               (alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
0169                         | real_p | lexeme_d[confix_p('"', *c_escape_ch_p, '"')]
0170                         | comment_nest_p('<', '>'))[ID.name
0171                         = construct_< std::string >(arg1, arg2)];
0172 
0173                     a_list = list_p(
0174                         ID[(a_list.key = arg1), (a_list.value = "true")] >> !(
0175                             ch_p('=') >> ID[a_list.value = arg1])[phoenix::bind(
0176                             &definition::call_prop_actor)(
0177                             var(*this), a_list.key, a_list.value)],
0178                         !ch_p(','));
0179 
0180                     attr_list = +(ch_p('[') >> !a_list >> ch_p(']'));
0181 
0182                     // RG - disregard port id's for now.
0183                     port_location = (ch_p(':') >> ID)
0184                         | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID
0185                             >> ch_p(')'));
0186 
0187                     port_angle = ch_p('@') >> ID;
0188 
0189                     port = port_location >> (!port_angle)
0190                         | port_angle >> (!port_location);
0191 
0192                     node_id
0193                         = (ID[node_id.name = arg1] >> (!port))[phoenix::bind(
0194                             &definition::memoize_node)(var(*this))];
0195 
0196                     graph_stmt = (ID[graph_stmt.key = arg1] >> ch_p('=')
0197                         >> ID[graph_stmt.value = arg1])[phoenix::bind(
0198                         &definition::call_graph_prop)(var(*this),
0199                         graph_stmt.key, graph_stmt.value)]; // Graph property.
0200 
0201                     attr_stmt
0202                         = (as_lower_d[keyword_p("graph")] >> attr_list(actor_t(
0203                                phoenix::bind(&definition::default_graph_prop)(
0204                                    var(*this), arg1, arg2))))
0205                         | (as_lower_d[keyword_p("node")] >> attr_list(actor_t(
0206                                phoenix::bind(&definition::default_node_prop)(
0207                                    var(*this), arg1, arg2))))
0208                         | (as_lower_d[keyword_p("edge")] >> attr_list(actor_t(
0209                                phoenix::bind(&definition::default_edge_prop)(
0210                                    var(*this), arg1, arg2))));
0211 
0212                     // edge_head is set depending on the graph type
0213                     // (directed/undirected)
0214                     edgeop = ch_p('-') >> ch_p(boost::ref(edge_head));
0215 
0216                     edgeRHS = +(edgeop[(data_stmt.sources = data_stmt.dests),
0217                                     (data_stmt.dests = construct_< nodes_t >())]
0218                         >> (subgraph[data_stmt.dests = arg1]
0219                             | node_id[phoenix::bind(&definition::insert_node)(
0220                                 var(*this), data_stmt.dests, arg1)])
0221                             [phoenix::bind(&definition::activate_edge)(
0222                                 var(*this), data_stmt.sources, data_stmt.dests,
0223                                 var(edges), var(default_edge_props))]);
0224 
0225                     // To avoid backtracking, edge, node, and subgraph
0226                     // statements are processed as one nonterminal.
0227                     data_stmt
0228                         = (subgraph[(data_stmt.dests
0229                                         = arg1), // will get moved in rhs
0230                                (data_stmt.saw_node = false)]
0231                               | node_id[(phoenix::bind(
0232                                             &definition::insert_node)(
0233                                             var(*this), data_stmt.dests, arg1)),
0234                                   (data_stmt.saw_node = true),
0235 #ifdef BOOST_GRAPH_DEBUG
0236                                   (std::cout << val("AcTive Node: ") << arg1
0237                                              << "\n"),
0238 #endif // BOOST_GRAPH_DEBUG
0239                                   (data_stmt.active_node = arg1)])
0240                         >> if_p(edgeRHS)[!attr_list(actor_t(phoenix::bind(
0241                                              &definition::edge_prop)(
0242                                              var(*this), arg1, arg2)))]
0243                                .else_p[if_p(data_stmt.saw_node)[!attr_list(
0244                                    actor_t(phoenix::bind(
0245                                        &definition::node_prop)(var(*this), arg1,
0246                                        arg2)))] // otherwise it's a subgraph,
0247                                                 // nothing more to do.
0248                     ];
0249 
0250                     stmt = graph_stmt | attr_stmt | data_stmt;
0251 
0252                     stmt_list = *(stmt >> !ch_p(';'));
0253 
0254                     subgraph = !(as_lower_d[keyword_p("subgraph")]
0255                                    >> (!ID[(subgraph.name = arg1),
0256                                        (subgraph.nodes
0257                                            = (var(subgraph_nodes))[arg1]),
0258                                        (subgraph.edges
0259                                            = (var(subgraph_edges))[arg1])]))
0260                             >> ch_p('{')[++var(subgraph_depth)] >> stmt_list
0261                             >> ch_p('}')[--var(subgraph_depth)]
0262                                         [(var(subgraph_nodes))[subgraph.name]
0263                                             = subgraph.nodes]
0264                                         [(var(subgraph_edges))[subgraph.name]
0265                                             = subgraph.edges]
0266 
0267                         | as_lower_d[keyword_p("subgraph")]
0268                             >> ID[(subgraph.nodes
0269                                       = (var(subgraph_nodes))[arg1]),
0270                                 (subgraph.edges = (var(subgraph_edges))[arg1])];
0271 
0272                     the_grammar = (!as_lower_d[keyword_p("strict")])
0273                         >> (as_lower_d[keyword_p(
0274                                 "graph")][(var(edge_head) = '-'),
0275                                 (phoenix::bind(&definition::check_undirected)(
0276                                     var(*this)))]
0277                             | as_lower_d[keyword_p(
0278                                 "digraph")][(var(edge_head) = '>'),
0279                                 (phoenix::bind(&definition::check_directed)(
0280                                     var(*this)))])
0281                         >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}');
0282 
0283                 } // definition()
0284 
0285                 typedef boost::spirit::classic::rule< ScannerT > rule_t;
0286 
0287                 rule_t const& start() const { return the_grammar; }
0288 
0289                 //
0290                 // Semantic actions
0291                 //
0292 
0293                 void check_undirected()
0294                 {
0295                     if (self.graph_.is_directed())
0296                         boost::throw_exception(boost::undirected_graph_error());
0297                 }
0298 
0299                 void check_directed()
0300                 {
0301                     if (!self.graph_.is_directed())
0302                         boost::throw_exception(boost::directed_graph_error());
0303                 }
0304 
0305                 void memoize_node()
0306                 {
0307                     id_t const& node = node_id.name();
0308                     props_t& node_props = default_node_props;
0309 
0310                     if (nodes.find(node) == nodes.end())
0311                     {
0312                         nodes.insert(node);
0313                         self.graph_.do_add_vertex(node);
0314 
0315                         node_map.insert(std::make_pair(node, ids_t()));
0316 
0317 #ifdef BOOST_GRAPH_DEBUG
0318                         std::cout << "Add new node " << node << std::endl;
0319 #endif // BOOST_GRAPH_DEBUG
0320        // Set the default properties for this edge
0321        // RG: Here I  would actually set the properties
0322                         for (props_t::iterator i = node_props.begin();
0323                              i != node_props.end(); ++i)
0324                         {
0325                             set_node_property(node, i->first, i->second);
0326                         }
0327                         if (subgraph_depth > 0)
0328                         {
0329                             subgraph.nodes().insert(node);
0330                             // Set the subgraph's default properties as well
0331                             props_t& props
0332                                 = subgraph_node_props[subgraph.name()];
0333                             for (props_t::iterator i = props.begin();
0334                                  i != props.end(); ++i)
0335                             {
0336                                 set_node_property(node, i->first, i->second);
0337                             }
0338                         }
0339                     }
0340                     else
0341                     {
0342 #ifdef BOOST_GRAPH_DEBUG
0343                         std::cout << "See node " << node << std::endl;
0344 #endif // BOOST_GRAPH_DEBUG
0345                     }
0346                 }
0347 
0348                 void activate_edge(nodes_t& sources, nodes_t& dests,
0349                     edges_t& edges, props_t& edge_props)
0350                 {
0351                     edge_stack_t& edge_stack = data_stmt.edge_stack();
0352                     for (nodes_t::iterator i = sources.begin();
0353                          i != sources.end(); ++i)
0354                     {
0355                         for (nodes_t::iterator j = dests.begin();
0356                              j != dests.end(); ++j)
0357                         {
0358                             // Create the edge and push onto the edge stack.
0359 #ifdef BOOST_GRAPH_DEBUG
0360                             std::cout << "Edge " << *i << " to " << *j
0361                                       << std::endl;
0362 #endif // BOOST_GRAPH_DEBUG
0363 
0364                             edge_t edge = edge_t::new_edge();
0365                             edge_stack.push_back(edge);
0366                             edges.insert(edge);
0367                             edge_map.insert(std::make_pair(edge, ids_t()));
0368 
0369                             // Add the real edge.
0370                             self.graph_.do_add_edge(edge, *i, *j);
0371 
0372                             // Set the default properties for this edge
0373                             for (props_t::iterator k = edge_props.begin();
0374                                  k != edge_props.end(); ++k)
0375                             {
0376                                 set_edge_property(edge, k->first, k->second);
0377                             }
0378                             if (subgraph_depth > 0)
0379                             {
0380                                 subgraph.edges().insert(edge);
0381                                 // Set the subgraph's default properties as well
0382                                 props_t& props
0383                                     = subgraph_edge_props[subgraph.name()];
0384                                 for (props_t::iterator k = props.begin();
0385                                      k != props.end(); ++k)
0386                                 {
0387                                     set_edge_property(
0388                                         edge, k->first, k->second);
0389                                 }
0390                             }
0391                         }
0392                     }
0393                 }
0394 
0395                 // node_prop - Assign the property for the current active node.
0396                 void node_prop(id_t const& key, id_t const& value)
0397                 {
0398                     node_t& active_object = data_stmt.active_node();
0399                     set_node_property(active_object, key, value);
0400                 }
0401 
0402                 // edge_prop - Assign the property for the current active edges.
0403                 void edge_prop(id_t const& key, id_t const& value)
0404                 {
0405                     edge_stack_t const& active_edges_ = data_stmt.edge_stack();
0406                     for (edge_stack_t::const_iterator i = active_edges_.begin();
0407                          i != active_edges_.end(); ++i)
0408                     {
0409                         set_edge_property(*i, key, value);
0410                     }
0411                 }
0412 
0413                 // default_graph_prop - Store as a graph property.
0414                 void default_graph_prop(id_t const& key, id_t const& value)
0415                 {
0416 #ifdef BOOST_GRAPH_DEBUG
0417                     std::cout << key << " = " << value << std::endl;
0418 #endif // BOOST_GRAPH_DEBUG
0419                     self.graph_.set_graph_property(key, value);
0420                 }
0421 
0422                 // default_node_prop - declare default properties for any future
0423                 // new nodes
0424                 void default_node_prop(id_t const& key, id_t const& value)
0425                 {
0426                     nodes_t& nodes_
0427                         = subgraph_depth == 0 ? nodes : subgraph.nodes();
0428                     props_t& node_props_ = subgraph_depth == 0
0429                         ? default_node_props
0430                         : subgraph_node_props[subgraph.name()];
0431 
0432                     // add this to the selected list of default node properties.
0433                     node_props_[key] = value;
0434                     // for each node, set its property to default-constructed
0435                     // value
0436                     //   if it hasn't been set already.
0437                     // set the dynamic property map value
0438                     for (nodes_t::iterator i = nodes_.begin();
0439                          i != nodes_.end(); ++i)
0440                         if (node_map[*i].find(key) == node_map[*i].end())
0441                         {
0442                             set_node_property(*i, key, id_t());
0443                         }
0444                 }
0445 
0446                 // default_edge_prop - declare default properties for any future
0447                 // new edges
0448                 void default_edge_prop(id_t const& key, id_t const& value)
0449                 {
0450                     edges_t& edges_
0451                         = subgraph_depth == 0 ? edges : subgraph.edges();
0452                     props_t& edge_props_ = subgraph_depth == 0
0453                         ? default_edge_props
0454                         : subgraph_edge_props[subgraph.name()];
0455 
0456                     // add this to the list of default edge properties.
0457                     edge_props_[key] = value;
0458                     // for each edge, set its property to be empty string
0459                     // set the dynamic property map value
0460                     for (edges_t::iterator i = edges_.begin();
0461                          i != edges_.end(); ++i)
0462                         if (edge_map[*i].find(key) == edge_map[*i].end())
0463                             set_edge_property(*i, key, id_t());
0464                 }
0465 
0466                 // helper function
0467                 void insert_node(nodes_t& nodes, id_t const& name)
0468                 {
0469                     nodes.insert(name);
0470                 }
0471 
0472                 void call_prop_actor(
0473                     std::string const& lhs, std::string const& rhs)
0474                 {
0475                     actor_t& actor = attr_list.prop_actor();
0476                     // If first and last characters of the rhs are
0477                     // double-quotes, remove them.
0478                     if (!rhs.empty() && rhs[0] == '"'
0479                         && rhs[rhs.size() - 1] == '"')
0480                         actor(lhs, rhs.substr(1, rhs.size() - 2));
0481                     else
0482                         actor(lhs, rhs);
0483                 }
0484 
0485                 void call_graph_prop(
0486                     std::string const& lhs, std::string const& rhs)
0487                 {
0488                     // If first and last characters of the rhs are
0489                     // double-quotes, remove them.
0490                     if (!rhs.empty() && rhs[0] == '"'
0491                         && rhs[rhs.size() - 1] == '"')
0492                         this->default_graph_prop(
0493                             lhs, rhs.substr(1, rhs.size() - 2));
0494                     else
0495                         this->default_graph_prop(lhs, rhs);
0496                 }
0497 
0498                 void set_node_property(
0499                     node_t const& node, id_t const& key, id_t const& value)
0500                 {
0501 
0502                     // Add the property key to the "set" table to avoid default
0503                     // overwrite
0504                     node_map[node].insert(key);
0505                     // Set the user's property map
0506                     self.graph_.set_node_property(key, node, value);
0507 #ifdef BOOST_GRAPH_DEBUG
0508                     // Tell the world
0509                     std::cout << node << ": " << key << " = " << value
0510                               << std::endl;
0511 #endif // BOOST_GRAPH_DEBUG
0512                 }
0513 
0514                 void set_edge_property(
0515                     edge_t const& edge, id_t const& key, id_t const& value)
0516                 {
0517 
0518                     // Add the property key to the "set" table to avoid default
0519                     // overwrite
0520                     edge_map[edge].insert(key);
0521                     // Set the user's property map
0522                     self.graph_.set_edge_property(key, edge, value);
0523 #ifdef BOOST_GRAPH_DEBUG
0524                     // Tell the world
0525 #if 0 // RG - edge representation changed,
0526             std::cout << "(" << edge.first << "," << edge.second << "): "
0527 #else
0528                     std::cout << "an edge: "
0529 #endif // 0
0530                     << key << " = " << value << std::endl;
0531 #endif // BOOST_GRAPH_DEBUG
0532                 }
0533 
0534                 // Variables explicitly initialized
0535                 dot_grammar const& self;
0536                 // if subgraph_depth > 0, then we're processing a subgraph.
0537                 int subgraph_depth;
0538 
0539                 // Keywords;
0540                 const boost::spirit::classic::distinct_parser<> keyword_p;
0541                 //
0542                 // rules that make up the grammar
0543                 //
0544                 boost::spirit::classic::rule< ScannerT, id_closure::context_t >
0545                     ID;
0546                 boost::spirit::classic::rule< ScannerT,
0547                     property_closure::context_t >
0548                     a_list;
0549                 boost::spirit::classic::rule< ScannerT,
0550                     attr_list_closure::context_t >
0551                     attr_list;
0552                 rule_t port_location;
0553                 rule_t port_angle;
0554                 rule_t port;
0555                 boost::spirit::classic::rule< ScannerT,
0556                     node_id_closure::context_t >
0557                     node_id;
0558                 boost::spirit::classic::rule< ScannerT,
0559                     property_closure::context_t >
0560                     graph_stmt;
0561                 rule_t attr_stmt;
0562                 boost::spirit::classic::rule< ScannerT,
0563                     data_stmt_closure::context_t >
0564                     data_stmt;
0565                 boost::spirit::classic::rule< ScannerT,
0566                     subgraph_closure::context_t >
0567                     subgraph;
0568                 rule_t edgeop;
0569                 rule_t edgeRHS;
0570                 rule_t stmt;
0571                 rule_t stmt_list;
0572                 rule_t the_grammar;
0573 
0574                 // The grammar uses edge_head to dynamically set the syntax for
0575                 // edges directed graphs: edge_head = '>', and so edgeop = "->"
0576                 // undirected graphs: edge_head = '-', and so edgeop = "--"
0577                 char edge_head;
0578 
0579                 //
0580                 // Support data structures
0581                 //
0582 
0583                 nodes_t nodes; // list of node names seen
0584                 edges_t edges; // list of edges seen
0585                 node_map_t
0586                     node_map; // remember the properties set for each node
0587                 edge_map_t
0588                     edge_map; // remember the properties set for each edge
0589 
0590                 subgraph_nodes_t subgraph_nodes; // per-subgraph lists of nodes
0591                 subgraph_edges_t subgraph_edges; // per-subgraph lists of edges
0592 
0593                 props_t default_node_props; // global default node properties
0594                 props_t default_edge_props; // global default edge properties
0595                 subgraph_props_t
0596                     subgraph_node_props; // per-subgraph default node properties
0597                 subgraph_props_t
0598                     subgraph_edge_props; // per-subgraph default edge properties
0599             }; // struct definition
0600         }; // struct dot_grammar
0601 
0602         //
0603         // dot_skipper - GraphViz whitespace and comment skipper
0604         //
0605         struct dot_skipper
0606         : public boost::spirit::classic::grammar< dot_skipper >
0607         {
0608             dot_skipper() {}
0609 
0610             template < typename ScannerT > struct definition
0611             {
0612                 definition(dot_skipper const& /*self*/)
0613                 {
0614                     using namespace boost::spirit::classic;
0615                     using namespace phoenix;
0616                     // comment forms
0617                     skip = eol_p >> comment_p("#") | space_p | comment_p("//")
0618 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
0619                         | confix_p(str_p("/*"), *anychar_p, str_p("*/"))
0620 #else
0621                         | confix_p("/*", *anychar_p, "*/")
0622 #endif
0623                         ;
0624 
0625 #ifdef BOOST_SPIRIT_DEBUG
0626                     BOOST_SPIRIT_DEBUG_RULE(skip);
0627 #endif
0628                 }
0629 
0630                 boost::spirit::classic::rule< ScannerT > skip;
0631                 boost::spirit::classic::rule< ScannerT > const& start() const
0632                 {
0633                     return skip;
0634                 }
0635             }; // definition
0636         }; // dot_skipper
0637 
0638     } // namespace graph
0639 } // namespace detail
0640 
0641 template < typename MultiPassIterator, typename MutableGraph >
0642 bool read_graphviz_spirit(MultiPassIterator begin, MultiPassIterator end,
0643     MutableGraph& graph, dynamic_properties& dp,
0644     std::string const& node_id = "node_id")
0645 {
0646     using namespace boost;
0647     using namespace boost::spirit::classic;
0648 
0649     typedef MultiPassIterator iterator_t;
0650     typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper >
0651         iter_policy_t;
0652     typedef scanner_policies< iter_policy_t > scanner_policies_t;
0653     typedef scanner< iterator_t, scanner_policies_t > scanner_t;
0654 
0655     ::boost::detail::graph::mutate_graph_impl< MutableGraph > m_graph(
0656         graph, dp, node_id);
0657 
0658     ::boost::detail::graph::dot_grammar p(m_graph);
0659     ::boost::detail::graph::dot_skipper skip_p;
0660 
0661     iter_policy_t iter_policy(skip_p);
0662     scanner_policies_t policies(iter_policy);
0663 
0664     scanner_t scan(begin, end, policies);
0665 
0666     bool ok = p.parse(scan);
0667     m_graph.finish_building_graph();
0668     return ok;
0669 }
0670 
0671 } // namespace boost
0672 
0673 #endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP