⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 read_graphviz_spirit.hpp

📁 C++的一个好库。。。现在很流行
💻 HPP
📖 第 1 页 / 共 2 页
字号:
// Copyright 2004-5 Trustees of Indiana University

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//
// read_graphviz_spirit.hpp - 
//   Initialize a model of the BGL's MutableGraph concept and an associated
//  collection of property maps using a graph expressed in the GraphViz
// DOT Language.  
//
//   Based on the grammar found at:
//   http://www.graphviz.org/cvs/doc/info/lang.html
//
//   See documentation for this code at: 
//     http://www.boost.org/libs/graph/doc/read-graphviz.html
//

// Author: Ronald Garcia
//

#ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
#define BOOST_READ_GRAPHVIZ_SPIRIT_HPP

// Phoenix/Spirit set these limits to 3, but I need more.
#define PHOENIX_LIMIT 6
#define BOOST_SPIRIT_CLOSURE_LIMIT 6


#include <boost/spirit/iterator/multi_pass.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/utility/distinct.hpp>
#include <boost/spirit/utility/lists.hpp>
#include <boost/spirit/utility/escape_char.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/dynamic.hpp>
#include <boost/spirit/actor.hpp>
#include <boost/spirit/phoenix.hpp>
#include <boost/spirit/phoenix/binders.hpp>
#include <boost/ref.hpp>
#include <boost/function/function2.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/dynamic_property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/workaround.hpp>
#include <algorithm>
#include <exception> // for std::exception
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <map>
#include <boost/graph/graphviz.hpp>

namespace phoenix {
// Workaround:  std::map::operator[] uses a different return type than all
// other standard containers.  Phoenix doesn't account for that.
template <typename TK, typename T0, typename T1>
struct binary_operator<index_op, std::map<TK,T0>, T1>
{
    typedef typename std::map<TK,T0>::mapped_type& result_type;
    static result_type eval(std::map<TK,T0>& container, T1 const& index)
    { return container[index]; }
};
} // namespace phoenix

namespace boost {
namespace detail {
namespace graph {

using namespace std;
using namespace boost;
using namespace boost::spirit;
using namespace phoenix;

/////////////////////////////////////////////////////////////////////////////
// Application-specific type definitions
/////////////////////////////////////////////////////////////////////////////

typedef std::set<edge_t> edges_t;
typedef std::set<node_t> nodes_t;
typedef std::set<id_t> ids_t;
typedef std::map<edge_t,ids_t> edge_map_t;
typedef std::map<node_t,ids_t> node_map_t;
typedef std::map<id_t,id_t> props_t;
typedef std::map<id_t,props_t> subgraph_props_t;
typedef boost::function2<void, id_t const&, id_t const&> actor_t;
typedef std::vector<edge_t> edge_stack_t;
typedef std::map<id_t,nodes_t> subgraph_nodes_t;
typedef std::map<id_t,edges_t> subgraph_edges_t;



/////////////////////////////////////////////////////////////////////////////
// Stack frames used by semantic actions
/////////////////////////////////////////////////////////////////////////////
struct id_closure : boost::spirit::closure<id_closure, node_t> {
  member1 name;
};


struct node_id_closure : boost::spirit::closure<node_id_closure, node_t> {
  member1 name;
};

struct attr_list_closure : boost::spirit::closure<attr_list_closure, actor_t> {
  member1 prop_actor;
};

struct property_closure : boost::spirit::closure<property_closure, id_t, id_t> {
  member1 key;
  member2 value;
};

struct data_stmt_closure : boost::spirit::closure<data_stmt_closure,
                           nodes_t,nodes_t,edge_stack_t,bool,node_t> {
  member1 sources;
  member2 dests;
  member3 edge_stack;
  member4 saw_node;
  member5 active_node;
};

struct subgraph_closure : boost::spirit::closure<subgraph_closure,
                          nodes_t, edges_t, node_t> {
  member1 nodes;
  member2 edges;
  member3 name;
};

/////////////////////////////////////////////////////////////////////////////
// Grammar and Actions for the DOT Language
/////////////////////////////////////////////////////////////////////////////

// Grammar for a dot file.
struct dot_grammar : public grammar<dot_grammar> { 
  mutate_graph& graph_;
  explicit dot_grammar(mutate_graph& graph) : graph_(graph) { }

  template <class ScannerT>
  struct definition {
    
