/*============================================================================= Copyright (c) 2001-2003 Daniel Nuffer Copyright (c) 2001-2007 Hartmut Kaiser Revised 2007, Copyright (c) Tobias Schwinger http://spirit.sourceforge.net/ 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) =============================================================================*/ #ifndef BOOST_SPIRIT_TREE_COMMON_HPP #define BOOST_SPIRIT_TREE_COMMON_HPP #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) #include #else #include #endif #if defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) #include #endif #include #include #include #include #include // for boost::detail::iterator_traits #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) #include #include #endif #include namespace boost { namespace spirit { template void swap(tree_node& a, tree_node& b); template void swap(node_iter_data& a, node_iter_data& b); namespace impl { template inline void cp_swap(T& t1, T& t2); } template struct tree_node { typedef T parse_node_t; #if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) typedef std::allocator > allocator_type; #elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) typedef boost::pool_allocator > allocator_type; #else typedef boost::fast_pool_allocator > allocator_type; #endif #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) typedef std::vector, allocator_type> children_t; #else typedef std::list, allocator_type> children_t; #endif // BOOST_SPIRIT_USE_LIST_FOR_TREES typedef typename children_t::iterator tree_iterator; typedef typename children_t::const_iterator const_tree_iterator; T value; children_t children; tree_node() : value() , children() {} explicit tree_node(T const& v) : value(v) , children() {} tree_node(T const& v, children_t const& c) : value(v) , children(c) {} void swap(tree_node& x) { impl::cp_swap(value, x.value); impl::cp_swap(children, x.children); } // Intel V5.0.1 has a problem without this explicit operator= tree_node &operator= (tree_node const &rhs) { tree_node(rhs).swap(*this); return *this; } }; #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) template inline std::ostream& operator<<(std::ostream& o, tree_node const& n) { static int depth = 0; o << "\n"; for (int i = 0; i <= depth; ++i) { o << "\t"; } o << "(depth = " << depth++ << " value = " << n.value; int c = 0; for (typename tree_node::children_t::const_iterator it = n.children.begin(); it != n.children.end(); ++it) { o << " children[" << c++ << "] = " << *it; } o << ")"; --depth; return o; } #endif ////////////////////////////////// template struct node_iter_data { typedef IteratorT iterator_t; typedef IteratorT /*const*/ const_iterator_t; node_iter_data() : first(), last(), is_root_(false), parser_id_(), value_() {} node_iter_data(IteratorT const& _first, IteratorT const& _last) : first(_first), last(_last), is_root_(false), parser_id_(), value_() {} void swap(node_iter_data& x) { impl::cp_swap(first, x.first); impl::cp_swap(last, x.last); impl::cp_swap(parser_id_, x.parser_id_); impl::cp_swap(is_root_, x.is_root_); impl::cp_swap(value_, x.value_); } IteratorT begin() { return first; } IteratorT const& begin() const { return first; } IteratorT end() { return last; } IteratorT const& end() const { return last; } bool is_root() const { return is_root_; } void is_root(bool b) { is_root_ = b; } parser_id id() const { return parser_id_; } void id(parser_id r) { parser_id_ = r; } ValueT const& value() const { return value_; } void value(ValueT const& v) { value_ = v; } private: IteratorT first, last; bool is_root_; parser_id parser_id_; ValueT value_; public: }; #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) // value is default nil_t, so provide an operator<< for nil_t inline std::ostream& operator<<(std::ostream& o, nil_t const&) { return o; } template inline std::ostream& operator<<(std::ostream& o, node_iter_data const& n) { o << "(id = " << n.id() << " text = \""; typedef typename node_iter_data::const_iterator_t iterator_t; for (iterator_t it = n.begin(); it != n.end(); ++it) impl::token_printer(o, *it); o << "\" is_root = " << n.is_root() << /*" value = " << n.value() << */")"; return o; } #endif ////////////////////////////////// template struct node_val_data { typedef typename boost::detail::iterator_traits::value_type value_type; #if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) typedef std::allocator allocator_type; #elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) typedef boost::pool_allocator allocator_type; #else typedef boost::fast_pool_allocator allocator_type; #endif #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) typedef std::vector container_t; #else typedef std::list container_t; #endif typedef typename container_t::iterator iterator_t; typedef typename container_t::const_iterator const_iterator_t; node_val_data() : text(), is_root_(false), parser_id_(), value_() {} #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) node_val_data(IteratorT const& _first, IteratorT const& _last) : text(), is_root_(false), parser_id_(), value_() { std::copy(_first, _last, std::inserter(text, text.end())); } // This constructor is for building text out of iterators template node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) : text(), is_root_(false), parser_id_(), value_() { std::copy(_first, _last, std::inserter(text, text.end())); } #else node_val_data(IteratorT const& _first, IteratorT const& _last) : text(_first, _last), is_root_(false), parser_id_(), value_() {} // This constructor is for building text out of iterators template node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) : text(_first, _last), is_root_(false), parser_id_(), value_() {} #endif void swap(node_val_data& x) { impl::cp_swap(text, x.text); impl::cp_swap(is_root_, x.is_root_); impl::cp_swap(parser_id_, x.parser_id_); impl::cp_swap(value_, x.value_); } typename container_t::iterator begin() { return text.begin(); } typename container_t::const_iterator begin() const { return text.begin(); } typename container_t::iterator end() { return text.end(); } typename container_t::const_iterator end() const { return text.end(); } bool is_root() const { return is_root_; } void is_root(bool b) { is_root_ = b; } parser_id id() const { return parser_id_; } void id(parser_id r) { parser_id_ = r; } ValueT const& value() const { return value_; } void value(ValueT const& v) { value_ = v; } private: container_t text; bool is_root_; parser_id parser_id_; ValueT value_; }; #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) template inline std::ostream& operator<<(std::ostream& o, node_val_data const& n) { o << "(id = " << n.id() << " text = \""; typedef typename node_val_data::const_iterator_t iterator_t; for (iterator_t it = n.begin(); it != n.end(); ++it) impl::token_printer(o, *it); o << "\" is_root = " << n.is_root() << " value = " << n.value() << ")"; return o; } #endif template inline void swap(tree_node& a, tree_node& b) { a.swap(b); } template inline void swap(node_iter_data& a, node_iter_data& b) { a.swap(b); } ////////////////////////////////// template class node_iter_data_factory { public: // This inner class is so that node_iter_data_factory can simulate // a template template parameter template class factory { public: typedef IteratorT iterator_t; typedef node_iter_data node_t; static node_t create_node(iterator_t const& first, iterator_t const& last, bool /*is_leaf_node*/) { return node_t(first, last); } static node_t empty_node() { return node_t(); } // precondition: ContainerT contains a tree_node. And all // iterators in the container point to the same sequence. template static node_t group_nodes(ContainerT const& nodes) { return node_t(nodes.begin()->value.begin(), nodes.back().value.end()); } }; }; ////////////////////////////////// template class node_val_data_factory { public: // This inner class is so that node_val_data_factory can simulate // a template template parameter template class factory { public: typedef IteratorT iterator_t; typedef node_val_data node_t; static node_t create_node(iterator_t const& first, iterator_t const& last, bool is_leaf_node) { if (is_leaf_node) return node_t(first, last); else return node_t(); } static node_t empty_node() { return node_t(); } template static node_t group_nodes(ContainerT const& nodes) { typename node_t::container_t c; typename ContainerT::const_iterator i_end = nodes.end(); // copy all the nodes text into a new one for (typename ContainerT::const_iterator i = nodes.begin(); i != i_end; ++i) { // See docs: reduced_node_d cannot be used with a // rule inside the []. assert(i->children.size() == 0); c.insert(c.end(), i->value.begin(), i->value.end()); } return node_t(c.begin(), c.end()); } }; }; ////////////////////////////////// template class node_all_val_data_factory { public: // This inner class is so that node_all_val_data_factory can simulate // a template template parameter template class factory { public: typedef IteratorT iterator_t; typedef node_val_data node_t; static node_t create_node(iterator_t const& first, iterator_t const& last, bool /*is_leaf_node*/) { return node_t(first, last); } static node_t empty_node() { return node_t(); } template static node_t group_nodes(ContainerT const& nodes) { typename node_t::container_t c; typename ContainerT::const_iterator i_end = nodes.end(); // copy all the nodes text into a new one for (typename ContainerT::const_iterator i = nodes.begin(); i != i_end; ++i) { assert(i->children.size() == 0); c.insert(c.end(), i->value.begin(), i->value.end()); } return node_t(c.begin(), c.end()); } }; }; namespace impl { /////////////////////////////////////////////////////////////////////////// // can't call unqualified swap from within classname::swap // as Koenig lookup rules will find only the classname::swap // member function not the global declaration, so use cp_swap // as a forwarding function (JM): #if __GNUC__ == 2 using ::std::swap; #endif template inline void cp_swap(T& t1, T& t2) { using std::swap; using boost::spirit::swap; using boost::swap; swap(t1, t2); } } ////////////////////////////////// template class tree_match : public match { public: typedef typename NodeFactoryT::template factory node_factory_t; typedef typename node_factory_t::node_t parse_node_t; typedef tree_node node_t; typedef typename node_t::children_t container_t; typedef typename container_t::iterator tree_iterator; typedef typename container_t::const_iterator const_tree_iterator; typedef T attr_t; typedef typename boost::call_traits::param_type param_type; typedef typename boost::call_traits::reference reference; typedef typename boost::call_traits::const_reference const_reference; tree_match() : match(), trees() {} explicit tree_match(std::size_t length) : match(length), trees() {} tree_match(std::size_t length, parse_node_t const& n) : match(length), trees() { trees.push_back(node_t(n)); } tree_match(std::size_t length, param_type val, parse_node_t const& n) : match(length, val), trees() { #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) trees.reserve(10); // this is more or less an arbitrary number... #endif trees.push_back(node_t(n)); } // attention, these constructors will change the second parameter! tree_match(std::size_t length, container_t& c) : match(length), trees() { impl::cp_swap(trees, c); } tree_match(std::size_t length, param_type val, container_t& c) : match(length, val), trees() { impl::cp_swap(trees, c); } template tree_match(match const& other) : match(other), trees() {} template tree_match(tree_match const& other) : match(other), trees() { impl::cp_swap(trees, other.trees); } template tree_match& operator=(match const& other) { match::operator=(other); return *this; } template tree_match& operator=(tree_match const& other) { match::operator=(other); impl::cp_swap(trees, other.trees); return *this; } tree_match(tree_match const& x) : match(x), trees() { // use auto_ptr like ownership for the trees data member impl::cp_swap(trees, x.trees); } tree_match& operator=(tree_match const& x) { tree_match tmp(x); this->swap(tmp); return *this; } void swap(tree_match& x) { match::swap(x); impl::cp_swap(trees, x.trees); } mutable container_t trees; }; #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) template inline std::ostream& operator<<(std::ostream& o, tree_match const& m) { typedef typename tree_match::container_t::iterator iterator; o << "(length = " << (int)m.length(); int c = 0; for (iterator i = m.trees.begin(); i != m.trees.end(); ++i) { o << " trees[" << c++ << "] = " << *i; } o << "\n)"; return o; } #endif ////////////////////////////////// struct tree_policy { template static void apply_op_to_match(FunctorT const& /*op*/, MatchT& /*m*/) {} template static void group_match(MatchT& /*m*/, parser_id const& /*id*/, Iterator1T const& /*first*/, Iterator2T const& /*last*/) {} template static void concat(MatchT& /*a*/, MatchT const& /*b*/) {} }; ////////////////////////////////// template < typename MatchPolicyT, typename IteratorT, typename NodeFactoryT, typename TreePolicyT, typename T > struct common_tree_match_policy : public match_policy { common_tree_match_policy() { } template common_tree_match_policy(PolicyT const & policies) : match_policy((match_policy const &)policies) { } template struct result { typedef tree_match type; }; typedef tree_match match_t; typedef IteratorT iterator_t; typedef TreePolicyT tree_policy_t; typedef NodeFactoryT factory_t; static const match_t no_match() { return match_t(); } static const match_t empty_match() { return match_t(0, tree_policy_t::empty_node()); } template static tree_match create_match( std::size_t length, AttrT const& val, Iterator1T const& first, Iterator2T const& last) { #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) BOOST_SPIRIT_DEBUG_OUT << "\n>>> create_node(begin) <<<\n" "creating node text: \""; for (Iterator1T it = first; it != last; ++it) impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); BOOST_SPIRIT_DEBUG_OUT << "\"\n"; BOOST_SPIRIT_DEBUG_OUT << ">>> create_node(end) <<<\n\n"; #endif return tree_match(length, val, tree_policy_t::create_node(length, first, last, true)); } template static void concat_match(Match1T& a, Match2T const& b) { #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) BOOST_SPIRIT_DEBUG_OUT << "\n>>> concat_match(begin) <<<\n"; BOOST_SPIRIT_DEBUG_OUT << "tree a:\n" << a << "\n"; BOOST_SPIRIT_DEBUG_OUT << "tree b:\n" << b << "\n"; BOOST_SPIRIT_DEBUG_OUT << ">>> concat_match(end) <<<\n\n"; #endif BOOST_SPIRIT_ASSERT(a && b); if (a.length() == 0) { a = b; return; } else if (b.length() == 0 #ifdef BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING && !b.trees.begin()->value.id().to_long() #endif ) { return; } a.concat(b); tree_policy_t::concat(a, b); } template void group_match( MatchT& m, parser_id const& id, IteratorT2 const& first, IteratorT2 const& last) const { if (!m) return; #if defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_TREES) BOOST_SPIRIT_DEBUG_OUT << "\n>>> group_match(begin) <<<\n" "new node(" << id << ") \""; for (IteratorT2 it = first; it != last; ++it) impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); BOOST_SPIRIT_DEBUG_OUT << "\"\n"; BOOST_SPIRIT_DEBUG_OUT << "new child tree (before grouping):\n" << m << "\n"; tree_policy_t::group_match(m, id, first, last); BOOST_SPIRIT_DEBUG_OUT << "new child tree (after grouping):\n" << m << "\n"; BOOST_SPIRIT_DEBUG_OUT << ">>> group_match(end) <<<\n\n"; #else tree_policy_t::group_match(m, id, first, last); #endif } }; ////////////////////////////////// template struct common_tree_tree_policy { typedef typename MatchPolicyT::iterator_t iterator_t; typedef typename MatchPolicyT::match_t match_t; typedef typename NodeFactoryT::template factory factory_t; typedef typename factory_t::node_t node_t; template static node_t create_node(std::size_t /*length*/, Iterator1T const& first, Iterator2T const& last, bool leaf_node) { return factory_t::create_node(first, last, leaf_node); } static node_t empty_node() { return factory_t::empty_node(); } template static void apply_op_to_match(FunctorT const& op, match_t& m) { op(m); } }; ////////////////////////////////// // directives to modify how the parse tree is generated struct no_tree_gen_node_parser_gen; template struct no_tree_gen_node_parser : public unary > > { typedef no_tree_gen_node_parser self_t; typedef no_tree_gen_node_parser_gen parser_generator_t; typedef unary_parser_category parser_category_t; no_tree_gen_node_parser(T const& a) : unary > >(a) {} template typename parser_result::type parse(ScannerT const& scanner) const { typedef typename ScannerT::iteration_policy_t iteration_policy_t; typedef match_policy match_policy_t; typedef typename ScannerT::action_policy_t action_policy_t; typedef scanner_policies< iteration_policy_t, match_policy_t, action_policy_t > policies_t; return this->subject().parse(scanner.change_policies(policies_t(scanner))); } }; struct no_tree_gen_node_parser_gen { template struct result { typedef no_tree_gen_node_parser type; }; template static no_tree_gen_node_parser generate(parser const& s) { return no_tree_gen_node_parser(s.derived()); } template no_tree_gen_node_parser operator[](parser const& s) const { return no_tree_gen_node_parser(s.derived()); } }; const no_tree_gen_node_parser_gen no_node_d = no_tree_gen_node_parser_gen(); ////////////////////////////////// struct leaf_node_parser_gen; template struct leaf_node_parser : public unary > > { typedef leaf_node_parser self_t; typedef leaf_node_parser_gen parser_generator_t; typedef unary_parser_category parser_category_t; leaf_node_parser(T const& a) : unary > >(a) {} template typename parser_result::type parse(ScannerT const& scanner) const { typedef scanner_policies< typename ScannerT::iteration_policy_t, match_policy, typename ScannerT::action_policy_t > policies_t; typedef typename ScannerT::iterator_t iterator_t; typedef typename parser_result::type result_t; typedef typename result_t::node_factory_t factory_t; iterator_t from = scanner.first; result_t hit = impl::contiguous_parser_parse(this->subject(), scanner.change_policies(policies_t(scanner,match_policy(),scanner)), scanner); if (hit) return result_t(hit.length(), factory_t::create_node(from, scanner.first, true)); else return result_t(hit.length()); } }; struct leaf_node_parser_gen { template struct result { typedef leaf_node_parser type; }; template static leaf_node_parser generate(parser const& s) { return leaf_node_parser(s.derived()); } template leaf_node_parser operator[](parser const& s) const { return leaf_node_parser(s.derived()); } }; const leaf_node_parser_gen leaf_node_d = leaf_node_parser_gen(); const leaf_node_parser_gen token_node_d = leaf_node_parser_gen(); ////////////////////////////////// namespace impl { template struct tree_policy_selector { typedef tree_policy type; }; } // namespace impl ////////////////////////////////// template struct node_parser_gen; template struct node_parser : public unary > > { typedef node_parser self_t; typedef node_parser_gen parser_generator_t; typedef unary_parser_category parser_category_t; node_parser(T const& a) : unary > >(a) {} template struct result { typedef typename parser_result::type type; }; template typename parser_result::type parse(ScannerT const& scanner) const { typename parser_result::type hit = this->subject().parse(scanner); if (hit) { impl::tree_policy_selector::type::apply_op_to_match(NodeParserT(), hit); } return hit; } }; template struct node_parser_gen { template struct result { typedef node_parser type; }; template static node_parser generate(parser const& s) { return node_parser(s.derived()); } template node_parser operator[](parser const& s) const { return node_parser(s.derived()); } }; ////////////////////////////////// struct reduced_node_op { template void operator()(MatchT& m) const { if (m.trees.size() == 1) { m.trees.begin()->children.clear(); } else if (m.trees.size() > 1) { typedef typename MatchT::node_factory_t node_factory_t; m = MatchT(m.length(), node_factory_t::group_nodes(m.trees)); } } }; const node_parser_gen reduced_node_d = node_parser_gen(); struct discard_node_op { template void operator()(MatchT& m) const { m.trees.clear(); } }; const node_parser_gen discard_node_d = node_parser_gen(); struct infix_node_op { template void operator()(MatchT& m) const { typedef typename MatchT::container_t container_t; typedef typename MatchT::container_t::iterator iter_t; typedef typename MatchT::container_t::value_type value_t; using std::swap; using boost::swap; using boost::spirit::swap; // copying the tree nodes is expensive, since it may copy a whole // tree. swapping them is cheap, so swap the nodes we want into // a new container of children. container_t new_children; std::size_t length = 0; std::size_t tree_size = m.trees.size(); // the infix_node_d[] make no sense for nodes with no subnodes BOOST_SPIRIT_ASSERT(tree_size >= 1); bool keep = true; #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) new_children.reserve((tree_size+1)/2); #endif iter_t i_end = m.trees.end(); for (iter_t i = m.trees.begin(); i != i_end; ++i) { if (keep) { // adjust the length length += std::distance((*i).value.begin(), (*i).value.end()); // move the child node new_children.push_back(value_t()); swap(new_children.back(), *i); keep = false; } else { // ignore this child node keep = true; } } m = MatchT(length, new_children); } }; const node_parser_gen infix_node_d = node_parser_gen(); struct discard_first_node_op { template void operator()(MatchT& m) const { typedef typename MatchT::container_t container_t; typedef typename MatchT::container_t::iterator iter_t; typedef typename MatchT::container_t::value_type value_t; using std::swap; using boost::swap; using boost::spirit::swap; // copying the tree nodes is expensive, since it may copy a whole // tree. swapping them is cheap, so swap the nodes we want into // a new container of children, instead of saying // m.trees.erase(m.trees.begin()) because, on a container_t that will // cause all the nodes afterwards to be copied into the previous // position. container_t new_children; std::size_t length = 0; std::size_t tree_size = m.trees.size(); // the discard_first_node_d[] make no sense for nodes with no subnodes BOOST_SPIRIT_ASSERT(tree_size >= 1); if (tree_size > 1) { #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) new_children.reserve(tree_size - 1); #endif iter_t i = m.trees.begin(), i_end = m.trees.end(); for (++i; i != i_end; ++i) { // adjust the length length += std::distance((*i).value.begin(), (*i).value.end()); // move the child node new_children.push_back(value_t()); swap(new_children.back(), *i); } } else { // if there was a tree and now there isn't any, insert an empty node iter_t i = m.trees.begin(); // This isn't entirely correct, since the empty node will reference // the end of the discarded node, but I currently don't see any way to // get at the begin of the node following this subnode. // This should be safe anyway because the it shouldn't get dereferenced // under any circumstances. typedef typename value_t::parse_node_t::iterator_t iterator_type; iterator_type it = (*i).value.end(); new_children.push_back( value_t(typename value_t::parse_node_t(it, it))); } m = MatchT(length, new_children); } }; const node_parser_gen discard_first_node_d = node_parser_gen(); struct discard_last_node_op { template void operator()(MatchT& m) const { typedef typename MatchT::container_t container_t; typedef typename MatchT::container_t::iterator iter_t; typedef typename MatchT::container_t::value_type value_t; using std::swap; using boost::swap; using boost::spirit::swap; // copying the tree nodes is expensive, since it may copy a whole // tree. swapping them is cheap, so swap the nodes we want into // a new container of children, instead of saying // m.trees.erase(m.trees.begin()) because, on a container_t that will // cause all the nodes afterwards to be copied into the previous // position. container_t new_children; std::size_t length = 0; std::size_t tree_size = m.trees.size(); // the discard_last_node_d[] make no sense for nodes with no subnodes BOOST_SPIRIT_ASSERT(tree_size >= 1); if (tree_size > 1) { m.trees.pop_back(); #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) new_children.reserve(tree_size - 1); #endif iter_t i_end = m.trees.end(); for (iter_t i = m.trees.begin(); i != i_end; ++i) { // adjust the length length += std::distance((*i).value.begin(), (*i).value.end()); // move the child node new_children.push_back(value_t()); swap(new_children.back(), *i); } } else { // if there was a tree and now there isn't any, insert an empty node iter_t i = m.trees.begin(); typedef typename value_t::parse_node_t::iterator_t iterator_type; iterator_type it = (*i).value.begin(); new_children.push_back( value_t(typename value_t::parse_node_t(it, it))); } m = MatchT(length, new_children); } }; const node_parser_gen discard_last_node_d = node_parser_gen(); struct inner_node_op { template void operator()(MatchT& m) const { typedef typename MatchT::container_t container_t; typedef typename MatchT::container_t::iterator iter_t; typedef typename MatchT::container_t::value_type value_t; using std::swap; using boost::swap; using boost::spirit::swap; // copying the tree nodes is expensive, since it may copy a whole // tree. swapping them is cheap, so swap the nodes we want into // a new container of children, instead of saying // m.trees.erase(m.trees.begin()) because, on a container_t that will // cause all the nodes afterwards to be copied into the previous // position. container_t new_children; std::size_t length = 0; std::size_t tree_size = m.trees.size(); // the inner_node_d[] make no sense for nodes with less then 2 subnodes BOOST_SPIRIT_ASSERT(tree_size >= 2); if (tree_size > 2) { m.trees.pop_back(); // erase the last element #if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) new_children.reserve(tree_size - 1); #endif iter_t i = m.trees.begin(); // skip over the first element iter_t i_end = m.trees.end(); for (++i; i != i_end; ++i) { // adjust the length length += std::distance((*i).value.begin(), (*i).value.end()); // move the child node new_children.push_back(value_t()); swap(new_children.back(), *i); } } else { // if there was a tree and now there isn't any, insert an empty node iter_t i = m.trees.begin(); // skip over the first element typedef typename value_t::parse_node_t::iterator_t iterator_type; iterator_type it = (*++i).value.begin(); new_children.push_back( value_t(typename value_t::parse_node_t(it, it))); } m = MatchT(length, new_children); } }; const node_parser_gen inner_node_d = node_parser_gen(); ////////////////////////////////// // action_directive_parser and action_directive_parser_gen // are meant to be used as a template to create directives that // generate action classes. For example access_match and // access_node. The ActionParserT template parameter must be // a class that has an innter class called action that is templated // on the parser type and the action type. template struct action_directive_parser_gen; template struct action_directive_parser : public unary > > { typedef action_directive_parser self_t; typedef action_directive_parser_gen parser_generator_t; typedef unary_parser_category parser_category_t; action_directive_parser(T const& a) : unary > >(a) {} template struct result { typedef typename parser_result::type type; }; template typename parser_result::type parse(ScannerT const& scanner) const { return this->subject().parse(scanner); } template typename ActionParserT::template action, ActionT> operator[](ActionT const& actor) const { typedef typename ActionParserT::template action action_t; return action_t(*this, actor); } }; ////////////////////////////////// template struct action_directive_parser_gen { template struct result { typedef action_directive_parser type; }; template static action_directive_parser generate(parser const& s) { return action_directive_parser(s.derived()); } template action_directive_parser operator[](parser const& s) const { return action_directive_parser(s.derived()); } }; ////////////////////////////////// // Calls the attached action passing it the match from the parser // and the first and last iterators. // The inner template class is used to simulate template-template parameters // (declared in common_fwd.hpp). template struct access_match_action::action : public unary > > { typedef action_parser_category parser_category; typedef action self_t; template struct result { typedef typename parser_result::type type; }; action( ParserT const& subject, ActionT const& actor_); template typename parser_result::type parse(ScannerT const& scanner) const; ActionT const &predicate() const; private: ActionT actor; }; ////////////////////////////////// template access_match_action::action::action( ParserT const& subject, ActionT const& actor_) : unary > >(subject) , actor(actor_) {} ////////////////////////////////// template template typename parser_result, ScannerT>::type access_match_action::action:: parse(ScannerT const& scan) const { typedef typename ScannerT::iterator_t iterator_t; typedef typename parser_result::type result_t; if (!scan.at_end()) { iterator_t save = scan.first; result_t hit = this->subject().parse(scan); actor(hit, save, scan.first); return hit; } return scan.no_match(); } ////////////////////////////////// template ActionT const &access_match_action::action::predicate() const { return actor; } ////////////////////////////////// const action_directive_parser_gen access_match_d = action_directive_parser_gen(); ////////////////////////////////// // Calls the attached action passing it the node from the parser // and the first and last iterators // The inner template class is used to simulate template-template parameters // (declared in common_fwd.hpp). template struct access_node_action::action : public unary > > { typedef action_parser_category parser_category; typedef action self_t; template struct result { typedef typename parser_result::type type; }; action( ParserT const& subject, ActionT const& actor_); template typename parser_result::type parse(ScannerT const& scanner) const; ActionT const &predicate() const; private: ActionT actor; }; ////////////////////////////////// template access_node_action::action::action( ParserT const& subject, ActionT const& actor_) : unary > >(subject) , actor(actor_) {} ////////////////////////////////// template template typename parser_result, ScannerT>::type access_node_action::action:: parse(ScannerT const& scan) const { typedef typename ScannerT::iterator_t iterator_t; typedef typename parser_result::type result_t; if (!scan.at_end()) { iterator_t save = scan.first; result_t hit = this->subject().parse(scan); if (hit && hit.trees.size() > 0) actor(*hit.trees.begin(), save, scan.first); return hit; } return scan.no_match(); } ////////////////////////////////// template ActionT const &access_node_action::action::predicate() const { return actor; } ////////////////////////////////// const action_directive_parser_gen access_node_d = action_directive_parser_gen(); ////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // tree_parse_info // // Results returned by the tree parse functions: // // stop: points to the final parse position (i.e parsing // processed the input up to this point). // // match: true if parsing is successful. This may be full: // the parser consumed all the input, or partial: // the parser consumed only a portion of the input. // // full: true when we have a full match (i.e the parser // consumed all the input. // // length: The number of characters consumed by the parser. // This is valid only if we have a successful match // (either partial or full). A negative value means // that the match is unsucessful. // // trees: Contains the root node(s) of the tree. // /////////////////////////////////////////////////////////////////////////////// template < typename IteratorT, typename NodeFactoryT, typename T > struct tree_parse_info { IteratorT stop; bool match; bool full; std::size_t length; typename tree_match::container_t trees; tree_parse_info() : stop() , match(false) , full(false) , length(0) , trees() {} template tree_parse_info(tree_parse_info const& pi) : stop(pi.stop) , match(pi.match) , full(pi.full) , length(pi.length) , trees() { using std::swap; using boost::swap; using boost::spirit::swap; // use auto_ptr like ownership for the trees data member swap(trees, pi.trees); } tree_parse_info( IteratorT stop_, bool match_, bool full_, std::size_t length_, typename tree_match::container_t trees_) : stop(stop_) , match(match_) , full(full_) , length(length_) , trees() { using std::swap; using boost::swap; using boost::spirit::swap; // use auto_ptr like ownership for the trees data member swap(trees, trees_); } }; }} // namespace boost::spirit #endif