Boost logo

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