    definition(dot_grammar const& self) : self(self), subgraph_depth(0),
    keyword_p("0-9a-zA-Z_") {

      
      // RG - Future Work
      // - Handle multi-line strings using \ line continuation
      // - Make keywords case insensitive

      ID 
          = ( lexeme_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
            | real_p
            | confix_p('"', *c_escape_ch_p, '"')
            | comment_nest_p('<', '>')
            )[ID.name = construct_<std::string>(arg1,arg2)]
          ; 

      a_list
          = list_p( ID[(a_list.key = arg1),
                       (a_list.value = "true")
                      ]
                    >> !( ch_p('=')
                          >> ID[a_list.value = arg1])
                          [phoenix::bind(&definition::call_prop_actor)
                          (var(*this),a_list.key,a_list.value)],ch_p(','));
      
      attr_list = +(ch_p('[') >> !a_list >> ch_p(']'));

      // RG - disregard port id's for now.
      port_location 
          = (ch_p(':') >> ID)
          | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID >> ch_p(')'))
          ;

      port_angle = ch_p('@') >> ID;

      port
          = port_location >> (!port_angle)
          | port_angle >> (!port_location);


      node_id
          = ( ID[node_id.name = arg1] >> (!port) )
             [phoenix::bind(&definition::memoize_node)(var(*this))];

      attr_stmt
          = (as_lower_d[keyword_p("graph")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_graph_prop)
                                     (var(*this),arg1,arg2))))
          | (as_lower_d[keyword_p("node")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_node_prop)
                                     (var(*this),arg1,arg2))))
          | (as_lower_d[keyword_p("edge")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_edge_prop)
                                     (var(*this),arg1,arg2))))
          ;

      // edge_head is set depending on the graph type (directed/undirected)
      edgeop = ch_p('-') >> ch_p(boost::ref(edge_head));

      edgeRHS
          =  +(    edgeop[(data_stmt.sources = data_stmt.dests),
                          (data_stmt.dests = construct_<nodes_t>())]
                   >> ( subgraph[data_stmt.dests = arg1]
                      | node_id[phoenix::bind(&definition::insert_node)
                                (var(*this),data_stmt.dests,arg1)]
                      )
                   [phoenix::bind(&definition::activate_edge)
                    (var(*this),data_stmt.sources,data_stmt.dests,
                     var(edges), var(default_edge_props))]
              );
      

      // To avoid backtracking, edge, node, and subgraph statements are
      // processed as one nonterminal.
      data_stmt
          = ( subgraph[(data_stmt.dests = arg1),// will get moved in rhs
                       (data_stmt.saw_node = false)] 
            | node_id[(phoenix::bind(&definition::insert_node)
                       (var(*this),data_stmt.dests,arg1)),
                      (data_stmt.saw_node = true),
#ifdef BOOST_GRAPH_DEBUG
                      (std::cout << val("AcTive Node: ") << arg1 << "\n"),
#endif // BOOST_GRAPH_DEBUG
                      (data_stmt.active_node = arg1)]
            ) >> if_p(edgeRHS)[
                     !attr_list(
                       actor_t(phoenix::bind(&definition::edge_prop)
                               (var(*this),arg1,arg2)))
                  ].else_p[
                     if_p(data_stmt.saw_node)[
                         !attr_list(
                           actor_t(phoenix::bind(&definition::node_prop)
                                   (var(*this),arg1,arg2)))
                     ] // otherwise it's a subgraph, nothing more to do.
                  ];


      stmt
          = (ID >> ch_p('=') >> ID) // Graph property -- ignore.
          | attr_stmt
          | data_stmt
          ;

      stmt_list = *( stmt >> !ch_p(';') );

      subgraph
          = !(  as_lower_d[keyword_p("subgraph")]
                >> (!ID[(subgraph.name = arg1), 
                        (subgraph.nodes = (var(subgraph_nodes))[arg1]),
                        (subgraph.edges = (var(subgraph_edges))[arg1])])
                )
          >> ch_p('{')[++var(subgraph_depth)]
          >> stmt_list 
          >> ch_p('}')[--var(subgraph_depth)]
                      [(var(subgraph_nodes))[subgraph.name] = subgraph.nodes]
                      [(var(subgraph_edges))[subgraph.name] = subgraph.edges]
                     
          | as_lower_d[keyword_p("subgraph")]
                >> ID[(subgraph.nodes = (var(subgraph_nodes))[arg1]),
                      (subgraph.edges = (var(subgraph_edges))[arg1])]
          ;

      the_grammar
          = (!as_lower_d[keyword_p("strict")])
            >>  ( as_lower_d[keyword_p("graph")][
                   (var(edge_head) = '-'),
                   (phoenix::bind(&definition::check_undirected)(var(*this)))]
                | as_lower_d[keyword_p("digraph")][
                   (var(edge_head) = '>'),
                   (phoenix::bind(&definition::check_directed)(var(*this)))]
                )
            >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}');

    } // definition()

    typedef rule<ScannerT> rule_t;

    rule_t const& start() const { return the_grammar; }


    //  
    // Semantic actions
    //

    void check_undirected() {
      if(self.graph_.is_directed())
        throw boost::undirected_graph_error();
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -