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