|
Proto : |
Subject: Re: [proto] Thoughts on traversing proto expressions and reusing grammar
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2010-10-20 10:49:08
On Wednesday 20 October 2010 15:02:01 Eric Niebler wrote:
> On 10/14/2010 12:27 PM, Eric Niebler wrote:
> <snip>
>
> > - A new set of actions can be created easily by delegating
> >
> > to MyActions::action by default, and specializing only those
> > rules that need custom handling.
>
> The code I sent around actually falls short on this promise. Here's an
> updated design that corrects the problem. The key is realizing that the
> actions need to be parameterized by ... the actions. That way, they can
> be easily subclassed.
>
> That is, we now have this:
>
> // A collection of semantic actions, indexed by phoenix grammar rules
> struct PhoenixDefaultActions
> {
> template<typename Rule, typename Actions = PhoenixDefaultActions>
> struct action;
> };
>
> struct MyActions
> {
> // Inherit default behavior from PhoenixDefaultActions
> template<typename Rule, typename Actions = MyActions>
> struct action
>
> : PhoenixDefaultActions::action<Rule, Actions>
>
> {};
>
> // Specialize action<> for custom handling of certain
> // grammar rules here...
> };
>
> If you don't ever pass MyActions to PhoenixDefaultActions, then any
> specializations of MyActions::actions will never be considered.
Good catch! I worked a little on trying to simplify that whole grammar with
rules that have thing a bit. Forgive me, but i changed the name to Visitor.
Why? Simply because i think this is what is done here. We visit a specific
node which happened to match our rule.
Here it goes:
namespace detail
{
template <
typename Grammar, typename Visitor, typename IsRule = void>
struct algorithm_case
: Grammar
{};
template <
typename Rule, typename Visitor, int RulesSize = Rule::size>
struct algorithm_case_rule;
template <typename Rule, typename Visitor>
struct algorithm_case_rule<Rule, Visitor, 1>
: proto::when<
typename Rule::rule0
, typename Visitor::template visit<typename Rule::rule0>
>
{};
// add more ...
template <typename Grammar, typename Visitor>
struct algorithm_case<Grammar, Visitor, typename Grammar::is_rule>
: algorithm_case_rule<Grammar, Visitor>
{};
// algorithm is what
template <typename Cases, typename Visitor>
struct algorithm
: proto::switch_<algorithm<Cases, Visitor> >
{
template <typename Tag>
struct case_
: algorithm_case<
typename Cases::template case_<Tag>
, Visitor
>
{};
};
template <typename Grammar>
struct rule
{
typedef void is_rule;
static int const size = 1;
typedef Grammar rule0;
};
template <
typename Grammar0 = void
, typename Grammar1 = void
, typename Grammar2 = void
, typename Dummy = void>
struct rules;
template <typename Grammar>
struct rules<Grammar>
{
typedef void is_rule;
static int const size = 1;
typedef Grammar rule0;
};
// add more ...
}
Making your example:
// A collection of actions indexable by rules.
struct MyActions
{
template<typename Rule>
struct action;
};
// An easier way to dispatch to a tag-specific sub-grammar
template<typename Tag, typename Actions>
struct MyCases
: proto::not< proto::_ >
{};
struct MyCasesImpl
{
template<typename Tag>
struct case_
: MyCases<Tag, Actions>
{};
};
// Define an openly extensible grammar using switch_
template<typename Actions = MyActions>
struct MyGrammar
: detail::algorithm< MyCasesImpl, Actions>
{};
// Define a grammar rule for int terminals
struct IntTerminalRule
: proto::terminal<int>
{};
// Define a grammar rule for char terminals
struct CharTerminalRule
: proto::terminal<char>
{};
// OK, handle the terminals we allow:
template<>
struct MyCases<proto::tag::terminal>
: proto::rules<
IntTerminalRule
, CharTerminalRule
>
{};
// Now, populate the MyActions metafunction class
// with the default actions:
template<>
struct MyActions::action< IntTerminalRule >
: DoIntAction
{};
template<>
struct MyActions::action< CharTerminalRule >
: DoCharAction
{};
Proto list run by eric at boostpro.com