Trouble with anon delegates.

Pragma ericanderton at yahoo.removeme.com
Wed Jan 17 12:02:34 PST 2007


BCS wrote:
> Pragma wrote:
>> BCS wrote:
>>
>>> Reply to Pragma,
>>>
>>>>
>>>> auto rule = ws >> '(' >> +Argument >> ')' >> { writefln("args
>>>> parsed"); };
>>>>
>>>> It works fine for this kind of stuff, but once you graduate beyond
>>>> there and want to bind terminals to class members, you need the
>>>> ability to perform filtering and aritmetic on them.  But once you do
>>>> that, you find that your stack frame is all out of whack. :(
>>>
>>>
>>> I tend to use structs for that kind of thing. They entail less 
>>> overhead than classes.
>>
>>
>> I would have done the same, but I'm making heavy use of polymorphism 
>> to get the operators to work as expected.  However, that could be 
>> refactored into a struct-oriented design with some clever templates 
>> and mixins to emulate inheritance.
> 
> Ah, you must be doing something more complicated than I was thinking of. 

Yea, sorry to talk so much about something that is basically vaporware.  I've learned to be cautious of releasing stuff 
without having completely worked the kinks out of it myself - if it's at all useful, poor quality offerings breed a 
contemptible support situation for everyone involved (especially for me).

But since the cat's out of the bag, I'll explain what I'm talking about.  Basically, it's something like this 
(paraphrased for clarity):

abstract class Expr{
   Expr opShr(Expr expr){ return new AndGroup(this,expr); }
   Expr opShr(String value){ return opShr(new Terminal(value)); }

   Expr opOr(Expr expr){ return new OrGroup(this,expr); }
   Expr opOr(String value){ return opOr(new Terminal(value)); }

   Expr opPlus(Expr expr){ return new Multiple(this); }
   Expr opNeg(Expr expr){ return new Optional(this); }

   bool Parse(IScanner scanner);
}
class Terminal: Expr{}
class Optional: Expr{}
class Multiple: Expr{}
class AndGroup: Expr{}
class OrGroup: Expr{}

... and so on, plus a few shims to get some expressions to work.

So that:
Expr ws =  /* defined elsewhere */
Expr rule = ws >> 'hello' >> ws >> 'world';

is equivalent to:
Expr rule = new AndGroup(
   ws,
   new AndGroup(
     new Terminal('hello'),
     new AndGroup(
       ws,
       new Terminal('world')
     )
   )
);

The various operators are overridden in the sub-classes so optimizations can be made.  For instance, AndGroup and 
OrGroup will maintain a list of terms such that the redundant nesting in the above never happens.  Now, to bring it back 
to where I started, I had some methods on Expr that did this:

Expr opShr(void delegate() predicate){ return opShr(new PredicateExpr(predicate)); }
Expr opOr(void delegate() predicate){ return opOr(new PredicateExpr(predicate)); }

... but that's dangerous for the reasons we discussed earlier.

FWIW, another limitation I ran into is that D offers no static operator overloads in the global scope, so we can't get 
operators to generate templates in the same way that Spirit can in C++.  Granted, that's a small limitation, but a 100% 
static parser /might/ help somewhat.

> I often find myself using the pattern of a struct that is used in 
> exactly one place:
> 
> struct S
> {
>     int i;
>     int j(){return i}
> }
> 
> auto s = new S;
> s.i=2;
> return &s.j
> 
> this can be done with a class, but it has some more overhead.
> 
> class C
> {
>     int i;
>     this(int k){i=k;}
>     int j(){return i}
> }
> 
> return &(new C(1)).j
> 
>>>
>>> (Where's the 2.0 wish list?  <g> )
>>>
>>
>> You mean, we dont' have one yet?!
>>
> 
> Not that I know of :-|


-- 
- EricAnderton at yahoo


More information about the Digitalmars-d-learn mailing list