[antlr-interest] Return values from listener methods (was "Appropriate use of honey badger listeners")

Sam Harwell sam at tunnelvisionlabs.com
Thu Jan 12 13:59:08 PST 2012


I've used listeners for several tasks in ANTLRWorks 2 and haven't
encountered any problems in returning values which I wasn't able to work
around in a clean manner.

For the case of expressions like your example below, once you realize that
exitRule behaves as an RPN calculator you just use a simple stack to track
computed results. For other tasks I've used stacks, flags, counters, or
whatever else was relevant to the specific task.

For a simple calculator, you might have this:

public void exitRule(multContext context) {
    double right = stack.pop();
    double left = stack.pop();
    stack.push(left * right);
}

If you don't mind reversing the operand order of a commutative operator, you
could also write:

public void exitRule(multContext context) {
    stack.push(stack.pop() * stack.pop());
}

--
Sam Harwell
Owner, Lead Developer
http://tunnelvisionlabs.com

-----Original Message-----
From: Terence Parr [mailto:parrt at cs.usfca.edu] 
Sent: Wednesday, January 11, 2012 6:40 PM
To: ANTLR Interest Mailing List
Subject: [antlr-interest] Appropriate use of honey badger listeners

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