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.
439 lines
15 KiB
439 lines
15 KiB
/*============================================================================= |
|
Copyright (c) 2001-2011 Joel de Guzman |
|
|
|
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_RULE_FEBRUARY_12_2007_1020AM) |
|
#define BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM |
|
|
|
#if defined(_MSC_VER) |
|
#pragma once |
|
#endif |
|
|
|
#include <boost/assert.hpp> |
|
#include <boost/config.hpp> |
|
#include <boost/function.hpp> |
|
#include <boost/mpl/vector.hpp> |
|
#include <boost/type_traits/add_reference.hpp> |
|
#include <boost/type_traits/is_same.hpp> |
|
|
|
#include <boost/fusion/include/vector.hpp> |
|
#include <boost/fusion/include/size.hpp> |
|
#include <boost/fusion/include/make_vector.hpp> |
|
#include <boost/fusion/include/cons.hpp> |
|
#include <boost/fusion/include/as_list.hpp> |
|
#include <boost/fusion/include/as_vector.hpp> |
|
|
|
#include <boost/spirit/home/support/unused.hpp> |
|
#include <boost/spirit/home/support/argument.hpp> |
|
#include <boost/spirit/home/support/context.hpp> |
|
#include <boost/spirit/home/support/info.hpp> |
|
#include <boost/spirit/home/qi/detail/attributes.hpp> |
|
#include <boost/spirit/home/support/nonterminal/extract_param.hpp> |
|
#include <boost/spirit/home/support/nonterminal/locals.hpp> |
|
#include <boost/spirit/home/qi/reference.hpp> |
|
#include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp> |
|
#include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp> |
|
#include <boost/spirit/home/qi/nonterminal/nonterminal_fwd.hpp> |
|
#include <boost/spirit/home/qi/skip_over.hpp> |
|
|
|
#if defined(BOOST_MSVC) |
|
# pragma warning(push) |
|
# pragma warning(disable: 4355) // 'this' : used in base member initializer list warning |
|
#endif |
|
|
|
namespace boost { namespace spirit { namespace qi |
|
{ |
|
BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _) |
|
|
|
using spirit::_pass_type; |
|
using spirit::_val_type; |
|
using spirit::_a_type; |
|
using spirit::_b_type; |
|
using spirit::_c_type; |
|
using spirit::_d_type; |
|
using spirit::_e_type; |
|
using spirit::_f_type; |
|
using spirit::_g_type; |
|
using spirit::_h_type; |
|
using spirit::_i_type; |
|
using spirit::_j_type; |
|
|
|
#ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
|
|
|
using spirit::_pass; |
|
using spirit::_val; |
|
using spirit::_a; |
|
using spirit::_b; |
|
using spirit::_c; |
|
using spirit::_d; |
|
using spirit::_e; |
|
using spirit::_f; |
|
using spirit::_g; |
|
using spirit::_h; |
|
using spirit::_i; |
|
using spirit::_j; |
|
|
|
#endif |
|
|
|
using spirit::info; |
|
using spirit::locals; |
|
|
|
template < |
|
typename Iterator, typename T1, typename T2, typename T3 |
|
, typename T4> |
|
struct rule |
|
: proto::extends< |
|
typename proto::terminal< |
|
reference<rule<Iterator, T1, T2, T3, T4> const> |
|
>::type |
|
, rule<Iterator, T1, T2, T3, T4> |
|
> |
|
, parser<rule<Iterator, T1, T2, T3, T4> > |
|
{ |
|
typedef Iterator iterator_type; |
|
typedef rule<Iterator, T1, T2, T3, T4> this_type; |
|
typedef reference<this_type const> reference_; |
|
typedef typename proto::terminal<reference_>::type terminal; |
|
typedef proto::extends<terminal, this_type> base_type; |
|
typedef mpl::vector<T1, T2, T3, T4> template_params; |
|
|
|
// The rule's locals_type: a sequence of types to be used as local variables |
|
typedef typename |
|
spirit::detail::extract_locals<template_params>::type |
|
locals_type; |
|
|
|
// The rule's skip-parser type |
|
typedef typename |
|
spirit::detail::extract_component< |
|
qi::domain, template_params>::type |
|
skipper_type; |
|
|
|
// The rule's signature |
|
typedef typename |
|
spirit::detail::extract_sig<template_params>::type |
|
sig_type; |
|
|
|
// The rule's encoding type |
|
typedef typename |
|
spirit::detail::extract_encoding<template_params>::type |
|
encoding_type; |
|
|
|
// This is the rule's attribute type |
|
typedef typename |
|
spirit::detail::attr_from_sig<sig_type>::type |
|
attr_type; |
|
typedef typename add_reference<attr_type>::type attr_reference_type; |
|
|
|
// parameter_types is a sequence of types passed as parameters to the rule |
|
typedef typename |
|
spirit::detail::params_from_sig<sig_type>::type |
|
parameter_types; |
|
|
|
static size_t const params_size = |
|
fusion::result_of::size<parameter_types>::type::value; |
|
|
|
typedef context< |
|
fusion::cons<attr_reference_type, parameter_types> |
|
, locals_type> |
|
context_type; |
|
|
|
typedef function< |
|
bool(Iterator& first, Iterator const& last |
|
, context_type& context |
|
, skipper_type const& skipper |
|
)> |
|
function_type; |
|
|
|
typedef typename |
|
mpl::if_< |
|
is_same<encoding_type, unused_type> |
|
, unused_type |
|
, tag::char_code<tag::encoding, encoding_type> |
|
>::type |
|
encoding_modifier_type; |
|
|
|
explicit rule(std::string const& name_ = "unnamed-rule") |
|
: base_type(terminal::make(reference_(*this))) |
|
, name_(name_) |
|
{ |
|
} |
|
|
|
rule(rule const& rhs) |
|
: base_type(terminal::make(reference_(*this))) |
|
, name_(rhs.name_) |
|
, f(rhs.f) |
|
{ |
|
} |
|
|
|
template <typename Auto, typename Expr> |
|
static void define(rule& lhs, Expr const& expr, mpl::false_) |
|
{ |
|
// Report invalid expression error as early as possible. |
|
// If you got an error_invalid_expression error message here, |
|
// then the expression (expr) is not a valid spirit qi expression. |
|
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); |
|
} |
|
|
|
template <typename Auto, typename Expr> |
|
static void define(rule& lhs, Expr const& expr, mpl::true_) |
|
{ |
|
lhs.f = detail::bind_parser<Auto>( |
|
compile<qi::domain>(expr, encoding_modifier_type())); |
|
} |
|
|
|
template <typename Expr> |
|
rule(Expr const& expr, std::string const& name_ = "unnamed-rule") |
|
: base_type(terminal::make(reference_(*this))) |
|
, name_(name_) |
|
{ |
|
define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>()); |
|
} |
|
|
|
rule& operator=(rule const& rhs) |
|
{ |
|
// The following assertion fires when you try to initialize a rule |
|
// from an uninitialized one. Did you mean to refer to the right |
|
// hand side rule instead of assigning from it? In this case you |
|
// should write lhs = rhs.alias(); |
|
BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?"); |
|
|
|
f = rhs.f; |
|
name_ = rhs.name_; |
|
return *this; |
|
} |
|
|
|
std::string const& name() const |
|
{ |
|
return name_; |
|
} |
|
|
|
void name(std::string const& str) |
|
{ |
|
name_ = str; |
|
} |
|
|
|
template <typename Expr> |
|
rule& operator=(Expr const& expr) |
|
{ |
|
define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>()); |
|
return *this; |
|
} |
|
|
|
// VC7.1 has problems to resolve 'rule' without explicit template parameters |
|
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) |
|
// g++ 3.3 barfs if this is a member function :( |
|
template <typename Expr> |
|
friend rule& operator%=(rule& r, Expr const& expr) |
|
{ |
|
define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>()); |
|
return r; |
|
} |
|
|
|
#if defined(BOOST_NO_RVALUE_REFERENCES) |
|
// non-const version needed to suppress proto's %= kicking in |
|
template <typename Expr> |
|
friend rule& operator%=(rule& r, Expr& expr) |
|
{ |
|
return r %= static_cast<Expr const&>(expr); |
|
} |
|
#else |
|
// for rvalue references |
|
template <typename Expr> |
|
friend rule& operator%=(rule& r, Expr&& expr) |
|
{ |
|
define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>()); |
|
return r; |
|
} |
|
#endif |
|
|
|
#else |
|
// both friend functions have to be defined out of class as VC7.1 |
|
// will complain otherwise |
|
template <typename OutputIterator_, typename T1_, typename T2_ |
|
, typename T3_, typename T4_, typename Expr> |
|
friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
|
rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr); |
|
|
|
// non-const version needed to suppress proto's %= kicking in |
|
template <typename OutputIterator_, typename T1_, typename T2_ |
|
, typename T3_, typename T4_, typename Expr> |
|
friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
|
rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr); |
|
#endif |
|
|
|
template <typename Context, typename Iterator_> |
|
struct attribute |
|
{ |
|
typedef attr_type type; |
|
}; |
|
|
|
template <typename Context, typename Skipper, typename Attribute> |
|
bool parse(Iterator& first, Iterator const& last |
|
, Context& /*context*/, Skipper const& skipper |
|
, Attribute& attr) const |
|
{ |
|
if (f) |
|
{ |
|
// do a preskip if this is an implied lexeme |
|
if (is_same<skipper_type, unused_type>::value) |
|
qi::skip_over(first, last, skipper); |
|
|
|
typedef traits::make_attribute<attr_type, Attribute> make_attribute; |
|
|
|
// do down-stream transformation, provides attribute for |
|
// rhs parser |
|
typedef traits::transform_attribute< |
|
typename make_attribute::type, attr_type, domain> |
|
transform; |
|
|
|
typename make_attribute::type made_attr = make_attribute::call(attr); |
|
typename transform::type attr_ = transform::pre(made_attr); |
|
|
|
// If you are seeing a compilation error here, you are probably |
|
// trying to use a rule or a grammar which has inherited |
|
// attributes, without passing values for them. |
|
context_type context(attr_); |
|
|
|
// If you are seeing a compilation error here stating that the |
|
// fourth parameter can't be converted to a required target type |
|
// then you are probably trying to use a rule or a grammar with |
|
// an incompatible skipper type. |
|
if (f(first, last, context, skipper)) |
|
{ |
|
// do up-stream transformation, this integrates the results |
|
// back into the original attribute value, if appropriate |
|
traits::post_transform(attr, attr_); |
|
return true; |
|
} |
|
|
|
// inform attribute transformation of failed rhs |
|
traits::fail_transform(attr, attr_); |
|
} |
|
return false; |
|
} |
|
|
|
template <typename Context, typename Skipper |
|
, typename Attribute, typename Params> |
|
bool parse(Iterator& first, Iterator const& last |
|
, Context& caller_context, Skipper const& skipper |
|
, Attribute& attr, Params const& params) const |
|
{ |
|
if (f) |
|
{ |
|
// do a preskip if this is an implied lexeme |
|
if (is_same<skipper_type, unused_type>::value) |
|
qi::skip_over(first, last, skipper); |
|
|
|
typedef traits::make_attribute<attr_type, Attribute> make_attribute; |
|
|
|
// do down-stream transformation, provides attribute for |
|
// rhs parser |
|
typedef traits::transform_attribute< |
|
typename make_attribute::type, attr_type, domain> |
|
transform; |
|
|
|
typename make_attribute::type made_attr = make_attribute::call(attr); |
|
typename transform::type attr_ = transform::pre(made_attr); |
|
|
|
// If you are seeing a compilation error here, you are probably |
|
// trying to use a rule or a grammar which has inherited |
|
// attributes, passing values of incompatible types for them. |
|
context_type context(attr_, params, caller_context); |
|
|
|
// If you are seeing a compilation error here stating that the |
|
// fourth parameter can't be converted to a required target type |
|
// then you are probably trying to use a rule or a grammar with |
|
// an incompatible skipper type. |
|
if (f(first, last, context, skipper)) |
|
{ |
|
// do up-stream transformation, this integrates the results |
|
// back into the original attribute value, if appropriate |
|
traits::post_transform(attr, attr_); |
|
return true; |
|
} |
|
|
|
// inform attribute transformation of failed rhs |
|
traits::fail_transform(attr, attr_); |
|
} |
|
return false; |
|
} |
|
|
|
template <typename Context> |
|
info what(Context& /*context*/) const |
|
{ |
|
return info(name_); |
|
} |
|
|
|
reference_ alias() const |
|
{ |
|
return reference_(*this); |
|
} |
|
|
|
typename proto::terminal<this_type>::type copy() const |
|
{ |
|
typename proto::terminal<this_type>::type result = {*this}; |
|
return result; |
|
} |
|
|
|
// bring in the operator() overloads |
|
rule const& get_parameterized_subject() const { return *this; } |
|
typedef rule parameterized_subject_type; |
|
#include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp> |
|
|
|
std::string name_; |
|
function_type f; |
|
}; |
|
|
|
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) |
|
template <typename OutputIterator_, typename T1_, typename T2_ |
|
, typename T3_, typename T4_, typename Expr> |
|
rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
|
rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr) |
|
{ |
|
// Report invalid expression error as early as possible. |
|
// If you got an error_invalid_expression error message here, |
|
// then the expression (expr) is not a valid spirit qi expression. |
|
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); |
|
|
|
typedef typename |
|
rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type |
|
encoding_modifier_type; |
|
|
|
r.f = detail::bind_parser<mpl::true_>( |
|
compile<qi::domain>(expr, encoding_modifier_type())); |
|
return r; |
|
} |
|
|
|
template <typename Iterator_, typename T1_, typename T2_ |
|
, typename T3_, typename T4_, typename Expr> |
|
rule<Iterator_, T1_, T2_, T3_, T4_>& operator%=( |
|
rule<Iterator_, T1_, T2_, T3_, T4_>& r, Expr& expr) |
|
{ |
|
return r %= static_cast<Expr const&>(expr); |
|
} |
|
#endif |
|
}}} |
|
|
|
namespace boost { namespace spirit { namespace traits |
|
{ |
|
/////////////////////////////////////////////////////////////////////////// |
|
template < |
|
typename IteratorA, typename IteratorB, typename Attribute |
|
, typename Context, typename T1, typename T2, typename T3, typename T4> |
|
struct handles_container< |
|
qi::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context, IteratorB> |
|
: traits::is_container< |
|
typename attribute_of< |
|
qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB |
|
>::type |
|
> |
|
{}; |
|
}}} |
|
|
|
#if defined(BOOST_MSVC) |
|
# pragma warning(pop) |
|
#endif |
|
|
|
#endif
|
|
|