Boost logo

Boost :

From: joel de guzman (isis-tech_at_[hidden])
Date: 2001-06-02 00:45:59


Bruce's post is a bit longish so I hope
you don't mind if I reply in tranches.


> Further, I'd proposed to him that the Filter<...> class (i.e. the
> parser type produced by the shift operator here) not hold a reference
> to the action, but rather aggregate the action directly. This would
> allow the action type's constructor to be invoked directly in the
> grammar so that a single action class could be reused for multiple
> distinct but related actions. For example if we had a Spirit::Action-
> derived class named PushOp whose ctor took an operator and a reference
> to a stack, then the expr2 rule above might be written like so:
> Rule expr2 = expr1 % *( times % expr1 >> PushOp(OP_MUL, stack)
> | divide % expr1 >> PushOp(OP_DIV, stack)
> );

same as:

    Rule expr2 = expr1 >> *( (times >> expr1) [ PushOp(OP_MUL, stack) ]
                           | (divide >> expr1) [ PushOp(OP_DIV, stack) ]

With my proposed expr[action] syntax and classic >> sequencing.
The [] binds tightly than any of Spirit's ops which IMO, makes
it easier to deal with. The >> has a precedence in between % and |
for example.

Also with the [], we can have lazy function expressions. I can't think of
a suitable example yet but I imagine an expression template framework
of lazy action objects. Something akin to Dr. Conway's deferred expressions.

> However, Joel pointed out that there are times when you really want
> the action to be held by reference so that the same object can be
> referenced from more than one point in the grammar and can thus serve
> as a channel for information between the points in the parse where
> those two grammar fragments have been recognized (I'm paraphrasing
> here, so he might correct me if I'm misrepresenting his position).

Thinking about it more a little more closely, I tend to agree now
with Bruce. If we consider actions merely as 'hooks' into the EBNF
hierarchy, then I would agree that these can be const objects.
These hooks, in turn, may carry a reference to some object that
holds the state information (think compiler).

> I'd then suggested that maybe we need to have two different kinds of
> actions to support both uses, and now that I've looked at and thought
> about the situation a little longer, I'd like to propose something
> further along those lines. I notice that the protocol Joel has
> established between Filter objects (BTW, I don't much care for the
> name "Filter" here, but I don't have any counterproposals at the
> moment) and Action objects -- i.e. the Filter calls a member function
> named Process -- is not used anywhere else in the framework. I'd like
> to suggest the following changes:

I don't mind changing the Filter name. This is in fact an artifact.
A pre-release version of Spirit actually allowed Filters to
modify the semantics of a parser (decorator). Spirit does not
allow that now since the inception of Directives.

I'd propose Hook or ActionHook or something close to this.
Or take out the action class altogether and change the name
of Filter to Action.

> 1. The Filter should use operator() rather than a member function
> named Process to invoke the semantic action, and it should NOT
> require the action to be an object derived from the Spirit::Action
> class. It just needs to be something to which the function call
> operator may be applied (with the correct arguments, of course).

Agreed. It can be a functor or a free function.

> 2. The syntax for embedding semantic actions, whatever ends up
> being used, should be overloaded (via partial or explicit
> specialization) so that the Filter holds Spirit::Action-derived
> objects by reference, and everything else by value.

I see no need now for non-const hooks. Your proposal is
superior and can accommodate the previous rationale for
non-const actions.

I will do more experimentation on this.


Thanks a lot,
-Joel de Guzman

Boost list run by bdawes at, gregod at, cpdaniel at, john at