#define BOOST_SPIRIT_DEBUG 1 #define PHOENIX_LIMIT 6 #define BOOST_SPIRIT_CLOSURE_LIMIT 6 #include #include #include #include #include #include #include #include #include using namespace boost; using namespace boost::spirit; //======== my data struture class Component { public: Component () : m_id (0) {} Component (const uint32_t id) : m_id (id) {} virtual ~Component(){} const uint32_t get_ID (void) const { return m_id; } virtual const std::string get_Name (void) const = 0; private: uint32_t m_id; }; class A : public Component { public: A (uint32_t id) : Component (id) {} ~A(){} virtual const std::string get_Name (void) const { return "A"; } }; class B : public Component { public: B (uint32_t id) : Component (id) {} ~B(){} virtual const std::string get_Name (void) const { return "B"; } }; class Component_Factory { private: static boost::shared_ptr m_factory; public: boost::shared_ptr get_A (uint32_t id) { return boost::shared_ptr ( new A(id)); } boost::shared_ptr get_B (uint32_t id) { return boost::shared_ptr ( new B(id)); } static boost::shared_ptr get_Factory () { if (m_factory.get() == 0) { m_factory.reset (new Component_Factory()); } return m_factory; } private: Component_Factory () {} }; boost::shared_ptr Component_Factory::m_factory; class Component_Graph { public: typedef property< vertex_index_t, uint32_t, property< vertex_name_t, boost::shared_ptr > > VertexProperty; typedef adjacency_list // VertexProperties Graph_Type; typedef graph_traits::vertex_descriptor Vertex; typedef graph_traits::edge_descriptor Edge; typedef std::map IdVertexMap; Component_Graph () {} void dump_Index () { std::cout << "Index:" << std::endl; for (IdVertexMap::iterator pos = m_index.begin(); pos != m_index.end(); ++pos) { std::cout << " id: " << pos->first << " pointer: " << (pos->second) << std::endl; } } void add_Source ( boost::shared_ptr obj_ptr ) { bool found; IdVertexMap::iterator pos; Vertex node; boost::tie (pos, found) = m_index.insert (std::make_pair(obj_ptr->get_ID(), node)); if (found) { // Insertion was successful // Make a new vertex and return handle to 'node' node = add_vertex(m_graph); // Get list of Components boost::property_map::type clist = get(vertex_name, m_graph); // Assign component to vertex position clist[node] = obj_ptr; // Add vertex handle to map position pos->second = node; } else { std::cerr << "ERROR: Duplicate source found. Skipping Component" << std::endl; return; } } void add_Component (uint32_t parent_id, boost::shared_ptr obj_ptr) { IdVertexMap::iterator pos; IdVertexMap::iterator cpos; Vertex child_node; bool cfound; pos = m_index.find (parent_id); if (pos != m_index.end()) { boost::tie (cpos, cfound) = m_index.insert (std::make_pair(obj_ptr->get_ID(), child_node)); if (cfound) { // Insertion was successful // Make a new vertex and return handle to 'node' child_node = add_vertex(m_graph); // Get list of Components boost::property_map::type clist = get(vertex_name,m_graph); // Assign component to vertex position clist[child_node] = obj_ptr; // Add vertex handle to map position cpos->second = child_node; } else { std::cerr << "ERROR: Duplicate child found. Skipping Component #" << obj_ptr->get_ID() << std::endl << obj_ptr->get_Name() << std::endl; return; } } else { std::cerr << "ERROR: Cannot find parent. Skipping adding component #" << obj_ptr->get_ID() << std::endl << obj_ptr->get_Name() << std::endl; return; } // Add edge from parent to child Edge link; if (! (add_edge ( pos->second, child_node, m_graph).second)) { std::cerr << "ERROR: Duplicate edge exists from " << parent_id << " to " << obj_ptr->get_ID() << std::endl; return; } } Graph_Type get_Graph () { return m_graph; } private: Graph_Type m_graph; IdVertexMap m_index; }; class Component_Writer { public: typedef boost::graph_traits::vertex_descriptor Vertex_Type; Component_Writer (const Component_Graph::Graph_Type& g) : g (g) {} void operator()(std::ostream& out, Vertex_Type& obj) const { boost::shared_ptr obj_ptr = get (vertex_name, g, obj); out << "[label=\"" << obj_ptr->get_Name() << "\n" << obj_ptr->get_ID() << "\"]"; } private: const Component_Graph::Graph_Type g; }; class Graph_Grammar : public grammar { public: Graph_Grammar (boost::shared_ptr data) : m_data (data) {} struct string_closure : closure { member1 text; }; struct source_closure : closure { member1 node_id; member2 name; }; struct node_closure : closure { member1 child_id; member2 name; member3 parent_id; }; static boost::shared_ptr get_Component (const uint32_t id, const std::string name, const uint32_t = 0) { boost::shared_ptr factory = Component_Factory::get_Factory(); boost::shared_ptr obj_ptr; if (name.compare("A") == 0) { obj_ptr = factory->get_A (id); } else if (name.compare("B") == 0) { obj_ptr = factory->get_B (id); } return obj_ptr; } struct construct_Component_ { template struct result { typedef void type; }; template void operator()(Data& data, const ID& id, const Name& name, const Parent_ID& pid) const { boost::shared_ptr obj_ptr = Graph_Grammar::get_Component (id,name,pid); data->add_Component ( pid, obj_ptr ); } }; phoenix::function construct_Component; struct construct_Source_ { template struct result { typedef void type; }; template void operator()(Data& data, const ID& id, const Name& name) const { boost::shared_ptr obj_ptr = Graph_Grammar::get_Component (id,name); data->add_Source ( obj_ptr ); } }; phoenix::function construct_Source; template struct definition { rule graph; rule source_node; rule node; rule name; definition(Graph_Grammar const& self) { graph = source_node >> while_p (~epsilon_p(end_p)) [ node ]; source_node = as_lower_d[str_p("source")] >> ch_p('{') >> uint_p [source_node.node_id = phoenix::arg1] >> ch_p(',') >> name [source_node.name = phoenix::arg1] >> str_p("};") [ self.construct_Source (self.m_data, source_node.node_id, source_node.name) ]; // Read this and add a semantic action to create a // File_Data_Source_Config object. Add to m_data. node = as_lower_d[str_p("node")] >> ch_p('{') >> uint_p [node.child_id = phoenix::arg1] >> ch_p(',') >> name [node.name = phoenix::arg1] >> ch_p (',') >> uint_p[node.parent_id = phoenix::arg1] >> str_p("};") [self.construct_Component (self.m_data, node.child_id, node.name, node.parent_id)]; name = ch_p('"') >> (alnum_p >> *(alnum_p | ch_p('_'))) [ name.text = phoenix::construct_(phoenix::arg1, phoenix::arg2) ] >> ch_p('"'); BOOST_SPIRIT_DEBUG_NODE(graph); BOOST_SPIRIT_DEBUG_NODE(source_node); BOOST_SPIRIT_DEBUG_NODE(node); BOOST_SPIRIT_DEBUG_NODE(name); } rule const& start() const { return graph; } }; mutable boost::shared_ptr m_data; }; template bool parse_i (const std::string & file, const Grammar& grammar) { boost::spirit::file_iterator<> first(file); if (!first) { std::cerr << "Configuration_Parser: Unable to open file '" << file << "'!" << std::endl; return false; } const boost::spirit::file_iterator<> last = first.make_end(); typedef typename boost::spirit::position_iterator < boost::spirit::file_iterator<> > iterator_t; const parse_info info = boost::spirit::parse(iterator_t(first, last, file), iterator_t(), grammar, boost::spirit::space_p | boost::spirit::comment_p("#")); if (!info.full) { const boost::spirit::file_position fp = info.stop.get_position(); std::cerr << "Parsing of file '" << fp.file << "' failed at line " << fp.line << ", column " << fp.column << ".\n"; } return info.full; } int main () { // read Graph2 and all internal properties boost::shared_ptr m_data (new Component_Graph()); Graph_Grammar grmr (m_data); std::ofstream file ("test.txt"); file << "source{0,\"A\"};" << std::endl; file << "node{1,\"B\",0};" << std::endl; file << "node{2,\"A\",0};" << std::endl; file << "node{3,\"A\",1};" << std::endl; file.close(); if (!parse_i("test.txt", grmr)) { std::cerr << "Invalid configuration file format." << std::endl; } std::ofstream gfile ("test.dot"); Component_Writer cw(m_data->get_Graph()) ; write_graphviz (gfile, m_data->get_Graph(), cw); return 0; }