[antlr-interest] Appropriate use of honey badger listeners

Martijn Reuvers martijn.reuvers at gmail.com
Wed Jan 11 23:22:30 PST 2012


Hey guys,

For option 1:
I would suggest you add something on the parsercontext directly
instead of using a plain hashmap. It should be dynamic I think - and
be up to the user to set it. You could set a default implementation,
which 'underwater' could work with the suggested Map and is good
enough for most. But users are completely free to replace it.

E.g. use a marker interface for the 'storage' thing.

// Marker
interface Storage {

}

// Provide a default implementation, but which can be replaced by the
user if needed (e.g. when a parser starts).
class StorageImpl implements Storage {

   // Implementation is customer specific, whatever you please - you
can store in whatever way.
   // In most cases you do not need a map and just want to store
values directly (after all getStorage().setValue(..) /
getStorage().getValue() are always much faster than maps due to
hashing).

}

// Start of parse somewhere user can replace the default (by class,
MyStorage.class if you need it dynamically), or they just replace it
on the rules where needed while listening.
parserContext.replaceStorage(new MyCustomStorage())

Just some thoughts.

Cheers!
Martijn

On Thu, Jan 12, 2012 at 1:39 AM, Terence Parr <parrt at cs.usfca.edu> wrote:
> hi Kyle,
>
> I have 2 questions about the current listener mechanism:
>
> 1. How do we return values from listener methods so that we can do computations?
> 2. How do we alter a parse tree?
>
> For 2, I think we return a new tree as a return value and the parse tree walker will incorporate that into the tree if it sees a different tree come back. In other words, it will do something like this in the walker:
>
> newtree = listener.someEvent(oldtree);
> if ( newtree!=oldtree ) replace-oldtree-with-newtree;
>
> For 1, I don't have a great answer. To make this more concrete, imagine we have an expression rule and we want to use listener events to compute the value of an expression. So, instead of having actions in the grammar  like:
>
> e returns [int v]
>      : a=e '*' b=e {$v = $a.v * $b.v;}
>
> we would simply match it
>
> e : e '*' e -> mult …
>
> and then have listener events compute values. but where does of the listener object store the intermediate results of a subtree computation? Certainly we don't want to have to add "returns [int v]" to the grammar for every different paths we make over the parse tree. Without a return value from a listener event (which I want to use for tree rewriting), how do we get a value up the tree in a computation?  We can't really use temporary fields of the listener object because it's hard to tell which value gets associated with which listener method. we would need a temporary fields to hold result values from each listener. actually, I'm not even sure that would work. We need to associate result values with sub tree roots (i.e. contexts). In other words, we need a way to dynamically add fields to contexts for the specific purpose of a particular parse tree walk. One can imagine that I have a pass for computing the type of expression and another pass for computing the value. In both cases, I need result values for each subtree (type and then value).
>
> Maybe that is just a hash table from ctx node to value; Map<ParserRuleContext, Object>. maybe. That presents a few issues for me because I use hashCode/equals in a weird way for use with grammar analysis, but that would be the idea.
>
> class MyGListener extends BlankGListener {
>        Map<ParserRuleContext, Integer> results = …;
>
>        public void exitRule(AParser.multContext ctx) { results.put(ctx, results.get(ctx.a) * results.get(ctx.b)); }
>        public void exitRule(AParser.addContext ctx) { results.put(ctx, results.get(ctx.a) + results.get(ctx.b)); }
> }
>
> not very pretty in Java. Python would look better:
>
> results[ctx] = results[ctx.a] * results[ctx.b];
>
> This way we can associate any values we need to for any node, in effect, decorating the parse tree as needed.
>
> What do people think about the solution? is there a way I can automate some of this? I think that Python and Ruby would make short work of that because they allow dynamically adding fields (normally a horrible thing to do) ;) Is there a better way to do decorations in Java?
>
> Ter
>
> On Jan 11, 2012, at 1:49 PM, Kyle Ferrio wrote:
>
>> Excellent, congratulations and thank you.
>>
>> I just spent about half an hour playing with variations on A.g4 (since it
>> worked right out of the box I had to keep going...)  and this is really
>> nice.  This is the first time I've looked at the new-in-antlr listener
>> paradigm.  I will need a while to fully appreciate the doors this opens.
>> Honey Badger makes things easy, so I want to stay on his (?) good side.
>>
>> Q: how do you tell a boy Honey Badger from a girl Honey Badger?
>>
>> A: you don't.  they're both bad-ass.
>
> nice!
>
> Ter
>
> List: http://www.antlr.org/mailman/listinfo/antlr-interest
> Unsubscribe: http://www.antlr.org/mailman/options/antlr-interest/your-email-address


More information about the antlr-interest mailing list