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 mailing list
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto

Reply via email to