File indexing completed on 2025-01-18 09:37:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
0024 #define BOOST_READ_GRAPHVIZ_SPIRIT_HPP
0025
0026
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
0061
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 }
0072
0073 namespace boost
0074 {
0075 namespace detail
0076 {
0077 namespace graph
0078 {
0079
0080
0081
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
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
0146
0147
0148
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
0165
0166
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
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)];
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
0213
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
0226
0227 data_stmt
0228 = (subgraph[(data_stmt.dests
0229 = arg1),
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
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)))]
0247
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 }
0284
0285 typedef boost::spirit::classic::rule< ScannerT > rule_t;
0286
0287 rule_t const& start() const { return the_grammar; }
0288
0289
0290
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
0320
0321
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
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
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
0359 #ifdef BOOST_GRAPH_DEBUG
0360 std::cout << "Edge " << *i << " to " << *j
0361 << std::endl;
0362 #endif
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
0370 self.graph_.do_add_edge(edge, *i, *j);
0371
0372
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
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
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
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
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
0419 self.graph_.set_graph_property(key, value);
0420 }
0421
0422
0423
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
0433 node_props_[key] = value;
0434
0435
0436
0437
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
0447
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
0457 edge_props_[key] = value;
0458
0459
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
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
0477
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
0489
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
0503
0504 node_map[node].insert(key);
0505
0506 self.graph_.set_node_property(key, node, value);
0507 #ifdef BOOST_GRAPH_DEBUG
0508
0509 std::cout << node << ": " << key << " = " << value
0510 << std::endl;
0511 #endif
0512 }
0513
0514 void set_edge_property(
0515 edge_t const& edge, id_t const& key, id_t const& value)
0516 {
0517
0518
0519
0520 edge_map[edge].insert(key);
0521
0522 self.graph_.set_edge_property(key, edge, value);
0523 #ifdef BOOST_GRAPH_DEBUG
0524
0525 #if 0
0526 std::cout << "(" << edge.first << "," << edge.second << "): "
0527 #else
0528 std::cout << "an edge: "
0529 #endif
0530 << key << " = " << value << std::endl;
0531 #endif
0532 }
0533
0534
0535 dot_grammar const& self;
0536
0537 int subgraph_depth;
0538
0539
0540 const boost::spirit::classic::distinct_parser<> keyword_p;
0541
0542
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
0575
0576
0577 char edge_head;
0578
0579
0580
0581
0582
0583 nodes_t nodes;
0584 edges_t edges;
0585 node_map_t
0586 node_map;
0587 edge_map_t
0588 edge_map;
0589
0590 subgraph_nodes_t subgraph_nodes;
0591 subgraph_edges_t subgraph_edges;
0592
0593 props_t default_node_props;
0594 props_t default_edge_props;
0595 subgraph_props_t
0596 subgraph_node_props;
0597 subgraph_props_t
0598 subgraph_edge_props;
0599 };
0600 };
0601
0602
0603
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& )
0613 {
0614 using namespace boost::spirit::classic;
0615 using namespace phoenix;
0616
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 };
0636 };
0637
0638 }
0639 }
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 }
0672
0673 #endif