|
Boost-Commit : |
From: hartmut.kaiser_at_[hidden]
Date: 2008-04-29 20:59:09
Author: hkaiser
Date: 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
New Revision: 44901
URL: http://svn.boost.org/trac/boost/changeset/44901
Log:
Spirit.Karma: Fixed rule, added calc2_ast_dump example
Added:
trunk/libs/spirit/example/karma/calc2_ast_dump.cpp (contents, props changed)
Text files modified:
trunk/boost/spirit/home/karma/char/char.hpp | 4
trunk/boost/spirit/home/karma/detail/output_iterator.hpp | 5
trunk/boost/spirit/home/karma/nonterminal/detail/rule.hpp | 147 ++++-----------------------
trunk/boost/spirit/home/karma/nonterminal/nonterminal.hpp | 34 ++----
trunk/boost/spirit/home/karma/nonterminal/nonterminal_director.hpp | 70 ++++++-------
trunk/boost/spirit/home/karma/nonterminal/rule.hpp | 24 ++-
trunk/boost/spirit/home/karma/operator/alternative.hpp | 32 ++----
trunk/boost/spirit/home/karma/operator/detail/alternative.hpp | 204 +++++++++++++++++++++++++-------------
trunk/boost/spirit/home/karma/operator/karma-alt/alternative.hpp | 34 ++----
trunk/boost/spirit/home/karma/operator/karma-alt/detail/alternative.hpp | 207 ++++++++++++++++++++++++++-------------
trunk/boost/spirit/home/support/argument.hpp | 2
11 files changed, 382 insertions(+), 381 deletions(-)
Modified: trunk/boost/spirit/home/karma/char/char.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/char/char.hpp (original)
+++ trunk/boost/spirit/home/karma/char/char.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -111,7 +111,7 @@
+ '\'';
}
};
-
+
///////////////////////////////////////////////////////////////////////////
//
// lazy_char
@@ -146,7 +146,7 @@
return "char";
}
};
-
+
///////////////////////////////////////////////////////////////////////////
//
// lower and upper case variants of any_char with an associated parameter
Modified: trunk/boost/spirit/home/karma/detail/output_iterator.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/detail/output_iterator.hpp (original)
+++ trunk/boost/spirit/home/karma/detail/output_iterator.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -14,6 +14,7 @@
#include <vector>
#include <algorithm>
+#include <boost/noncopyable.hpp>
#include <boost/spirit/home/karma/detail/ostream_iterator.hpp>
namespace boost { namespace spirit { namespace karma { namespace detail
@@ -83,7 +84,7 @@
///////////////////////////////////////////////////////////////////////////
template <typename OutputIterator>
- class buffer_sink
+ class buffer_sink : boost::noncopyable
{
public:
buffer_sink()
@@ -144,7 +145,7 @@
// on demand, such as counting, buffering, and position tracking.
///////////////////////////////////////////////////////////////////////////
template <typename OutputIterator, typename Enable = void>
- class output_iterator
+ class output_iterator : boost::noncopyable
{
private:
enum output_mode
Modified: trunk/boost/spirit/home/karma/nonterminal/detail/rule.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/nonterminal/detail/rule.hpp (original)
+++ trunk/boost/spirit/home/karma/nonterminal/detail/rule.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -33,6 +33,16 @@
namespace boost { namespace spirit { namespace karma { namespace detail
{
+ struct no_delimiter
+ {
+ // this struct accepts only unused types and
+ // nothing else. This is used by the second
+ // pure virtual parse member function of
+ // virtual_component_base below.
+
+ no_delimiter(unused_type) {}
+ };
+
template <typename OutputIterator, typename Context, typename Delimiter>
struct virtual_component_base
{
@@ -60,7 +70,7 @@
delimiter_type const& delim) = 0;
virtual bool
- generate(OutputIterator& sink, Context& context, unused_type) = 0;
+ generate(OutputIterator& sink, Context& context, no_delimiter) = 0;
boost::detail::atomic_count use_count;
};
@@ -83,119 +93,6 @@
}
///////////////////////////////////////////////////////////////////////////
- template <typename Component, typename Context>
- struct needs_single_attribute
- : mpl::not_<
- typename fusion::traits::is_sequence<
- typename traits::attribute_of<
- karma::domain, Component, Context>::type
- >::type
- >
- {
- };
-
- ///////////////////////////////////////////////////////////////////////////
- template <typename MustDeref, typename Parameter>
- struct deref_if
- {
- typedef typename
- mpl::eval_if<
- MustDeref,
- fusion::result_of::at_c<Parameter, 1>,
- fusion::result_of::pop_front<Parameter>
- >::type
- type;
-
- template <typename Param>
- static type
- call(Param const& param, mpl::true_)
- {
- return fusion::at_c<1>(param);
- }
-
- template <typename Param>
- static type
- call(Param const& param, mpl::false_)
- {
- return fusion::pop_front(param);
- }
-
- template <typename Param>
- static type
- call(Param const& param)
- {
- return call(param, MustDeref());
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
- template <typename Component, typename Context>
- struct propagate_param
- {
- // If first element of the context (that's the parameter type) contains
- // one element only, then the parameter type to propagate is unused,
- // otherwise we consider to use everything except the first element of
- // this sequence.
- //
- // If the resulting sequence type is a fusion sequence containing
- // exactly one element and the right hand side expects a singular
- // (non-sequence) parameter we pass on the first (and only) element of
- // this sequence, otherwise we pass the parameter sequence itself.
- typedef typename
- boost::add_const<
- typename boost::remove_reference<
- typename fusion::result_of::at_c<Context, 0>::type
- >::type
- >::type
- parameter_type;
-
- // this evaluates to mpl::true_ if the rules parameter type is unused
- typedef typename
- mpl::equal_to<mpl::size<parameter_type>, mpl::long_<1> >::type
- no_parameter;
-
- // this evaluates to mpl::true_ if the rules parameter type contains
- // one element and the right hand side generator expects a single
- // (non-sequence) parameter type
- typedef typename
- mpl::and_<
- mpl::equal_to<mpl::size<parameter_type>, mpl::long_<2> >,
- needs_single_attribute<Component, Context>
- >::type
- must_dereference;
-
- typedef typename
- mpl::eval_if<
- no_parameter,
- mpl::identity<unused_type const>,
- deref_if<must_dereference, parameter_type>
- >::type
- propagated_type;
-
- template <typename Ctx>
- static unused_type const
- call(Ctx& context, mpl::true_)
- {
- return unused;
- }
-
- template <typename Ctx>
- static propagated_type
- call(Ctx& context, mpl::false_)
- {
- return deref_if<must_dereference, parameter_type>::
- call(fusion::at_c<0>(context));
- }
-
- template <typename Ctx>
- static propagated_type
- call(Ctx& context)
- {
- return call(context, no_parameter());
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
template <typename OutputIterator, typename Component, typename Context,
typename Delimiter, typename Auto>
struct virtual_component
@@ -220,33 +117,37 @@
bool generate_main(OutputIterator& sink, Context& context,
Delimiter_ const& delim, mpl::false_)
{
- // If Auto is false, the component's parameter is unused.
+ // If Auto is false, we synthesize a new (default constructed)
+ // attribute instance based on the attributes of the embedded
+ // generator.
+ typename traits::attribute_of<
+ karma::domain, Component, Context
+ >::type param;
+
typedef typename Component::director director;
- return director::generate(component, sink, context, delim, unused);
+ return director::generate(component, sink, context, delim, param);
}
template <typename Delimiter_>
bool generate_main(OutputIterator& sink, Context& context,
Delimiter_ const& delim, mpl::true_)
{
- // If Auto is true, we pass the rule's parameters on to the
+ // If Auto is true, we pass the rule's attribute on to the
// component.
typedef typename Component::director director;
return director::generate(component, sink, context, delim,
- detail::propagate_param<Component, Context>::call(context));
+ fusion::at_c<0>(fusion::at_c<0>(context)));
}
bool
- generate_main(OutputIterator& /*sink*/, Context& /*context*/, take_no_delimiter,
- mpl::false_)
+ generate_main(OutputIterator&, Context&, take_no_delimiter, mpl::false_)
{
BOOST_ASSERT(false); // this should never be called
return false;
}
bool
- generate_main(OutputIterator& /*sink*/, Context& /*context*/, take_no_delimiter,
- mpl::true_)
+ generate_main(OutputIterator&, Context&, take_no_delimiter, mpl::true_)
{
BOOST_ASSERT(false); // this should never be called
return false;
@@ -260,7 +161,7 @@
}
virtual bool
- generate(OutputIterator& sink, Context& context, unused_type)
+ generate(OutputIterator& sink, Context& context, no_delimiter)
{
return generate_main(sink, context, unused, Auto());
}
Modified: trunk/boost/spirit/home/karma/nonterminal/nonterminal.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/nonterminal/nonterminal.hpp (original)
+++ trunk/boost/spirit/home/karma/nonterminal/nonterminal.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -59,25 +59,24 @@
mpl::if_<
is_same<result_type_, void>, unused_type, result_type_
>::type
- result_type;
+ attribute_type;
// param_types is a sequence of types passed as parameters to the
// nonterminal
typedef typename
function_types::parameter_types<sig_type>::type
- param_types_;
-
- // if no parameters have been specified, we generate a single
- // unused_type parameter, which is needed to allow grammar parameter
- // propagation to function correctly
- typedef typename
- mpl::if_<
- is_same<typename mpl::size<param_types_>::type, mpl::long_<0> >,
- fusion::single_view<unused_type>,
- param_types_
- >::type
param_types;
+ // the parameter tuple has the attribute value pre-pended
+ typedef typename
+ fusion::result_of::as_vector<
+ fusion::joint_view<
+ fusion::single_view<attribute_type const&>,
+ param_types
+ >
+ >::type
+ retval_param_types;
+
// locals_type is a sequence of types to be used as local variables
typedef typename
fusion::result_of::as_vector<Locals>::type
@@ -86,16 +85,7 @@
// The overall context_type consist of a tuple with:
// 1) a tuple of the return value and parameters
// 2) the locals
- typedef fusion::vector<
- typename fusion::result_of::as_vector<
- fusion::joint_view<
- fusion::single_view<result_type const>,
- param_types
- >
- >::type,
- typename fusion::result_of::as_vector<locals_type>::type
- >
- context_type;
+ typedef fusion::vector<retval_param_types, locals_type> context_type;
typedef nonterminal<Derived, Sig, Locals> self_type;
typedef nonterminal_holder<Derived const*, Derived> nonterminal_holder_;
Modified: trunk/boost/spirit/home/karma/nonterminal/nonterminal_director.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/nonterminal/nonterminal_director.hpp (original)
+++ trunk/boost/spirit/home/karma/nonterminal/nonterminal_director.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -15,6 +15,7 @@
#include <boost/spirit/home/support/nonterminal/detail/expand_arg.hpp>
#include <boost/spirit/home/karma/domain.hpp>
#include <boost/spirit/home/support/component.hpp>
+#include <boost/spirit/home/support/attribute_transform.hpp>
#include <boost/spirit/home/support/detail/values.hpp>
#include <boost/fusion/include/transform.hpp>
#include <boost/fusion/include/join.hpp>
@@ -28,56 +29,63 @@
{
struct nonterminal_director
{
+ // The attribute (parameter) of nonterminals is the type given to them
+ // as the return value of the function signature.
template <typename Component, typename Context, typename Unused>
struct attribute
{
- typedef typename result_of::subject<Component>::type nonterminal_holder;
- typedef typename nonterminal_holder::nonterminal_type::param_types type;
+ typedef typename
+ result_of::subject<Component>::type
+ nonterminal_holder;
+ typedef typename
+ nonterminal_holder::nonterminal_type::attribute_type
+ type;
};
+ // the nonterminal_holder holds an actual nonterminal_object
template <
typename NonterminalContext, typename Nonterminal,
- typename OutputIterator, typename Context,
- typename Delimiter, typename Parameter>
+ typename OutputIterator, typename Context, typename Delimiter,
+ typename Parameter>
static bool generate_nonterminal(
nonterminal_object<Nonterminal> const& x,
- OutputIterator& sink, Context& context_,
- Delimiter const& delim, Parameter const& param)
+ OutputIterator& sink, Context&, Delimiter const& delim,
+ Parameter const& param)
{
- // the nonterminal_holder holds an actual nonterminal_object
typedef typename Nonterminal::locals_type locals_type;
- NonterminalContext context(param, locals_type());
+ fusion::single_view<Parameter const&> front(param);
+ NonterminalContext context(front, locals_type());
return x.obj.generate(sink, context, delim);
}
+ // the nonterminal_holder holds a pointer to a nonterminal
template <
typename NonterminalContext, typename Nonterminal,
- typename OutputIterator, typename Context,
- typename Delimiter, typename Parameter>
+ typename OutputIterator, typename Context, typename Delimiter,
+ typename Parameter>
static bool generate_nonterminal(
Nonterminal const* ptr,
- OutputIterator& sink, Context& /*context_*/,
- Delimiter const& delim, Parameter const& param)
+ OutputIterator& sink, Context&, Delimiter const& delim,
+ Parameter const& param)
{
- // the nonterminal_holder holds a pointer to a nonterminal
typedef typename Nonterminal::locals_type locals_type;
- NonterminalContext context(param, locals_type());
+ fusion::single_view<Parameter const&> front(param);
+ NonterminalContext context(front, locals_type());
return ptr->generate(sink, context, delim);
}
+ // the nonterminal_holder holds a parameterized_nonterminal
template <
typename NonterminalContext, typename Nonterminal,
typename FSequence, typename OutputIterator,
- typename Context, typename Delimiter,
- typename Parameter>
+ typename Context, typename Delimiter, typename Parameter>
static bool generate_nonterminal(
parameterized_nonterminal<Nonterminal, FSequence> const& x,
- OutputIterator& sink, Context& context_,
- Delimiter const& delim, Parameter const& /*param*/)
+ OutputIterator& sink, Context& context_, Delimiter const& delim,
+ Parameter const& param)
{
- // the nonterminal_holder holds a parameterized_nonterminal
typedef typename Nonterminal::locals_type locals_type;
- fusion::single_view<unused_type const> front(unused);
+ fusion::single_view<Parameter const&> front(param);
NonterminalContext context(
fusion::join(
front,
@@ -95,8 +103,7 @@
// main entry point
///////////////////////////////////////////////////////////////////////
template <
- typename Component,
- typename OutputIterator, typename Context,
+ typename Component, typename OutputIterator, typename Context,
typename Delimiter, typename Parameter>
static bool generate(
Component const& component, OutputIterator& sink,
@@ -107,29 +114,16 @@
nonterminal_holder;
// The overall context_type consists of a tuple with:
- // 1) a tuple of the return value and parameters
+ // 1) a tuple of the attribute and parameters
// 2) the locals
// if no signature is specified the first tuple contains
- // an unused_type element at position zero only.
-
+ // the attribute at position zero only.
typedef typename
nonterminal_holder::nonterminal_type::context_type
context_type;
- typedef typename
- mpl::if_<
- is_same<typename remove_const<Parameter>::type, unused_type>,
- context_type,
- Parameter
- >::type
- parameter_type;
-
- // create an parameter if one is not supplied
- parameter_type p (spirit::detail::make_value<parameter_type>::call(param));
-
return generate_nonterminal<context_type>(
- subject(component).held, sink, context, delim, p
- );
+ subject(component).held, sink, context, delim, param);
}
template <typename Nonterminal>
Modified: trunk/boost/spirit/home/karma/nonterminal/rule.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/nonterminal/rule.hpp (original)
+++ trunk/boost/spirit/home/karma/nonterminal/rule.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -75,9 +75,12 @@
is_component;
// report invalid expression error as early as possible
- BOOST_MPL_ASSERT_MSG(
- is_component::value,
- xpr_is_not_convertible_to_a_generator, ());
+// BOOST_MPL_ASSERT_MSG(
+// is_component::value,
+// xpr_is_not_convertible_to_a_generator, ());
+
+ // temp workaround for mpl problem
+ BOOST_STATIC_ASSERT(is_component::value);
define(xpr, mpl::false_());
return *this;
@@ -91,9 +94,12 @@
is_component;
// report invalid expression error as early as possible
- BOOST_MPL_ASSERT_MSG(
- is_component::value,
- xpr_is_not_convertible_to_a_generator, ());
+// BOOST_MPL_ASSERT_MSG(
+// is_component::value,
+// xpr_is_not_convertible_to_a_generator, ());
+
+ // temp workaround for mpl problem
+ BOOST_STATIC_ASSERT(is_component::value);
r.define(xpr, mpl::true_());
return r;
@@ -161,9 +167,9 @@
{
// If the following line produces a compilation error stating the
// 3rd parameter is not convertible to the expected type, then you
- // probably trying to use this rule instance with a delimiter which
- // is not compatible with the delimiter type used while defining
- // the type of this rule instance.
+ // are probably trying to use this rule instance with a delimiter
+ // which is not compatible with the delimiter type used while
+ // defining the type of this rule instance.
return ptr->generate(sink, context, delim);
}
Modified: trunk/boost/spirit/home/karma/operator/alternative.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/alternative.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/alternative.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -18,7 +18,13 @@
#include <boost/spirit/home/support/algorithm/any.hpp>
#include <boost/spirit/home/support/unused.hpp>
#include <boost/fusion/include/for_each.hpp>
+#include <boost/fusion/include/mpl.hpp>
+#include <boost/fusion/include/transform.hpp>
#include <boost/variant.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/insert_range.hpp>
+#include <boost/mpl/transform_view.hpp>
namespace boost { namespace spirit { namespace karma
{
@@ -51,28 +57,12 @@
Context& ctx, Delimiter const& d, Parameter const& param)
{
typedef detail::alternative_generate_functor<
- Component, OutputIterator, Context, Delimiter, Parameter>
- functor;
+ OutputIterator, Context, Delimiter, Parameter
+ > functor;
- functor f(component, sink, ctx, d, param);
- return boost::apply_visitor(f, param);
- }
-
- template <typename Component, typename OutputIterator,
- typename Context, typename Delimiter>
- static bool
- generate(Component const& component, OutputIterator& sink,
- Context& ctx, Delimiter const& d, unused_type)
- {
- typedef typename
- fusion::result_of::value_at_c<
- typename Component::elements_type, 0>::type
- child_component_type;
-
- typedef typename child_component_type::director director;
- return director::generate(
- fusion::at_c<0>(component.elements),
- sink, ctx, d, unused);
+ // f return true if *any* of the parser succeeds
+ functor f (sink, ctx, d, param);
+ return fusion::any(component.elements, f);
}
template <typename Component>
Modified: trunk/boost/spirit/home/karma/operator/detail/alternative.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/detail/alternative.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/detail/alternative.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -11,102 +11,166 @@
#pragma once // MS compatible compilers support #pragma once
#endif
+#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/attribute_of.hpp>
#include <boost/spirit/home/karma/domain.hpp>
-#include <boost/fusion/include/at.hpp>
-#include <boost/fusion/include/value_at.hpp>
-#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
+#include <boost/mpl/find_if.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/mpl/distance.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_convertible.hpp>
#include <boost/variant.hpp>
namespace boost { namespace spirit { namespace karma { namespace detail
{
- template <typename Component, typename OutputIterator,
- typename Context, typename Delimiter, typename Parameter>
- struct alternative_generate_functor
+ ///////////////////////////////////////////////////////////////////////////
+ // A component is compatible to a given parameter type if the parameter
+ // is the same as the expected type of the component
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename Expected, typename Parameter>
+ struct compute_compatible_component
{
- typedef bool result_type; // to satisfy boost::variant visition
-
- template <typename Attribute, typename Got>
- struct compute_is_compatible
- {
- typedef typename
- Attribute::types
- types; // mpl sequence of types in the variant
-
- typedef typename
- mpl::begin<types>::type
- begin; // iterator to the first element
+ typedef typename Parameter::types types;
+ typedef typename mpl::end<types>::type end;
+ typedef typename mpl::begin<types>::type begin;
+
+ typedef typename
+ mpl::find_if<
+ types,
+ is_same<mpl::_1, Expected>
+ >::type
+ iter;
- typedef typename
- mpl::end<types>::type
- end; // iterator to the last element
-
- typedef typename
- mpl::find_if<
- types,
- is_same<mpl::_1, Got> // $$$ fix this
- >::type
- iter;
+ typedef typename mpl::not_<is_same<iter, end> >::type type;
+ enum { value = type::value };
+ };
- typedef typename mpl::distance<begin, iter>::type index;
- typedef typename mpl::not_<is_same<iter, end> >::type type;
- enum { value = type::value };
- };
-
- template <typename Got>
- struct compute_is_compatible<unused_type, Got> : mpl::false_ {};
-
- template <typename Attribute, typename Component_, typename Context_>
- struct is_compatible :
- compute_is_compatible<
- typename traits::attribute_of<
- karma::domain, Component_, Context_>::type,
- Attribute>
+ template <typename Expected>
+ struct compute_compatible_component<Expected, unused_type>
+ : mpl::false_
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
+ // execute a generator if the given parameter type is compatible
+ ///////////////////////////////////////////////////////////////////////////
+
+ // this get's instantiated if the parameter type is _not_ compatible with
+ // the generator
+ template <typename Component, typename Parameter, typename Expected,
+ typename Enable = void>
+ struct alternative_generate
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const&, OutputIterator&, Context&, Delimiter const&,
+ Parameter const&)
{
- };
+ return false;
+ }
+ };
- alternative_generate_functor(Component const& component_,
- OutputIterator& sink_, Context& ctx_,
- Delimiter const& d, Parameter const& p)
- : component(component_), sink(sink_), ctx(ctx_), delim(d), param(p)
- {
+ template <typename Component>
+ struct alternative_generate<Component, unused_type, unused_type>
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const& component, OutputIterator& sink,
+ Context& ctx, Delimiter const& delim, unused_type const&)
+ {
+ // return true if any of the generators succeed
+ typedef typename Component::director director;
+ return director::generate(component, sink, ctx, delim, unused);
}
+ };
- template <typename Attribute>
- bool call(Attribute const& actual_attribute, mpl::true_) const
- {
- typedef is_compatible<Attribute, Component, Context> is_compatible;
- typedef typename is_compatible::index index;
- typedef typename Component::elements_type elements;
+ // this get's instantiated if there is no parameter given for the
+ // alternative generator
+ template <typename Component, typename Expected>
+ struct alternative_generate<Component, unused_type, Expected>
+ : alternative_generate<Component, unused_type, unused_type>
+ {};
+
+ // this get's instantiated if the generator does not expect to receive a
+ // parameter (the generator is self contained).
+ template <typename Component, typename Parameter>
+ struct alternative_generate<Component, Parameter, unused_type>
+ : alternative_generate<Component, unused_type, unused_type>
+ {};
+
+ // this get's instantiated if the parameter type is compatible to the
+ // generator
+ template <typename Component, typename Parameter, typename Expected>
+ struct alternative_generate<
+ Component, Parameter, Expected,
+ typename enable_if<
+ compute_compatible_component<Expected, Parameter>
+ >::type
+ >
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const& component, OutputIterator& sink,
+ Context& ctx, Delimiter const& delim, Parameter const& param)
+ {
+ typedef
+ compute_compatible_component<Expected, Parameter>
+ component_type;
typedef typename
- fusion::result_of::value_at<elements, index>::type
- child_component_type;
+ mpl::distance<
+ typename component_type::begin,
+ typename component_type::iter
+ >::type
+ distance_type;
- typedef typename child_component_type::director director;
- return director::generate(
- fusion::at<index>(component.elements),
- sink, ctx, delim, actual_attribute);
+ // make sure, the content of the passed variant matches our
+ // expectations
+ if (param.which() != distance_type::value)
+ return false;
+
+ // returns true if any of the generators succeed
+ typedef
+ typename mpl::deref<
+ typename component_type::iter
+ >::type
+ compatible_type;
+
+ typedef typename Component::director director;
+ return director::generate(component, sink, ctx, delim,
+ get<compatible_type>(param));
}
+ };
- template <typename Attribute>
- bool call(Attribute const&, mpl::false_) const
+ ///////////////////////////////////////////////////////////////////////////
+ // alternative_generate_functor: a functor supplied to spirit::any which
+ // will be executed for every generator in a given alternative generator
+ // expression
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename OutputIterator, typename Context, typename Delimiter,
+ typename Parameter>
+ struct alternative_generate_functor
+ {
+ alternative_generate_functor(OutputIterator& sink_, Context& ctx_,
+ Delimiter const& d, Parameter const& p)
+ : sink(sink_), ctx(ctx_), delim(d), param(p)
{
- return false;
}
- template <typename Attribute>
- bool operator()(Attribute const& actual_attribute) const
+ template <typename Component>
+ bool operator()(Component const& component)
{
- typedef mpl::bool_<
- is_compatible<Attribute, Component, Context>::value>
- is_compatible;
+ typedef
+ typename traits::attribute_of<
+ karma::domain, Component, Context>::type
+ expected;
+ typedef
+ alternative_generate<Component, Parameter, expected>
+ generate;
- return call(actual_attribute, is_compatible());
+ return generate::call(component, sink, ctx, delim, param);
}
- Component const& component;
OutputIterator& sink;
Context& ctx;
Delimiter const& delim;
Modified: trunk/boost/spirit/home/karma/operator/karma-alt/alternative.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/karma-alt/alternative.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/karma-alt/alternative.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -1,4 +1,4 @@
-// Copyright (c) 2001-2007 Hartmut Kaiser
+// Copyright (c) 2001-2008 Hartmut Kaiser
// Copyright (c) 2001-2007 Joel de Guzman
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -18,7 +18,13 @@
#include <boost/spirit/home/support/algorithm/any.hpp>
#include <boost/spirit/home/support/unused.hpp>
#include <boost/fusion/include/for_each.hpp>
+#include <boost/fusion/include/mpl.hpp>
+#include <boost/fusion/include/transform.hpp>
#include <boost/variant.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/insert_range.hpp>
+#include <boost/mpl/transform_view.hpp>
namespace boost { namespace spirit { namespace karma
{
@@ -51,28 +57,12 @@
Context& ctx, Delimiter const& d, Parameter const& param)
{
typedef detail::alternative_generate_functor<
- Component, OutputIterator, Context, Delimiter, Parameter>
- functor;
+ OutputIterator, Context, Delimiter, Parameter
+ > functor;
- functor f(component, sink, ctx, d, param);
- return boost::apply_visitor(f, param);
- }
-
- template <typename Component, typename OutputIterator,
- typename Context, typename Delimiter>
- static bool
- generate(Component const& component, OutputIterator& sink,
- Context& ctx, Delimiter const& d, unused_type)
- {
- typedef typename
- fusion::result_of::value_at_c<
- typename Component::elements_type, 0>::type
- child_component_type;
-
- typedef typename child_component_type::director director;
- return director::generate(
- fusion::at_c<0>(component.elements),
- sink, ctx, d, unused);
+ // f return true if *any* of the parser succeeds
+ functor f (sink, ctx, d, param);
+ return fusion::any(component.elements, f);
}
template <typename Component>
Modified: trunk/boost/spirit/home/karma/operator/karma-alt/detail/alternative.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/karma-alt/detail/alternative.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/karma-alt/detail/alternative.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -1,4 +1,4 @@
-// Copyright (c) 2001-2007 Hartmut Kaiser
+// Copyright (c) 2001-2008 Hartmut Kaiser
// Copyright (c) 2001-2007 Joel de Guzman
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -11,101 +11,166 @@
#pragma once // MS compatible compilers support #pragma once
#endif
+#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/attribute_of.hpp>
#include <boost/spirit/home/karma/domain.hpp>
-#include <boost/fusion/include/at.hpp>
-#include <boost/fusion/include/value_at.hpp>
-#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
+#include <boost/mpl/find_if.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/mpl/distance.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/variant.hpp>
namespace boost { namespace spirit { namespace karma { namespace detail
{
- template <typename Component, typename OutputIterator,
- typename Context, typename Delimiter, typename Parameter>
- struct alternative_generate_functor
+ ///////////////////////////////////////////////////////////////////////////
+ // A component is compatible to a given parameter type if the parameter
+ // is the same as the expected type of the component
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename Expected, typename Parameter>
+ struct is_compatible_component
{
- typedef bool result_type; // to satisfy boost::variant visition
-
- template <typename Attribute, typename Got>
- struct compute_is_compatible
- {
- typedef typename
- Attribute::types
- types; // mpl sequence of types in the variant
-
- typedef typename
- mpl::begin<types>::type
- begin; // iterator to the first element
+ typedef typename Parameter::types types;
+ typedef typename mpl::end<types>::type end;
+ typedef typename mpl::begin<types>::type begin;
+
+ typedef typename
+ mpl::find_if<
+ types,
+ is_same<mpl::_1, Expected>
+ >::type
+ iter;
- typedef typename
- mpl::end<types>::type
- end; // iterator to the last element
-
- typedef typename
- mpl::find_if<
- types,
- is_same<mpl::_1, Got> // $$$ fix this
- >::type
- iter;
+ typedef typename mpl::not_<is_same<iter, end> >::type type;
+ enum { value = type::value };
+ };
- typedef typename mpl::distance<begin, iter>::type index;
- typedef typename mpl::not_<is_same<iter, end> >::type type;
- enum { value = type::value };
- };
-
- template <typename Got>
- struct compute_is_compatible<unused_type, Got> : mpl::false_ {};
-
- template <typename Attribute, typename Component_, typename Context_>
- struct is_compatible :
- compute_is_compatible<
- typename traits::attribute_of<
- karma::domain, Component_, Context_>::type,
- Attribute>
+ template <typename Expected>
+ struct is_compatible_component<Expected, unused_type>
+ : mpl::false_
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
+ // execute a generator if the given parameter type is compatible
+ ///////////////////////////////////////////////////////////////////////////
+
+ // this get's instantiated if the parameter type is _not_ compatible with
+ // the generator
+ template <typename Component, typename Parameter, typename Expected,
+ typename Enable = void>
+ struct alternative_generate
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const&, OutputIterator&, Context&, Delimiter const&,
+ Parameter const&)
{
- };
+ return false;
+ }
+ };
- alternative_generate_functor(Component const& component_,
- OutputIterator& sink_, Context& ctx_,
- Delimiter const& d, Parameter const& p)
- : component(component_), sink(sink_), ctx(ctx_), delim(d), param(p)
- {
+ template <typename Component>
+ struct alternative_generate<Component, unused_type, unused_type>
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const& component, OutputIterator& sink,
+ Context& ctx, Delimiter const& delim, unused_type const&)
+ {
+ // return true if any of the generators succeed
+ typedef typename Component::director director;
+ return director::generate(component, sink, ctx, delim, unused);
}
+ };
- template <typename Attribute>
- bool call(Attribute const& actual_attribute, mpl::true_) const
- {
- typedef is_compatible<Attribute, Component, Context> is_compatible;
- typedef typename is_compatible::index index;
- typedef typename Component::elements_type elements;
+ // this get's instantiated if there is no parameter given for the
+ // alternative generator
+ template <typename Component, typename Expected>
+ struct alternative_generate<Component, unused_type, Expected>
+ : alternative_generate<Component, unused_type, unused_type>
+ {};
+
+ // this get's instantiated if the generator does not expect to receive a
+ // parameter (the generator is self contained).
+ template <typename Component, typename Parameter>
+ struct alternative_generate<Component, Parameter, unused_type>
+ : alternative_generate<Component, unused_type, unused_type>
+ {};
+
+ // this get's instantiated if the parameter type is compatible to the
+ // generator
+ template <typename Component, typename Parameter, typename Expected>
+ struct alternative_generate<
+ Component, Parameter, Expected,
+ typename enable_if<
+ is_compatible_component<Expected, Parameter>
+ >::type
+ >
+ {
+ template <typename OutputIterator, typename Context, typename Delimiter>
+ static bool
+ call(Component const& component, OutputIterator& sink,
+ Context& ctx, Delimiter const& delim, Parameter const& param)
+ {
+ typedef
+ is_compatible_component<Expected, Parameter>
+ component_type;
typedef typename
- fusion::result_of::value_at<elements, index>::type
- child_component_type;
+ mpl::distance<
+ typename component_type::begin,
+ typename component_type::iter
+ >::type
+ distance_type;
- typedef typename child_component_type::director director;
- return director::generate(
- fusion::at<index>(component.elements),
- sink, ctx, delim, actual_attribute);
+ // make sure, the content of the passed variant matches our
+ // expectations
+ if (param.which() != distance_type::value)
+ return false;
+
+ // returns true if any of the generators succeed
+ typedef
+ typename mpl::deref<
+ typename component_type::iter
+ >::type
+ compatible_type;
+
+ typedef typename Component::director director;
+ return director::generate(component, sink, ctx, delim,
+ get<compatible_type>(param));
}
+ };
- template <typename Attribute>
- bool call(Attribute const& actual_attribute, mpl::false_) const
+ ///////////////////////////////////////////////////////////////////////////
+ // alternative_generate_functor: a functor supplied to spirit::any which
+ // will be executed for every generator in a given alternative generator
+ // expression
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename OutputIterator, typename Context, typename Delimiter,
+ typename Parameter>
+ struct alternative_generate_functor
+ {
+ alternative_generate_functor(OutputIterator& sink_, Context& ctx_,
+ Delimiter const& d, Parameter const& p)
+ : sink(sink_), ctx(ctx_), delim(d), param(p)
{
- return false;
}
- template <typename Attribute>
- bool operator()(Attribute const& actual_attribute) const
+ template <typename Component>
+ bool operator()(Component const& component)
{
- typedef mpl::bool_<
- is_compatible<Attribute, Component, Context>::value>
- is_compatible;
+ typedef
+ typename traits::attribute_of<
+ karma::domain, Component, Context>::type
+ expected;
+ typedef
+ alternative_generate<Component, Parameter, expected>
+ generate;
- return call(actual_attribute, is_compatible());
+ return generate::call(component, sink, ctx, delim, param);
}
- Component const& component;
OutputIterator& sink;
Context& ctx;
Delimiter const& delim;
Modified: trunk/boost/spirit/home/support/argument.hpp
==============================================================================
--- trunk/boost/spirit/home/support/argument.hpp (original)
+++ trunk/boost/spirit/home/support/argument.hpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -209,7 +209,7 @@
// current lexer state
phoenix::actor<lexer_state> const state = lexer_state();
- // _val refers to the |return| value of a rule
+ // _val refers to the 'return' value of a rule
// _r0, _r1, ... refer to the rule arguments
phoenix::actor<attribute<0> > const _val = attribute<0>();
phoenix::actor<attribute<0> > const _r0 = attribute<0>();
Added: trunk/libs/spirit/example/karma/calc2_ast_dump.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/karma/calc2_ast_dump.cpp 2008-04-29 20:59:08 EDT (Tue, 29 Apr 2008)
@@ -0,0 +1,385 @@
+/*=============================================================================
+ Copyright (c) 2001-2008 Joel de Guzman
+ Copyright (c) 2001-2008 Hartmut Kaiser
+
+ 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)
+=============================================================================*/
+///////////////////////////////////////////////////////////////////////////////
+//
+// A Calculator example demonstrating generation of AST which gets dumped into
+// a human readable format afterwards.
+//
+// [ JDG April 28, 2008 ]
+// [ HK April 28, 2008 ]
+//
+///////////////////////////////////////////////////////////////////////////////
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/karma.hpp>
+#include <boost/variant/recursive_variant.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/spirit/include/phoenix_statement.hpp>
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include <boost/function_output_iterator.hpp>
+
+using namespace boost::spirit;
+using namespace boost::spirit::ascii;
+using namespace boost::spirit::arg_names;
+
+///////////////////////////////////////////////////////////////////////////////
+// Our AST
+///////////////////////////////////////////////////////////////////////////////
+struct binary_op;
+struct unary_op;
+struct nil {};
+
+struct expression_ast
+{
+ typedef
+ boost::variant<
+ nil // can't happen!
+ , int
+ , boost::recursive_wrapper<binary_op>
+ , boost::recursive_wrapper<unary_op>
+ >
+ type;
+
+ // expose variant types
+ typedef type::types types;
+
+ // expose variant functionality
+ int which() const { return expr.which(); }
+
+ // constructors
+ expression_ast()
+ : expr(nil()) {}
+
+ expression_ast(unary_op const& expr)
+ : expr(expr) {}
+
+ expression_ast(binary_op const& expr)
+ : expr(expr) {}
+
+ expression_ast(unsigned int expr)
+ : expr(expr) {}
+
+ expression_ast(type const& expr)
+ : expr(expr) {}
+
+ expression_ast& operator+=(expression_ast const& rhs);
+ expression_ast& operator-=(expression_ast const& rhs);
+ expression_ast& operator*=(expression_ast const& rhs);
+ expression_ast& operator/=(expression_ast const& rhs);
+
+ type expr;
+};
+
+// expose variant functionality
+template <typename T>
+inline T get(expression_ast const& expr)
+{
+ return boost::get<T>(expr.expr);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+struct binary_op
+{
+ binary_op() {}
+
+ binary_op(
+ char op
+ , expression_ast const& left
+ , expression_ast const& right)
+ : op(op), left(left), right(right) {}
+
+ char op;
+ expression_ast left;
+ expression_ast right;
+};
+
+struct unary_op
+{
+ unary_op(
+ char op
+ , expression_ast const& right)
+ : op(op), right(right) {}
+
+ char op;
+ expression_ast right;
+};
+
+expression_ast& expression_ast::operator+=(expression_ast const& rhs)
+{
+ expr = binary_op('+', expr, rhs);
+ return *this;
+}
+
+expression_ast& expression_ast::operator-=(expression_ast const& rhs)
+{
+ expr = binary_op('-', expr, rhs);
+ return *this;
+}
+
+expression_ast& expression_ast::operator*=(expression_ast const& rhs)
+{
+ expr = binary_op('*', expr, rhs);
+ return *this;
+}
+
+expression_ast& expression_ast::operator/=(expression_ast const& rhs)
+{
+ expr = binary_op('/', expr, rhs);
+ return *this;
+}
+
+// We should be using expression_ast::operator-. There's a bug
+// in phoenix type deduction mechanism that prevents us from
+// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
+// meantime, we will use a phoenix::function below:
+struct negate_expr
+{
+ template <typename T>
+ struct result { typedef T type; };
+
+ expression_ast operator()(expression_ast const& expr) const
+ {
+ return unary_op('-', expr);
+ }
+};
+
+boost::phoenix::function<negate_expr> neg;
+
+///////////////////////////////////////////////////////////////////////////////
+// Our calculator parser grammar
+///////////////////////////////////////////////////////////////////////////////
+template <typename Iterator>
+struct calculator : qi::grammar_def<Iterator, expression_ast(), space_type>
+{
+ calculator()
+ {
+ expression =
+ term [_val = _1]
+ >> *( ('+' >> term [_val += _1])
+ | ('-' >> term [_val -= _1])
+ )
+ ;
+
+ term =
+ factor [_val = _1]
+ >> *( ('*' >> factor [_val *= _1])
+ | ('/' >> factor [_val /= _1])
+ )
+ ;
+
+ factor =
+ uint_ [_val = _1]
+ | '(' >> expression [_val = _1] >> ')'
+ | ('-' >> factor [_val = neg(_1)])
+ | ('+' >> factor [_val = _1])
+ ;
+ }
+
+ qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// A couple of phoenix functions helping to access the elements of the
+// generated AST
+///////////////////////////////////////////////////////////////////////////////
+template <typename T>
+struct get_element
+{
+ template <typename T1>
+ struct result { typedef T const& type; };
+
+ T const& operator()(expression_ast const& expr) const
+ {
+ return boost::get<T>(expr.expr);
+ }
+};
+
+boost::phoenix::function<get_element<int> > _int;
+boost::phoenix::function<get_element<binary_op> > _bin_op;
+boost::phoenix::function<get_element<unary_op> > _unary_op;
+
+///////////////////////////////////////////////////////////////////////////////
+struct get_left
+{
+ template <typename T1>
+ struct result { typedef expression_ast const& type; };
+
+ expression_ast const& operator()(binary_op const& bin_op) const
+ {
+ return bin_op.left;
+ }
+};
+
+boost::phoenix::function<get_left> _left;
+
+struct get_right
+{
+ template <typename T1>
+ struct result { typedef expression_ast const& type; };
+
+ template <typename Node>
+ expression_ast const& operator()(Node const& op) const
+ {
+ return op.right;
+ }
+};
+
+boost::phoenix::function<get_right> _right;
+
+struct get_op
+{
+ template <typename T1>
+ struct result { typedef char type; };
+
+ template <typename Node>
+ char operator()(Node const& bin_op) const
+ {
+ return bin_op.op;
+ }
+};
+
+boost::phoenix::function<get_op> _op;
+
+///////////////////////////////////////////////////////////////////////////////
+// Our AST grammar for the generator
+///////////////////////////////////////////////////////////////////////////////
+template <typename OuputIterator>
+struct dump_ast
+ : karma::grammar_def<OuputIterator, expression_ast(), space_type>
+{
+ dump_ast()
+ {
+ ast_node %=
+ int_ [_1 = _int(_r0)]
+ | binary_node [_1 = _bin_op(_r0)]
+ | unary_node [_1 = _unary_op(_r0)]
+ ;
+
+ binary_node =
+ ('(' << ast_node << char_ << ast_node << ')')
+ [
+ _1 = _left(_r0), _2 = _op(_r0), _3 = _right(_r0)
+ ]
+ ;
+
+ unary_node =
+ ('(' << char_ << ast_node << ')')
+ [
+ _1 = _op(_r0), _2 = _right(_r0)
+ ]
+ ;
+ }
+
+ karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
+ karma::rule<OuputIterator, binary_op(), space_type> binary_node;
+ karma::rule<OuputIterator, unary_op(), space_type> unary_node;
+};
+
+///////////////////////////////////////////////////////////////////////////
+template <typename String>
+struct string_appender
+{
+ string_appender(String& s)
+ : str(s)
+ {}
+
+ template <typename T>
+ void operator()(T const &x) const
+ {
+ str += x;
+ }
+
+ String& str;
+};
+
+template <typename String>
+inline string_appender<String>
+make_string_appender(String& str)
+{
+ return string_appender<String>(str);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Main program
+///////////////////////////////////////////////////////////////////////////////
+int
+main()
+{
+ using boost::make_function_output_iterator;
+
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "Expression parser...\n\n";
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "Type an expression...or [q or Q] to quit\n\n";
+
+ // Our parser grammar definitions
+ typedef std::string::const_iterator iterator_type;
+ typedef calculator<iterator_type> calculator;
+
+ calculator def;
+ qi::grammar<calculator> calc(def, def.expression);
+
+ // Our generator grammar definitions
+ typedef
+ boost::function_output_iterator<string_appender<std::string> >
+ output_iterator_type;
+ typedef dump_ast<output_iterator_type> dump_ast;
+
+ dump_ast dump_ast_def;
+ karma::grammar<dump_ast> ast_grammar(dump_ast_def, dump_ast_def.ast_node);
+
+ std::string str;
+ while (std::getline(std::cin, str))
+ {
+ if (str.empty() || str[0] == 'q' || str[0] == 'Q')
+ break;
+
+ expression_ast ast;
+ std::string::const_iterator iter = str.begin();
+ std::string::const_iterator end = str.end();
+ bool r = qi::phrase_parse(iter, end, calc, ast, space);
+
+ if (r && iter == end)
+ {
+ std::string generated;
+ r = karma::generate_delimited(
+ make_function_output_iterator(make_string_appender(generated)),
+ ast_grammar, ast, space
+ );
+
+ if (r)
+ {
+ std::cout << "AST for '" << str << "': " << generated
+ << std::endl;
+ }
+ else
+ {
+ std::cout << "-------------------------\n";
+ std::cout << "Generating failed\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+ else
+ {
+ std::string rest(iter, end);
+ std::cout << "-------------------------\n";
+ std::cout << "Parsing failed\n";
+ std::cout << "stopped at: \": " << rest << "\"\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+
+ std::cout << "Bye... :-) \n\n";
+ return 0;
+}
+
+
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk