annotate DEPENDENCIES/generic/include/boost/graph/detail/read_graphviz_spirit.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright 2004-9 Trustees of Indiana University
Chris@16 2
Chris@16 3 // Distributed under the Boost Software License, Version 1.0.
Chris@16 4 // (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 //
Chris@16 8 // read_graphviz_spirit.hpp -
Chris@16 9 // Initialize a model of the BGL's MutableGraph concept and an associated
Chris@16 10 // collection of property maps using a graph expressed in the GraphViz
Chris@16 11 // DOT Language.
Chris@16 12 //
Chris@16 13 // Based on the grammar found at:
Chris@16 14 // http://www.graphviz.org/cvs/doc/info/lang.html
Chris@16 15 //
Chris@16 16 // See documentation for this code at:
Chris@16 17 // http://www.boost.org/libs/graph/doc/read-graphviz.html
Chris@16 18 //
Chris@16 19
Chris@16 20 // Author: Ronald Garcia
Chris@16 21 //
Chris@16 22
Chris@16 23 #ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
Chris@16 24 #define BOOST_READ_GRAPHVIZ_SPIRIT_HPP
Chris@16 25
Chris@16 26 // Phoenix/Spirit set these limits to 3, but I need more.
Chris@16 27 #define PHOENIX_LIMIT 6
Chris@16 28 #define BOOST_SPIRIT_CLOSURE_LIMIT 6
Chris@16 29
Chris@16 30
Chris@16 31 #include <boost/spirit/include/classic_multi_pass.hpp>
Chris@16 32 #include <boost/spirit/include/classic_core.hpp>
Chris@16 33 #include <boost/spirit/include/classic_confix.hpp>
Chris@16 34 #include <boost/spirit/include/classic_distinct.hpp>
Chris@16 35 #include <boost/spirit/include/classic_lists.hpp>
Chris@16 36 #include <boost/spirit/include/classic_escape_char.hpp>
Chris@16 37 #include <boost/spirit/include/classic_attribute.hpp>
Chris@16 38 #include <boost/spirit/include/classic_dynamic.hpp>
Chris@16 39 #include <boost/spirit/include/classic_actor.hpp>
Chris@16 40 #include <boost/spirit/include/classic_closure.hpp>
Chris@16 41 #include <boost/spirit/include/phoenix1.hpp>
Chris@16 42 #include <boost/spirit/include/phoenix1_binders.hpp>
Chris@16 43 #include <boost/ref.hpp>
Chris@16 44 #include <boost/function/function2.hpp>
Chris@16 45 #include <boost/type_traits/is_same.hpp>
Chris@16 46 #include <boost/property_map/dynamic_property_map.hpp>
Chris@16 47 #include <boost/graph/graph_traits.hpp>
Chris@16 48 #include <boost/detail/workaround.hpp>
Chris@16 49 #include <algorithm>
Chris@16 50 #include <exception> // for std::exception
Chris@16 51 #include <string>
Chris@16 52 #include <vector>
Chris@16 53 #include <set>
Chris@16 54 #include <utility>
Chris@16 55 #include <map>
Chris@16 56 #include <boost/graph/graphviz.hpp>
Chris@16 57 #include <boost/throw_exception.hpp>
Chris@16 58
Chris@16 59 namespace phoenix {
Chris@16 60 // Workaround: std::map::operator[] uses a different return type than all
Chris@16 61 // other standard containers. Phoenix doesn't account for that.
Chris@16 62 template <typename TK, typename T0, typename T1>
Chris@16 63 struct binary_operator<index_op, std::map<TK,T0>, T1>
Chris@16 64 {
Chris@16 65 typedef typename std::map<TK,T0>::mapped_type& result_type;
Chris@16 66 static result_type eval(std::map<TK,T0>& container, T1 const& index)
Chris@16 67 { return container[index]; }
Chris@16 68 };
Chris@16 69 } // namespace phoenix
Chris@16 70
Chris@16 71 namespace boost {
Chris@16 72 namespace detail {
Chris@16 73 namespace graph {
Chris@16 74
Chris@16 75
Chris@16 76 /////////////////////////////////////////////////////////////////////////////
Chris@16 77 // Application-specific type definitions
Chris@16 78 /////////////////////////////////////////////////////////////////////////////
Chris@16 79
Chris@16 80 typedef std::set<edge_t> edges_t;
Chris@16 81 typedef std::set<node_t> nodes_t;
Chris@16 82 typedef std::set<id_t> ids_t;
Chris@16 83 typedef std::map<edge_t,ids_t> edge_map_t;
Chris@16 84 typedef std::map<node_t,ids_t> node_map_t;
Chris@16 85 typedef std::map<id_t,id_t> props_t;
Chris@16 86 typedef std::map<id_t,props_t> subgraph_props_t;
Chris@16 87 typedef boost::function2<void, id_t const&, id_t const&> actor_t;
Chris@16 88 typedef std::vector<edge_t> edge_stack_t;
Chris@16 89 typedef std::map<id_t,nodes_t> subgraph_nodes_t;
Chris@16 90 typedef std::map<id_t,edges_t> subgraph_edges_t;
Chris@16 91
Chris@16 92
Chris@16 93
Chris@16 94 /////////////////////////////////////////////////////////////////////////////
Chris@16 95 // Stack frames used by semantic actions
Chris@16 96 /////////////////////////////////////////////////////////////////////////////
Chris@16 97 struct id_closure : boost::spirit::classic::closure<id_closure, node_t> {
Chris@16 98 member1 name;
Chris@16 99 };
Chris@16 100
Chris@16 101
Chris@16 102 struct node_id_closure : boost::spirit::classic::closure<node_id_closure, node_t> {
Chris@16 103 member1 name;
Chris@16 104 };
Chris@16 105
Chris@16 106 struct attr_list_closure : boost::spirit::classic::closure<attr_list_closure, actor_t> {
Chris@16 107 member1 prop_actor;
Chris@16 108 };
Chris@16 109
Chris@16 110 struct property_closure : boost::spirit::classic::closure<property_closure, id_t, id_t> {
Chris@16 111 member1 key;
Chris@16 112 member2 value;
Chris@16 113 };
Chris@16 114
Chris@16 115 struct data_stmt_closure : boost::spirit::classic::closure<data_stmt_closure,
Chris@16 116 nodes_t,nodes_t,edge_stack_t,bool,node_t> {
Chris@16 117 member1 sources;
Chris@16 118 member2 dests;
Chris@16 119 member3 edge_stack;
Chris@16 120 member4 saw_node;
Chris@16 121 member5 active_node;
Chris@16 122 };
Chris@16 123
Chris@16 124 struct subgraph_closure : boost::spirit::classic::closure<subgraph_closure,
Chris@16 125 nodes_t, edges_t, node_t> {
Chris@16 126 member1 nodes;
Chris@16 127 member2 edges;
Chris@16 128 member3 name;
Chris@16 129 };
Chris@16 130
Chris@16 131 /////////////////////////////////////////////////////////////////////////////
Chris@16 132 // Grammar and Actions for the DOT Language
Chris@16 133 /////////////////////////////////////////////////////////////////////////////
Chris@16 134
Chris@16 135 // Grammar for a dot file.
Chris@16 136 struct dot_grammar : public boost::spirit::classic::grammar<dot_grammar> {
Chris@16 137 mutate_graph& graph_;
Chris@16 138 explicit dot_grammar(mutate_graph& graph) : graph_(graph) { }
Chris@16 139
Chris@16 140 template <class ScannerT>
Chris@16 141 struct definition {
Chris@16 142
Chris@16 143 definition(dot_grammar const& self) : self(self), subgraph_depth(0),
Chris@16 144 keyword_p("0-9a-zA-Z_") {
Chris@16 145 using namespace boost::spirit::classic;
Chris@16 146 using namespace phoenix;
Chris@16 147
Chris@16 148 // RG - Future Work
Chris@16 149 // - Handle multi-line strings using \ line continuation
Chris@16 150 // - Make keywords case insensitive
Chris@16 151 ID
Chris@16 152 = ( lexeme_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
Chris@16 153 | real_p
Chris@16 154 | lexeme_d[confix_p('"', *c_escape_ch_p, '"')]
Chris@16 155 | comment_nest_p('<', '>')
Chris@16 156 )[ID.name = construct_<std::string>(arg1,arg2)]
Chris@16 157 ;
Chris@16 158
Chris@16 159 a_list
Chris@16 160 = list_p( ID[(a_list.key = arg1),
Chris@16 161 (a_list.value = "true")
Chris@16 162 ]
Chris@16 163 >> !( ch_p('=')
Chris@16 164 >> ID[a_list.value = arg1])
Chris@16 165 [phoenix::bind(&definition::call_prop_actor)
Chris@16 166 (var(*this),a_list.key,a_list.value)],!ch_p(','));
Chris@16 167
Chris@16 168 attr_list = +(ch_p('[') >> !a_list >> ch_p(']'));
Chris@16 169
Chris@16 170 // RG - disregard port id's for now.
Chris@16 171 port_location
Chris@16 172 = (ch_p(':') >> ID)
Chris@16 173 | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID >> ch_p(')'))
Chris@16 174 ;
Chris@16 175
Chris@16 176 port_angle = ch_p('@') >> ID;
Chris@16 177
Chris@16 178 port
Chris@16 179 = port_location >> (!port_angle)
Chris@16 180 | port_angle >> (!port_location);
Chris@16 181
Chris@16 182
Chris@16 183 node_id
Chris@16 184 = ( ID[node_id.name = arg1] >> (!port) )
Chris@16 185 [phoenix::bind(&definition::memoize_node)(var(*this))];
Chris@16 186
Chris@16 187 graph_stmt
Chris@16 188 = (ID[graph_stmt.key = arg1] >>
Chris@16 189 ch_p('=') >>
Chris@16 190 ID[graph_stmt.value = arg1])
Chris@16 191 [phoenix::bind(&definition::call_graph_prop)
Chris@16 192 (var(*this),graph_stmt.key,graph_stmt.value)]
Chris@16 193 ; // Graph property.
Chris@16 194
Chris@16 195 attr_stmt
Chris@16 196 = (as_lower_d[keyword_p("graph")]
Chris@16 197 >> attr_list(actor_t(phoenix::bind(&definition::default_graph_prop)
Chris@16 198 (var(*this),arg1,arg2))))
Chris@16 199 | (as_lower_d[keyword_p("node")]
Chris@16 200 >> attr_list(actor_t(phoenix::bind(&definition::default_node_prop)
Chris@16 201 (var(*this),arg1,arg2))))
Chris@16 202 | (as_lower_d[keyword_p("edge")]
Chris@16 203 >> attr_list(actor_t(phoenix::bind(&definition::default_edge_prop)
Chris@16 204 (var(*this),arg1,arg2))))
Chris@16 205 ;
Chris@16 206
Chris@16 207 // edge_head is set depending on the graph type (directed/undirected)
Chris@16 208 edgeop = ch_p('-') >> ch_p(boost::ref(edge_head));
Chris@16 209
Chris@16 210 edgeRHS
Chris@16 211 = +( edgeop[(data_stmt.sources = data_stmt.dests),
Chris@16 212 (data_stmt.dests = construct_<nodes_t>())]
Chris@16 213 >> ( subgraph[data_stmt.dests = arg1]
Chris@16 214 | node_id[phoenix::bind(&definition::insert_node)
Chris@16 215 (var(*this),data_stmt.dests,arg1)]
Chris@16 216 )
Chris@16 217 [phoenix::bind(&definition::activate_edge)
Chris@16 218 (var(*this),data_stmt.sources,data_stmt.dests,
Chris@16 219 var(edges), var(default_edge_props))]
Chris@16 220 );
Chris@16 221
Chris@16 222
Chris@16 223 // To avoid backtracking, edge, node, and subgraph statements are
Chris@16 224 // processed as one nonterminal.
Chris@16 225 data_stmt
Chris@16 226 = ( subgraph[(data_stmt.dests = arg1),// will get moved in rhs
Chris@16 227 (data_stmt.saw_node = false)]
Chris@16 228 | node_id[(phoenix::bind(&definition::insert_node)
Chris@16 229 (var(*this),data_stmt.dests,arg1)),
Chris@16 230 (data_stmt.saw_node = true),
Chris@16 231 #ifdef BOOST_GRAPH_DEBUG
Chris@16 232 (std::cout << val("AcTive Node: ") << arg1 << "\n"),
Chris@16 233 #endif // BOOST_GRAPH_DEBUG
Chris@16 234 (data_stmt.active_node = arg1)]
Chris@16 235 ) >> if_p(edgeRHS)[
Chris@16 236 !attr_list(
Chris@16 237 actor_t(phoenix::bind(&definition::edge_prop)
Chris@16 238 (var(*this),arg1,arg2)))
Chris@16 239 ].else_p[
Chris@16 240 if_p(data_stmt.saw_node)[
Chris@16 241 !attr_list(
Chris@16 242 actor_t(phoenix::bind(&definition::node_prop)
Chris@16 243 (var(*this),arg1,arg2)))
Chris@16 244 ] // otherwise it's a subgraph, nothing more to do.
Chris@16 245 ];
Chris@16 246
Chris@16 247
Chris@16 248 stmt
Chris@16 249 = graph_stmt
Chris@16 250 | attr_stmt
Chris@16 251 | data_stmt
Chris@16 252 ;
Chris@16 253
Chris@16 254 stmt_list = *( stmt >> !ch_p(';') );
Chris@16 255
Chris@16 256 subgraph
Chris@16 257 = !( as_lower_d[keyword_p("subgraph")]
Chris@16 258 >> (!ID[(subgraph.name = arg1),
Chris@16 259 (subgraph.nodes = (var(subgraph_nodes))[arg1]),
Chris@16 260 (subgraph.edges = (var(subgraph_edges))[arg1])])
Chris@16 261 )
Chris@16 262 >> ch_p('{')[++var(subgraph_depth)]
Chris@16 263 >> stmt_list
Chris@16 264 >> ch_p('}')[--var(subgraph_depth)]
Chris@16 265 [(var(subgraph_nodes))[subgraph.name] = subgraph.nodes]
Chris@16 266 [(var(subgraph_edges))[subgraph.name] = subgraph.edges]
Chris@16 267
Chris@16 268 | as_lower_d[keyword_p("subgraph")]
Chris@16 269 >> ID[(subgraph.nodes = (var(subgraph_nodes))[arg1]),
Chris@16 270 (subgraph.edges = (var(subgraph_edges))[arg1])]
Chris@16 271 ;
Chris@16 272
Chris@16 273 the_grammar
Chris@16 274 = (!as_lower_d[keyword_p("strict")])
Chris@16 275 >> ( as_lower_d[keyword_p("graph")][
Chris@16 276 (var(edge_head) = '-'),
Chris@16 277 (phoenix::bind(&definition::check_undirected)(var(*this)))]
Chris@16 278 | as_lower_d[keyword_p("digraph")][
Chris@16 279 (var(edge_head) = '>'),
Chris@16 280 (phoenix::bind(&definition::check_directed)(var(*this)))]
Chris@16 281 )
Chris@16 282 >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}');
Chris@16 283
Chris@16 284 } // definition()
Chris@16 285
Chris@16 286 typedef boost::spirit::classic::rule<ScannerT> rule_t;
Chris@16 287
Chris@16 288 rule_t const& start() const { return the_grammar; }
Chris@16 289
Chris@16 290
Chris@16 291 //
Chris@16 292 // Semantic actions
Chris@16 293 //
Chris@16 294
Chris@16 295 void check_undirected() {
Chris@16 296 if(self.graph_.is_directed())
Chris@16 297 boost::throw_exception(boost::undirected_graph_error());
Chris@16 298 }
Chris@16 299
Chris@16 300 void check_directed() {
Chris@16 301 if(!self.graph_.is_directed())
Chris@16 302 boost::throw_exception(boost::directed_graph_error());
Chris@16 303 }
Chris@16 304
Chris@16 305 void memoize_node() {
Chris@16 306 id_t const& node = node_id.name();
Chris@16 307 props_t& node_props = default_node_props;
Chris@16 308
Chris@16 309 if(nodes.find(node) == nodes.end()) {
Chris@16 310 nodes.insert(node);
Chris@16 311 self.graph_.do_add_vertex(node);
Chris@16 312
Chris@16 313 node_map.insert(std::make_pair(node,ids_t()));
Chris@16 314
Chris@16 315 #ifdef BOOST_GRAPH_DEBUG
Chris@16 316 std::cout << "Add new node " << node << std::endl;
Chris@16 317 #endif // BOOST_GRAPH_DEBUG
Chris@16 318 // Set the default properties for this edge
Chris@16 319 // RG: Here I would actually set the properties
Chris@16 320 for(props_t::iterator i = node_props.begin();
Chris@16 321 i != node_props.end(); ++i) {
Chris@16 322 set_node_property(node,i->first,i->second);
Chris@16 323 }
Chris@16 324 if(subgraph_depth > 0) {
Chris@16 325 subgraph.nodes().insert(node);
Chris@16 326 // Set the subgraph's default properties as well
Chris@16 327 props_t& props = subgraph_node_props[subgraph.name()];
Chris@16 328 for(props_t::iterator i = props.begin(); i != props.end(); ++i) {
Chris@16 329 set_node_property(node,i->first,i->second);
Chris@16 330 }
Chris@16 331 }
Chris@16 332 } else {
Chris@16 333 #ifdef BOOST_GRAPH_DEBUG
Chris@16 334 std::cout << "See node " << node << std::endl;
Chris@16 335 #endif // BOOST_GRAPH_DEBUG
Chris@16 336 }
Chris@16 337 }
Chris@16 338
Chris@16 339 void activate_edge(nodes_t& sources, nodes_t& dests, edges_t& edges,
Chris@16 340 props_t& edge_props) {
Chris@16 341 edge_stack_t& edge_stack = data_stmt.edge_stack();
Chris@16 342 for(nodes_t::iterator i = sources.begin(); i != sources.end(); ++i) {
Chris@16 343 for(nodes_t::iterator j = dests.begin(); j != dests.end(); ++j) {
Chris@16 344 // Create the edge and push onto the edge stack.
Chris@16 345 #ifdef BOOST_GRAPH_DEBUG
Chris@16 346 std::cout << "Edge " << *i << " to " << *j << std::endl;
Chris@16 347 #endif // BOOST_GRAPH_DEBUG
Chris@16 348
Chris@16 349 edge_t edge = edge_t::new_edge();
Chris@16 350 edge_stack.push_back(edge);
Chris@16 351 edges.insert(edge);
Chris@16 352 edge_map.insert(std::make_pair(edge,ids_t()));
Chris@16 353
Chris@16 354 // Add the real edge.
Chris@16 355 self.graph_.do_add_edge(edge, *i, *j);
Chris@16 356
Chris@16 357 // Set the default properties for this edge
Chris@16 358 for(props_t::iterator k = edge_props.begin();
Chris@16 359 k != edge_props.end(); ++k) {
Chris@16 360 set_edge_property(edge,k->first,k->second);
Chris@16 361 }
Chris@16 362 if(subgraph_depth > 0) {
Chris@16 363 subgraph.edges().insert(edge);
Chris@16 364 // Set the subgraph's default properties as well
Chris@16 365 props_t& props = subgraph_edge_props[subgraph.name()];
Chris@16 366 for(props_t::iterator k = props.begin(); k != props.end(); ++k) {
Chris@16 367 set_edge_property(edge,k->first,k->second);
Chris@16 368 }
Chris@16 369 }
Chris@16 370 }
Chris@16 371 }
Chris@16 372 }
Chris@16 373
Chris@16 374 // node_prop - Assign the property for the current active node.
Chris@16 375 void node_prop(id_t const& key, id_t const& value) {
Chris@16 376 node_t& active_object = data_stmt.active_node();
Chris@16 377 set_node_property(active_object, key, value);
Chris@16 378 }
Chris@16 379
Chris@16 380 // edge_prop - Assign the property for the current active edges.
Chris@16 381 void edge_prop(id_t const& key, id_t const& value) {
Chris@16 382 edge_stack_t const& active_edges_ = data_stmt.edge_stack();
Chris@16 383 for (edge_stack_t::const_iterator i = active_edges_.begin();
Chris@16 384 i != active_edges_.end(); ++i) {
Chris@16 385 set_edge_property(*i,key,value);
Chris@16 386 }
Chris@16 387 }
Chris@16 388
Chris@16 389 // default_graph_prop - Store as a graph property.
Chris@16 390 void default_graph_prop(id_t const& key, id_t const& value) {
Chris@16 391 #ifdef BOOST_GRAPH_DEBUG
Chris@16 392 std::cout << key << " = " << value << std::endl;
Chris@16 393 #endif // BOOST_GRAPH_DEBUG
Chris@16 394 self.graph_.set_graph_property(key, value);
Chris@16 395 }
Chris@16 396
Chris@16 397 // default_node_prop - declare default properties for any future new nodes
Chris@16 398 void default_node_prop(id_t const& key, id_t const& value) {
Chris@16 399 nodes_t& nodes_ =
Chris@16 400 subgraph_depth == 0 ? nodes : subgraph.nodes();
Chris@16 401 props_t& node_props_ =
Chris@16 402 subgraph_depth == 0 ?
Chris@16 403 default_node_props :
Chris@16 404 subgraph_node_props[subgraph.name()];
Chris@16 405
Chris@16 406 // add this to the selected list of default node properties.
Chris@16 407 node_props_[key] = value;
Chris@16 408 // for each node, set its property to default-constructed value
Chris@16 409 // if it hasn't been set already.
Chris@16 410 // set the dynamic property map value
Chris@16 411 for(nodes_t::iterator i = nodes_.begin(); i != nodes_.end(); ++i)
Chris@16 412 if(node_map[*i].find(key) == node_map[*i].end()) {
Chris@16 413 set_node_property(*i,key,id_t());
Chris@16 414 }
Chris@16 415 }
Chris@16 416
Chris@16 417 // default_edge_prop - declare default properties for any future new edges
Chris@16 418 void default_edge_prop(id_t const& key, id_t const& value) {
Chris@16 419 edges_t& edges_ =
Chris@16 420 subgraph_depth == 0 ? edges : subgraph.edges();
Chris@16 421 props_t& edge_props_ =
Chris@16 422 subgraph_depth == 0 ?
Chris@16 423 default_edge_props :
Chris@16 424 subgraph_edge_props[subgraph.name()];
Chris@16 425
Chris@16 426 // add this to the list of default edge properties.
Chris@16 427 edge_props_[key] = value;
Chris@16 428 // for each edge, set its property to be empty string
Chris@16 429 // set the dynamic property map value
Chris@16 430 for(edges_t::iterator i = edges_.begin(); i != edges_.end(); ++i)
Chris@16 431 if(edge_map[*i].find(key) == edge_map[*i].end())
Chris@16 432 set_edge_property(*i,key,id_t());
Chris@16 433 }
Chris@16 434
Chris@16 435 // helper function
Chris@16 436 void insert_node(nodes_t& nodes, id_t const& name) {
Chris@16 437 nodes.insert(name);
Chris@16 438 }
Chris@16 439
Chris@16 440 void call_prop_actor(std::string const& lhs, std::string const& rhs) {
Chris@16 441 actor_t& actor = attr_list.prop_actor();
Chris@16 442 // If first and last characters of the rhs are double-quotes,
Chris@16 443 // remove them.
Chris@16 444 if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"')
Chris@16 445 actor(lhs, rhs.substr(1, rhs.size()-2));
Chris@16 446 else
Chris@16 447 actor(lhs,rhs);
Chris@16 448 }
Chris@16 449
Chris@16 450 void call_graph_prop(std::string const& lhs, std::string const& rhs) {
Chris@16 451 // If first and last characters of the rhs are double-quotes,
Chris@16 452 // remove them.
Chris@16 453 if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"')
Chris@16 454 this->default_graph_prop(lhs, rhs.substr(1, rhs.size()-2));
Chris@16 455 else
Chris@16 456 this->default_graph_prop(lhs,rhs);
Chris@16 457 }
Chris@16 458
Chris@16 459 void set_node_property(node_t const& node, id_t const& key,
Chris@16 460 id_t const& value) {
Chris@16 461
Chris@16 462 // Add the property key to the "set" table to avoid default overwrite
Chris@16 463 node_map[node].insert(key);
Chris@16 464 // Set the user's property map
Chris@16 465 self.graph_.set_node_property(key, node, value);
Chris@16 466 #ifdef BOOST_GRAPH_DEBUG
Chris@16 467 // Tell the world
Chris@16 468 std::cout << node << ": " << key << " = " << value << std::endl;
Chris@16 469 #endif // BOOST_GRAPH_DEBUG
Chris@16 470 }
Chris@16 471
Chris@16 472 void set_edge_property(edge_t const& edge, id_t const& key,
Chris@16 473 id_t const& value) {
Chris@16 474
Chris@16 475 // Add the property key to the "set" table to avoid default overwrite
Chris@16 476 edge_map[edge].insert(key);
Chris@16 477 // Set the user's property map
Chris@16 478 self.graph_.set_edge_property(key, edge, value);
Chris@16 479 #ifdef BOOST_GRAPH_DEBUG
Chris@16 480 // Tell the world
Chris@16 481 #if 0 // RG - edge representation changed,
Chris@16 482 std::cout << "(" << edge.first << "," << edge.second << "): "
Chris@16 483 #else
Chris@16 484 std::cout << "an edge: "
Chris@16 485 #endif // 0
Chris@16 486 << key << " = " << value << std::endl;
Chris@16 487 #endif // BOOST_GRAPH_DEBUG
Chris@16 488 }
Chris@16 489
Chris@16 490 // Variables explicitly initialized
Chris@16 491 dot_grammar const& self;
Chris@16 492 // if subgraph_depth > 0, then we're processing a subgraph.
Chris@16 493 int subgraph_depth;
Chris@16 494
Chris@16 495 // Keywords;
Chris@16 496 const boost::spirit::classic::distinct_parser<> keyword_p;
Chris@16 497 //
Chris@16 498 // rules that make up the grammar
Chris@16 499 //
Chris@16 500 boost::spirit::classic::rule<ScannerT,id_closure::context_t> ID;
Chris@16 501 boost::spirit::classic::rule<ScannerT,property_closure::context_t> a_list;
Chris@16 502 boost::spirit::classic::rule<ScannerT,attr_list_closure::context_t> attr_list;
Chris@16 503 rule_t port_location;
Chris@16 504 rule_t port_angle;
Chris@16 505 rule_t port;
Chris@16 506 boost::spirit::classic::rule<ScannerT,node_id_closure::context_t> node_id;
Chris@16 507 boost::spirit::classic::rule<ScannerT,property_closure::context_t> graph_stmt;
Chris@16 508 rule_t attr_stmt;
Chris@16 509 boost::spirit::classic::rule<ScannerT,data_stmt_closure::context_t> data_stmt;
Chris@16 510 boost::spirit::classic::rule<ScannerT,subgraph_closure::context_t> subgraph;
Chris@16 511 rule_t edgeop;
Chris@16 512 rule_t edgeRHS;
Chris@16 513 rule_t stmt;
Chris@16 514 rule_t stmt_list;
Chris@16 515 rule_t the_grammar;
Chris@16 516
Chris@16 517
Chris@16 518 // The grammar uses edge_head to dynamically set the syntax for edges
Chris@16 519 // directed graphs: edge_head = '>', and so edgeop = "->"
Chris@16 520 // undirected graphs: edge_head = '-', and so edgeop = "--"
Chris@16 521 char edge_head;
Chris@16 522
Chris@16 523
Chris@16 524 //
Chris@16 525 // Support data structures
Chris@16 526 //
Chris@16 527
Chris@16 528 nodes_t nodes; // list of node names seen
Chris@16 529 edges_t edges; // list of edges seen
Chris@16 530 node_map_t node_map; // remember the properties set for each node
Chris@16 531 edge_map_t edge_map; // remember the properties set for each edge
Chris@16 532
Chris@16 533 subgraph_nodes_t subgraph_nodes; // per-subgraph lists of nodes
Chris@16 534 subgraph_edges_t subgraph_edges; // per-subgraph lists of edges
Chris@16 535
Chris@16 536 props_t default_node_props; // global default node properties
Chris@16 537 props_t default_edge_props; // global default edge properties
Chris@16 538 subgraph_props_t subgraph_node_props; // per-subgraph default node properties
Chris@16 539 subgraph_props_t subgraph_edge_props; // per-subgraph default edge properties
Chris@16 540 }; // struct definition
Chris@16 541 }; // struct dot_grammar
Chris@16 542
Chris@16 543
Chris@16 544
Chris@16 545 //
Chris@16 546 // dot_skipper - GraphViz whitespace and comment skipper
Chris@16 547 //
Chris@16 548 struct dot_skipper : public boost::spirit::classic::grammar<dot_skipper>
Chris@16 549 {
Chris@16 550 dot_skipper() {}
Chris@16 551
Chris@16 552 template <typename ScannerT>
Chris@16 553 struct definition
Chris@16 554 {
Chris@16 555 definition(dot_skipper const& /*self*/) {
Chris@16 556 using namespace boost::spirit::classic;
Chris@16 557 using namespace phoenix;
Chris@16 558 // comment forms
Chris@16 559 skip = eol_p >> comment_p("#")
Chris@16 560 | space_p
Chris@16 561 | comment_p("//")
Chris@16 562 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
Chris@16 563 | confix_p(str_p("/*") ,*anychar_p, str_p("*/"))
Chris@16 564 #else
Chris@16 565 | confix_p("/*" ,*anychar_p, "*/")
Chris@16 566 #endif
Chris@16 567 ;
Chris@16 568
Chris@16 569 #ifdef BOOST_SPIRIT_DEBUG
Chris@16 570 BOOST_SPIRIT_DEBUG_RULE(skip);
Chris@16 571 #endif
Chris@16 572 }
Chris@16 573
Chris@16 574 boost::spirit::classic::rule<ScannerT> skip;
Chris@16 575 boost::spirit::classic::rule<ScannerT> const&
Chris@16 576 start() const { return skip; }
Chris@16 577 }; // definition
Chris@16 578 }; // dot_skipper
Chris@16 579
Chris@16 580 } // namespace graph
Chris@16 581 } // namespace detail
Chris@16 582
Chris@16 583 template <typename MultiPassIterator, typename MutableGraph>
Chris@16 584 bool read_graphviz_spirit(MultiPassIterator begin, MultiPassIterator end,
Chris@16 585 MutableGraph& graph, dynamic_properties& dp,
Chris@16 586 std::string const& node_id = "node_id") {
Chris@16 587 using namespace boost;
Chris@16 588 using namespace boost::spirit::classic;
Chris@16 589
Chris@16 590 typedef MultiPassIterator iterator_t;
Chris@16 591 typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper>
Chris@16 592 iter_policy_t;
Chris@16 593 typedef scanner_policies<iter_policy_t> scanner_policies_t;
Chris@16 594 typedef scanner<iterator_t, scanner_policies_t> scanner_t;
Chris@16 595
Chris@16 596 ::boost::detail::graph::mutate_graph_impl<MutableGraph>
Chris@16 597 m_graph(graph, dp, node_id);
Chris@16 598
Chris@16 599 ::boost::detail::graph::dot_grammar p(m_graph);
Chris@16 600 ::boost::detail::graph::dot_skipper skip_p;
Chris@16 601
Chris@16 602 iter_policy_t iter_policy(skip_p);
Chris@16 603 scanner_policies_t policies(iter_policy);
Chris@16 604
Chris@16 605 scanner_t scan(begin, end, policies);
Chris@16 606
Chris@16 607 bool ok = p.parse(scan);
Chris@16 608 m_graph.finish_building_graph();
Chris@16 609 return ok;
Chris@16 610 }
Chris@16 611
Chris@16 612 } // namespace boost
Chris@16 613
Chris@16 614 #endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP