Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2007-04-04 15:49:15


Larry Evans wrote:
> On 04/04/2007 01:14 PM, Eric Niebler wrote:
>
>> They are
>> part of proto's meta-grammar facility. If you want to know if an
>> expression type E matches grammar G1 or G2, you use:
>>
>> proto::matches<E, proto::or_<G1, G2> >
>>
>> That's a compile-time boolean test. Proto::and_ behaves similarly. Like
>> mpl::or_ and mpl::and_ (and like || and &&) these do short-circuit
>> evaluation.
>>
>> HTH,
>>
>
> That sort of helps. I guess I was just predisposed to thinking
> of them as doing something similar to spirit's alternative<L,R> and
> sequence<L,R> templates; however, I guess not. Maybe my confusion is
> somehow related to the possiblity of have placeholder's as arguments
> to the templates. I understand that this is related to proto's ability
> to do transform of the template expressions, OTOH, spirit doesn't
> transform templates, only runtime values (via the parse member function).
>
> In short, I need to study proto some more :(

Proto has some novel ways of doing things, so your confusion is not
surprising. But this is a good opportunity for me to dig into Proto's
philosophy.

In Spirit-1, alternate<> and sequence<> are containers. They *are* the
expression template. They also have domain-specific behaviors (eg.
parse() member functions) that make the expression template do that
thing that Spirit does (parse).

In proto, there is one container: expr<>. Proto's operator overloads
glom smaller expr<>'s into larger ones, building a tree. By default,
that tree has no behaviors (no parse() member function, for example).[*]
So once you've built this tree, you'll need to do something with it.
Proto gives you a couple of choices. One is proto::eval(), which lets
you walk the tree and do domain-specific things at each node. Another
choice is to transform the tree into another object that has the
behaviors you want. For this, you write a domain-specific tree
transformation by writing out your DSEL's grammar and attaching
transforms to your grammar's rules.

This is where proto::or_ and proto::and_ come in. Imagine in your DSEL,
only terminals of type int and char* are allowed. Then you might define
a Terminal rule in your grammar as follows:

struct Terminal
   : proto::or_<
         proto::terminal<int>
       , proto::terminal<char*>
>
{};

When you write your tree transform, you might want to attach some
transformation to the Terminal rule to, for example, turn char* into
spirit::string_parser, or whatever.

Proto's meta-grammar facilities are good for more than just tree
transformations, by the way. You can use them with proto::matches<> to
make compile-time decisions based on the structure of an expression. You
can even use a proto meta-grammar to control proto's operator
overloading! When you do that, only those operators which build valid
expressions, as determined by your meta-grammar, are considered.

[*] There is a way in proto to add domain-specific behaviors, like extra
member functions, directly to the expression tree. It's called
proto::extends<>. Just so you know.

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

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