Boost logo

Boost :

From: David A. Greene (greened_at_[hidden])
Date: 2007-07-10 22:29:51


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk