132 lines
4.2 KiB
C++
132 lines
4.2 KiB
C++
// Copyright (c) 2011 Aaron Graham
|
|
//
|
|
// 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)
|
|
|
|
#if !defined(BOOST_SPIRIT_REPOSITORY_QI_ADVANCE_JAN_23_2011_1203PM)
|
|
#define BOOST_SPIRIT_REPOSITORY_QI_ADVANCE_JAN_23_2011_1203PM
|
|
|
|
#include <boost/spirit/home/support/terminal.hpp>
|
|
#include <boost/spirit/include/qi_parse.hpp>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// definition the place holder
|
|
namespace boost { namespace spirit { namespace repository { namespace qi
|
|
{
|
|
BOOST_SPIRIT_TERMINAL_EX(advance)
|
|
}}}}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// implementation the enabler
|
|
namespace boost { namespace spirit
|
|
{
|
|
template <typename A0>
|
|
struct use_terminal<qi::domain
|
|
, terminal_ex<repository::qi::tag::advance, fusion::vector1<A0> > >
|
|
: mpl::or_<is_integral<A0>, is_enum<A0> >
|
|
{};
|
|
|
|
template <>
|
|
struct use_lazy_terminal<qi::domain, repository::qi::tag::advance, 1>
|
|
: mpl::true_
|
|
{};
|
|
}}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// implementation of the parser
|
|
namespace boost { namespace spirit { namespace repository { namespace qi
|
|
{
|
|
template <typename Int>
|
|
struct advance_parser
|
|
: boost::spirit::qi::primitive_parser< advance_parser<Int> >
|
|
{
|
|
// Define the attribute type exposed by this parser component
|
|
template <typename Context, typename Iterator>
|
|
struct attribute
|
|
{
|
|
typedef boost::spirit::unused_type type;
|
|
};
|
|
|
|
advance_parser(Int dist)
|
|
: dist(dist)
|
|
{}
|
|
|
|
// This function is called during the actual parsing process
|
|
template <typename Iterator, typename Context
|
|
, typename Skipper, typename Attribute>
|
|
bool parse(Iterator& first, Iterator const& last
|
|
, Context&, Skipper&, Attribute&) const
|
|
{
|
|
// This series of checks is designed to fail parsing on negative
|
|
// values, without generating a "expression always evaluates true"
|
|
// warning on unsigned types.
|
|
if (dist == Int(0)) return true;
|
|
if (dist < Int(1)) return false;
|
|
|
|
typedef typename std::iterator_traits<Iterator>::iterator_category
|
|
iterator_category;
|
|
return advance(first, last, iterator_category());
|
|
}
|
|
|
|
// This function is called during error handling to create
|
|
// a human readable string for the error context.
|
|
template <typename Context>
|
|
boost::spirit::info what(Context&) const
|
|
{
|
|
return boost::spirit::info("advance");
|
|
}
|
|
|
|
private:
|
|
// this is the general implementation used by most iterator categories
|
|
template <typename Iterator, typename IteratorCategory>
|
|
bool advance(Iterator& first, Iterator const& last
|
|
, IteratorCategory) const
|
|
{
|
|
Int n = dist;
|
|
Iterator i = first;
|
|
while (n)
|
|
{
|
|
if (i == last) return false;
|
|
++i;
|
|
--n;
|
|
}
|
|
first = i;
|
|
return true;
|
|
}
|
|
|
|
// this is a specialization for random access iterators
|
|
template <typename Iterator>
|
|
bool advance(Iterator& first, Iterator const& last
|
|
, std::random_access_iterator_tag) const
|
|
{
|
|
Iterator const it = first + dist;
|
|
if (it > last) return false;
|
|
first = it;
|
|
return true;
|
|
}
|
|
|
|
Int const dist;
|
|
};
|
|
}}}}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// instantiation of the parser
|
|
namespace boost { namespace spirit { namespace qi
|
|
{
|
|
template <typename Modifiers, typename A0>
|
|
struct make_primitive<
|
|
terminal_ex<repository::qi::tag::advance, fusion::vector1<A0> >
|
|
, Modifiers>
|
|
{
|
|
typedef repository::qi::advance_parser<A0> result_type;
|
|
|
|
template <typename Terminal>
|
|
result_type operator()(Terminal const& term, unused_type) const
|
|
{
|
|
return result_type(fusion::at_c<0>(term.args));
|
|
}
|
|
};
|
|
}}}
|
|
|
|
#endif
|