|
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