
Eric, Several newbie questions here. I'm trying to understand how the proto::arg transform works. Looking at the Mixed example, I see this: template<typename Grammar> struct begin : Grammar { template<typename Expr, typename State, typename Visitor> struct apply : proto::terminal< iterator_wrapper< typename proto::result_of::arg<Expr>::type::const_iterator > > {}; template<typename Expr, typename State, typename Visitor> static typename apply<Expr, State, Visitor>::type call(Expr const &expr, State const &state, Visitor &visitor) { return proto::as_expr(cbegin(proto::arg(expr))); } }; Not knowing exactly what cbegin does, I think this makes sense to me. Given a grammar like this: // Here is the grammar for if_ statements // matches if_(e1)[e2] struct IfGrammar : boost::proto::subscript< boost::proto::unary_expr< tag::If, ExpressionGrammar >, StatementGrammar > {}; I want to create an AST node representing the statement. So I wrote a custom transform like this: // Transform a two-operand node template<typename Grammar, typename NodeType> struct ConstructBinaryLeftNested { : Grammar { template<typename Expr, typename State, typename Visitor> struct apply { typedef typename Ptr<NodeType>::type type; }; template<typename Expr, typename State, typename Visitor> static typename apply<Expr, State, Visitor>::type call(Expr const &expr, State const &state, Visitor &visitor) { return(new typename apply<Expr, State, Visitor>::type( Grammar::call(proto::arg(proto::left(expr)),state,visitor), Grammar::call(proto::right(expr),state,visitor))); } } } And use it like this: struct StatementGrammar : boost::proto::or< ConstructBinaryLeftNested<IfGrammar, IfStatement>, ... Essentially, I want to generate code like this: new IfStatement( transformed arg of unary_expr, // The condition transformed arg of subscript); // The statement block So several questions arise: - Is this use of arg/left allowed and correct? - If not, do I have to use identity instead to pass up the grandchild? - If not, what should I do? Something's telling me I'm not understanding something really fundamental. In particular, I don't understand the use of arg in the run-time code of Mixed vs. the use of arg as a compile-time transform. Some annotated examples of how proto transforms work with runtime code would be helpful. The calc transform examples are all pure compile-time code. Also, how do I get the arity of an expression at compile time? I need to be able to construct an AST node representing a function call which could have any number of arguments: struct CallGrammar : boost::proto::function<ExpressionGrammar, boost::proto::vararg<ExpressionGrammar> > {}; I need a transform that looks something like this: // Transform an n-ary node template<typename Grammar, typename NodeType> struct ConstructNary { : Grammar { template<typename Expr, typename State, typename Visitor> struct apply { typedef typename Ptr<NodeType>::type type; }; template<typename Expr, typename State, typename Visitor> static typename apply<Expr, State, Visitor>::type call(Expr const &expr, State const &state, Visitor &visitor) { func = new typename apply<Expr, State, Visitor>::type( // Function name Grammar::call(proto::arg<0>(expr),state,visitor)); // Generate func->addArgument(arg<i>(expr)) for each child ct_for<numargs(expr)-1>::exec(expr, func); return(func); } } } Does this make sense? Is it possible? Thanks for your help. -Dave