You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
1588 lines
44 KiB
1588 lines
44 KiB
/*============================================================================= |
|
Copyright (c) 2001-2003 Daniel Nuffer |
|
Copyright (c) 2001-2007 Hartmut Kaiser |
|
Revised 2007, Copyright (c) Tobias Schwinger |
|
http://spirit.sourceforge.net/ |
|
|
|
Distributed under 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 <vector> |
|
#else |
|
#include <list> |
|
#endif |
|
|
|
#if defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) |
|
#include <boost/pool/pool_alloc.hpp> |
|
#endif |
|
|
|
#include <algorithm> |
|
|
|
#include <boost/ref.hpp> |
|
#include <boost/call_traits.hpp> |
|
#include <boost/spirit/home/classic/namespace.hpp> |
|
#include <boost/spirit/home/classic/core.hpp> |
|
#include <boost/detail/iterator.hpp> // for boost::detail::iterator_traits |
|
#include <boost/assert.hpp> |
|
|
|
#if defined(BOOST_SPIRIT_DEBUG) && \ |
|
(BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) |
|
#include <iostream> |
|
#include <boost/spirit/home/classic/debug/debug_node.hpp> |
|
#endif |
|
|
|
#include <boost/spirit/home/classic/tree/common_fwd.hpp> |
|
|
|
namespace boost { namespace spirit { |
|
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
|
|
|
template <typename T> |
|
void swap(tree_node<T>& a, tree_node<T>& b); |
|
|
|
template <typename T, typename V> |
|
void swap(node_iter_data<T, V>& a, node_iter_data<T, V>& b); |
|
|
|
namespace impl { |
|
template <typename T> |
|
inline void cp_swap(T& t1, T& t2); |
|
} |
|
|
|
template <typename T> |
|
struct tree_node |
|
{ |
|
typedef T parse_node_t; |
|
|
|
#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) |
|
typedef std::allocator<tree_node<T> > allocator_type; |
|
#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) |
|
typedef boost::pool_allocator<tree_node<T> > allocator_type; |
|
#else |
|
typedef boost::fast_pool_allocator<tree_node<T> > allocator_type; |
|
#endif |
|
|
|
#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) |
|
typedef std::vector<tree_node<T>, allocator_type> children_t; |
|
#else |
|
typedef std::list<tree_node<T>, 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<T>& 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 <typename T> |
|
inline std::ostream& |
|
operator<<(std::ostream& o, tree_node<T> 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<T>::children_t::const_iterator it = n.children.begin(); |
|
it != n.children.end(); ++it) |
|
{ |
|
o << " children[" << c++ << "] = " << *it; |
|
} |
|
o << ")"; |
|
--depth; |
|
return o; |
|
} |
|
#endif |
|
|
|
////////////////////////////////// |
|
template <typename IteratorT, typename ValueT> |
|
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 <typename IteratorT, typename ValueT> |
|
inline std::ostream& |
|
operator<<(std::ostream& o, node_iter_data<IteratorT, ValueT> const& n) |
|
{ |
|
o << "(id = " << n.id() << " text = \""; |
|
typedef typename node_iter_data<IteratorT, ValueT>::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 <typename IteratorT = char const*, typename ValueT = nil_t> |
|
struct node_val_data |
|
{ |
|
typedef |
|
typename boost::detail::iterator_traits<IteratorT>::value_type |
|
value_type; |
|
|
|
#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) |
|
typedef std::allocator<value_type> allocator_type; |
|
#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) |
|
typedef boost::pool_allocator<value_type> allocator_type; |
|
#else |
|
typedef boost::fast_pool_allocator<value_type> allocator_type; |
|
#endif |
|
|
|
#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) |
|
typedef std::vector<value_type, allocator_type> container_t; |
|
#else |
|
typedef std::list<value_type, allocator_type> 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 <typename IteratorT2> |
|
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 <typename IteratorT2> |
|
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 <typename IteratorT, typename ValueT> |
|
inline std::ostream& |
|
operator<<(std::ostream& o, node_val_data<IteratorT, ValueT> const& n) |
|
{ |
|
o << "(id = " << n.id() << " text = \""; |
|
typedef typename node_val_data<IteratorT, ValueT>::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 <typename T> |
|
inline void |
|
swap(tree_node<T>& a, tree_node<T>& b) |
|
{ |
|
a.swap(b); |
|
} |
|
|
|
template <typename T, typename V> |
|
inline void |
|
swap(node_iter_data<T, V>& a, node_iter_data<T, V>& b) |
|
{ |
|
a.swap(b); |
|
} |
|
|
|
////////////////////////////////// |
|
template <typename ValueT> |
|
class node_iter_data_factory |
|
{ |
|
public: |
|
// This inner class is so that node_iter_data_factory can simulate |
|
// a template template parameter |
|
template <typename IteratorT> |
|
class factory |
|
{ |
|
public: |
|
typedef IteratorT iterator_t; |
|
typedef node_iter_data<iterator_t, ValueT> 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<node_t>. And all |
|
// iterators in the container point to the same sequence. |
|
template <typename ContainerT> |
|
static node_t group_nodes(ContainerT const& nodes) |
|
{ |
|
return node_t(nodes.begin()->value.begin(), |
|
nodes.back().value.end()); |
|
} |
|
}; |
|
}; |
|
|
|
////////////////////////////////// |
|
template <typename ValueT> |
|
class node_val_data_factory |
|
{ |
|
public: |
|
// This inner class is so that node_val_data_factory can simulate |
|
// a template template parameter |
|
template <typename IteratorT> |
|
class factory |
|
{ |
|
public: |
|
typedef IteratorT iterator_t; |
|
typedef node_val_data<iterator_t, ValueT> 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 <typename ContainerT> |
|
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 []. |
|
BOOST_ASSERT(i->children.size() == 0); |
|
c.insert(c.end(), i->value.begin(), i->value.end()); |
|
} |
|
return node_t(c.begin(), c.end()); |
|
} |
|
}; |
|
}; |
|
|
|
////////////////////////////////// |
|
template <typename ValueT> |
|
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 <typename IteratorT> |
|
class factory |
|
{ |
|
public: |
|
typedef IteratorT iterator_t; |
|
typedef node_val_data<iterator_t, ValueT> 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 <typename ContainerT> |
|
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) |
|
{ |
|
BOOST_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 <typename T> |
|
inline void cp_swap(T& t1, T& t2) |
|
{ |
|
using std::swap; |
|
using BOOST_SPIRIT_CLASSIC_NS::swap; |
|
using boost::swap; |
|
swap(t1, t2); |
|
} |
|
} |
|
|
|
////////////////////////////////// |
|
template <typename IteratorT, typename NodeFactoryT, typename T> |
|
class tree_match : public match<T> |
|
{ |
|
public: |
|
|
|
typedef typename NodeFactoryT::template factory<IteratorT> node_factory_t; |
|
typedef typename node_factory_t::node_t parse_node_t; |
|
typedef tree_node<parse_node_t> 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<T>::param_type param_type; |
|
typedef typename boost::call_traits<T>::reference reference; |
|
typedef typename boost::call_traits<T>::const_reference const_reference; |
|
|
|
tree_match() |
|
: match<T>(), trees() |
|
{} |
|
|
|
explicit |
|
tree_match(std::size_t length_) |
|
: match<T>(length_), trees() |
|
{} |
|
|
|
tree_match(std::size_t length_, parse_node_t const& n) |
|
: match<T>(length_), trees() |
|
{ |
|
trees.push_back(node_t(n)); |
|
} |
|
|
|
tree_match(std::size_t length_, param_type val, parse_node_t const& n) |
|
: match<T>(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<T>(length_), trees() |
|
{ |
|
impl::cp_swap(trees, c); |
|
} |
|
|
|
tree_match(std::size_t length_, param_type val, container_t& c) |
|
: match<T>(length_, val), trees() |
|
{ |
|
impl::cp_swap(trees, c); |
|
} |
|
|
|
template <typename T2> |
|
tree_match(match<T2> const& other) |
|
: match<T>(other), trees() |
|
{} |
|
|
|
template <typename T2, typename T3, typename T4> |
|
tree_match(tree_match<T2, T3, T4> const& other) |
|
: match<T>(other), trees() |
|
{ impl::cp_swap(trees, other.trees); } |
|
|
|
template <typename T2> |
|
tree_match& |
|
operator=(match<T2> const& other) |
|
{ |
|
match<T>::operator=(other); |
|
return *this; |
|
} |
|
|
|
template <typename T2, typename T3, typename T4> |
|
tree_match& |
|
operator=(tree_match<T2, T3, T4> const& other) |
|
{ |
|
match<T>::operator=(other); |
|
impl::cp_swap(trees, other.trees); |
|
return *this; |
|
} |
|
|
|
tree_match(tree_match const& x) |
|
: match<T>(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<T>::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 <typename IteratorT, typename NodeFactoryT, typename T> |
|
inline std::ostream& |
|
operator<<(std::ostream& o, tree_match<IteratorT, NodeFactoryT, T> const& m) |
|
{ |
|
typedef |
|
typename tree_match<IteratorT, NodeFactoryT, T>::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 <typename FunctorT, typename MatchT> |
|
static void apply_op_to_match(FunctorT const& /*op*/, MatchT& /*m*/) |
|
{} |
|
|
|
template <typename MatchT, typename Iterator1T, typename Iterator2T> |
|
static void group_match(MatchT& /*m*/, parser_id const& /*id*/, |
|
Iterator1T const& /*first*/, Iterator2T const& /*last*/) |
|
{} |
|
|
|
template <typename MatchT> |
|
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 <typename PolicyT> |
|
common_tree_match_policy(PolicyT const & policies) |
|
: match_policy((match_policy const &)policies) |
|
{ |
|
} |
|
|
|
template <typename U> |
|
struct result { typedef tree_match<IteratorT, NodeFactoryT, U> type; }; |
|
|
|
typedef tree_match<IteratorT, NodeFactoryT, T> 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 <typename AttrT, typename Iterator1T, typename Iterator2T> |
|
static tree_match<IteratorT, NodeFactoryT, AttrT> 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<IteratorT, NodeFactoryT, AttrT>(length, val, |
|
tree_policy_t::create_node(length, first, last, true)); |
|
} |
|
|
|
template <typename Match1T, typename Match2T> |
|
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 <typename MatchT, typename IteratorT2> |
|
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 <typename MatchPolicyT, typename NodeFactoryT> |
|
struct common_tree_tree_policy |
|
{ |
|
typedef typename MatchPolicyT::iterator_t iterator_t; |
|
typedef typename MatchPolicyT::match_t match_t; |
|
typedef typename NodeFactoryT::template factory<iterator_t> factory_t; |
|
typedef typename factory_t::node_t node_t; |
|
|
|
template <typename Iterator1T, typename Iterator2T> |
|
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 <typename FunctorT> |
|
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 <typename T> |
|
struct no_tree_gen_node_parser |
|
: public unary<T, parser<no_tree_gen_node_parser<T> > > |
|
{ |
|
typedef no_tree_gen_node_parser<T> 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<T, parser<no_tree_gen_node_parser<T> > >(a) {} |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::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 <typename T> |
|
struct result { |
|
|
|
typedef no_tree_gen_node_parser<T> type; |
|
}; |
|
|
|
template <typename T> |
|
static no_tree_gen_node_parser<T> |
|
generate(parser<T> const& s) |
|
{ |
|
return no_tree_gen_node_parser<T>(s.derived()); |
|
} |
|
|
|
template <typename T> |
|
no_tree_gen_node_parser<T> |
|
operator[](parser<T> const& s) const |
|
{ |
|
return no_tree_gen_node_parser<T>(s.derived()); |
|
} |
|
}; |
|
|
|
const no_tree_gen_node_parser_gen no_node_d = no_tree_gen_node_parser_gen(); |
|
|
|
////////////////////////////////// |
|
|
|
struct leaf_node_parser_gen; |
|
|
|
template<typename T> |
|
struct leaf_node_parser |
|
: public unary<T, parser<leaf_node_parser<T> > > |
|
{ |
|
typedef leaf_node_parser<T> self_t; |
|
typedef leaf_node_parser_gen parser_generator_t; |
|
typedef unary_parser_category parser_category_t; |
|
|
|
leaf_node_parser(T const& a) |
|
: unary<T, parser<leaf_node_parser<T> > >(a) {} |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::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<self_t, ScannerT>::type result_t; |
|
typedef typename result_t::node_factory_t factory_t; |
|
|
|
iterator_t from = scanner.first; |
|
result_t hit = impl::contiguous_parser_parse<result_t>(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 <typename T> |
|
struct result { |
|
|
|
typedef leaf_node_parser<T> type; |
|
}; |
|
|
|
template <typename T> |
|
static leaf_node_parser<T> |
|
generate(parser<T> const& s) |
|
{ |
|
return leaf_node_parser<T>(s.derived()); |
|
} |
|
|
|
template <typename T> |
|
leaf_node_parser<T> |
|
operator[](parser<T> const& s) const |
|
{ |
|
return leaf_node_parser<T>(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 <typename MatchPolicyT> |
|
struct tree_policy_selector |
|
{ |
|
typedef tree_policy type; |
|
}; |
|
|
|
} // namespace impl |
|
|
|
////////////////////////////////// |
|
template <typename NodeParserT> |
|
struct node_parser_gen; |
|
|
|
template <typename T, typename NodeParserT> |
|
struct node_parser |
|
: public unary<T, parser<node_parser<T, NodeParserT> > > |
|
{ |
|
typedef node_parser<T, NodeParserT> self_t; |
|
typedef node_parser_gen<NodeParserT> parser_generator_t; |
|
typedef unary_parser_category parser_category_t; |
|
|
|
node_parser(T const& a) |
|
: unary<T, parser<node_parser<T, NodeParserT> > >(a) {} |
|
|
|
template <typename ScannerT> |
|
struct result |
|
{ |
|
typedef typename parser_result<T, ScannerT>::type type; |
|
}; |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::type |
|
parse(ScannerT const& scanner) const |
|
{ |
|
typename parser_result<self_t, ScannerT>::type hit = this->subject().parse(scanner); |
|
if (hit) |
|
{ |
|
impl::tree_policy_selector<typename ScannerT::match_policy_t>::type::apply_op_to_match(NodeParserT(), hit); |
|
} |
|
return hit; |
|
} |
|
}; |
|
|
|
template <typename NodeParserT> |
|
struct node_parser_gen |
|
{ |
|
template <typename T> |
|
struct result { |
|
|
|
typedef node_parser<T, NodeParserT> type; |
|
}; |
|
|
|
template <typename T> |
|
static node_parser<T, NodeParserT> |
|
generate(parser<T> const& s) |
|
{ |
|
return node_parser<T, NodeParserT>(s.derived()); |
|
} |
|
|
|
template <typename T> |
|
node_parser<T, NodeParserT> |
|
operator[](parser<T> const& s) const |
|
{ |
|
return node_parser<T, NodeParserT>(s.derived()); |
|
} |
|
}; |
|
////////////////////////////////// |
|
struct reduced_node_op |
|
{ |
|
template <typename MatchT> |
|
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_op> reduced_node_d = |
|
node_parser_gen<reduced_node_op>(); |
|
|
|
|
|
struct discard_node_op |
|
{ |
|
template <typename MatchT> |
|
void operator()(MatchT& m) const |
|
{ |
|
m.trees.clear(); |
|
} |
|
}; |
|
|
|
const node_parser_gen<discard_node_op> discard_node_d = |
|
node_parser_gen<discard_node_op>(); |
|
|
|
struct infix_node_op |
|
{ |
|
template <typename MatchT> |
|
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_CLASSIC_NS::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_op> infix_node_d = |
|
node_parser_gen<infix_node_op>(); |
|
|
|
struct discard_first_node_op |
|
{ |
|
template <typename MatchT> |
|
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_CLASSIC_NS::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_op> discard_first_node_d = |
|
node_parser_gen<discard_first_node_op>(); |
|
|
|
struct discard_last_node_op |
|
{ |
|
template <typename MatchT> |
|
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_CLASSIC_NS::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_op> discard_last_node_d = |
|
node_parser_gen<discard_last_node_op>(); |
|
|
|
struct inner_node_op |
|
{ |
|
template <typename MatchT> |
|
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_CLASSIC_NS::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_op> inner_node_d = |
|
node_parser_gen<inner_node_op>(); |
|
|
|
|
|
////////////////////////////////// |
|
// 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 <typename ActionParserT> |
|
struct action_directive_parser_gen; |
|
|
|
template <typename T, typename ActionParserT> |
|
struct action_directive_parser |
|
: public unary<T, parser<action_directive_parser<T, ActionParserT> > > |
|
{ |
|
typedef action_directive_parser<T, ActionParserT> self_t; |
|
typedef action_directive_parser_gen<ActionParserT> parser_generator_t; |
|
typedef unary_parser_category parser_category_t; |
|
|
|
action_directive_parser(T const& a) |
|
: unary<T, parser<action_directive_parser<T, ActionParserT> > >(a) {} |
|
|
|
template <typename ScannerT> |
|
struct result |
|
{ |
|
typedef typename parser_result<T, ScannerT>::type type; |
|
}; |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::type |
|
parse(ScannerT const& scanner) const |
|
{ |
|
return this->subject().parse(scanner); |
|
} |
|
|
|
template <typename ActionT> |
|
typename ActionParserT::template action<action_directive_parser<T, ActionParserT>, ActionT> |
|
operator[](ActionT const& actor) const |
|
{ |
|
typedef typename |
|
ActionParserT::template action<action_directive_parser, ActionT> |
|
action_t; |
|
return action_t(*this, actor); |
|
} |
|
}; |
|
|
|
////////////////////////////////// |
|
template <typename ActionParserT> |
|
struct action_directive_parser_gen |
|
{ |
|
template <typename T> |
|
struct result { |
|
|
|
typedef action_directive_parser<T, ActionParserT> type; |
|
}; |
|
|
|
template <typename T> |
|
static action_directive_parser<T, ActionParserT> |
|
generate(parser<T> const& s) |
|
{ |
|
return action_directive_parser<T, ActionParserT>(s.derived()); |
|
} |
|
|
|
template <typename T> |
|
action_directive_parser<T, ActionParserT> |
|
operator[](parser<T> const& s) const |
|
{ |
|
return action_directive_parser<T, ActionParserT>(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 <typename ParserT, typename ActionT> |
|
struct access_match_action::action |
|
: public unary<ParserT, parser<access_match_action::action<ParserT, ActionT> > > |
|
{ |
|
typedef action_parser_category parser_category; |
|
typedef action<ParserT, ActionT> self_t; |
|
|
|
template <typename ScannerT> |
|
struct result |
|
{ |
|
typedef typename parser_result<ParserT, ScannerT>::type type; |
|
}; |
|
|
|
action( ParserT const& subject, |
|
ActionT const& actor_); |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::type |
|
parse(ScannerT const& scanner) const; |
|
|
|
ActionT const &predicate() const; |
|
|
|
private: |
|
ActionT actor; |
|
}; |
|
|
|
////////////////////////////////// |
|
template <typename ParserT, typename ActionT> |
|
access_match_action::action<ParserT, ActionT>::action( |
|
ParserT const& subject, |
|
ActionT const& actor_) |
|
: unary<ParserT, parser<access_match_action::action<ParserT, ActionT> > >(subject) |
|
, actor(actor_) |
|
{} |
|
|
|
////////////////////////////////// |
|
template <typename ParserT, typename ActionT> |
|
template <typename ScannerT> |
|
typename parser_result<access_match_action::action<ParserT, ActionT>, ScannerT>::type |
|
access_match_action::action<ParserT, ActionT>:: |
|
parse(ScannerT const& scan) const |
|
{ |
|
typedef typename ScannerT::iterator_t iterator_t; |
|
typedef typename parser_result<self_t, ScannerT>::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 <typename ParserT, typename ActionT> |
|
ActionT const &access_match_action::action<ParserT, ActionT>::predicate() const |
|
{ |
|
return actor; |
|
} |
|
|
|
////////////////////////////////// |
|
const action_directive_parser_gen<access_match_action> access_match_d |
|
= action_directive_parser_gen<access_match_action>(); |
|
|
|
|
|
|
|
////////////////////////////////// |
|
// 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 <typename ParserT, typename ActionT> |
|
struct access_node_action::action |
|
: public unary<ParserT, parser<access_node_action::action<ParserT, ActionT> > > |
|
{ |
|
typedef action_parser_category parser_category; |
|
typedef action<ParserT, ActionT> self_t; |
|
|
|
template <typename ScannerT> |
|
struct result |
|
{ |
|
typedef typename parser_result<ParserT, ScannerT>::type type; |
|
}; |
|
|
|
action( ParserT const& subject, |
|
ActionT const& actor_); |
|
|
|
template <typename ScannerT> |
|
typename parser_result<self_t, ScannerT>::type |
|
parse(ScannerT const& scanner) const; |
|
|
|
ActionT const &predicate() const; |
|
|
|
private: |
|
ActionT actor; |
|
}; |
|
|
|
////////////////////////////////// |
|
template <typename ParserT, typename ActionT> |
|
access_node_action::action<ParserT, ActionT>::action( |
|
ParserT const& subject, |
|
ActionT const& actor_) |
|
: unary<ParserT, parser<access_node_action::action<ParserT, ActionT> > >(subject) |
|
, actor(actor_) |
|
{} |
|
|
|
////////////////////////////////// |
|
template <typename ParserT, typename ActionT> |
|
template <typename ScannerT> |
|
typename parser_result<access_node_action::action<ParserT, ActionT>, ScannerT>::type |
|
access_node_action::action<ParserT, ActionT>:: |
|
parse(ScannerT const& scan) const |
|
{ |
|
typedef typename ScannerT::iterator_t iterator_t; |
|
typedef typename parser_result<self_t, ScannerT>::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 <typename ParserT, typename ActionT> |
|
ActionT const &access_node_action::action<ParserT, ActionT>::predicate() const |
|
{ |
|
return actor; |
|
} |
|
|
|
////////////////////////////////// |
|
const action_directive_parser_gen<access_node_action> access_node_d |
|
= action_directive_parser_gen<access_node_action>(); |
|
|
|
|
|
|
|
////////////////////////////////// |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// 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<IteratorT, NodeFactoryT, T>::container_t trees; |
|
|
|
tree_parse_info() |
|
: stop() |
|
, match(false) |
|
, full(false) |
|
, length(0) |
|
, trees() |
|
{} |
|
|
|
template <typename IteratorT2> |
|
tree_parse_info(tree_parse_info<IteratorT2> const& pi) |
|
: stop(pi.stop) |
|
, match(pi.match) |
|
, full(pi.full) |
|
, length(pi.length) |
|
, trees() |
|
{ |
|
using std::swap; |
|
using boost::swap; |
|
using BOOST_SPIRIT_CLASSIC_NS::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<IteratorT, NodeFactoryT, T>::container_t trees_) |
|
: stop(stop_) |
|
, match(match_) |
|
, full(full_) |
|
, length(length_) |
|
, trees() |
|
{ |
|
using std::swap; |
|
using boost::swap; |
|
using BOOST_SPIRIT_CLASSIC_NS::swap; |
|
|
|
// use auto_ptr like ownership for the trees data member |
|
swap(trees, trees_); |
|
} |
|
}; |
|
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
|
|
|
}} // namespace BOOST_SPIRIT_CLASSIC_NS |
|
|
|
#endif |
|
|
|
|