The parse tree listener (or listener) is a class that implements callback methods that are called by the parser when it creates the parse tree. You can overwrite this class to get information when the parser enter or exit a rule (ie as found a pattern)
Antlr - Parse Tree VisitorUse mainly when the code is spread around many parts. The listener can also be used to compile but only when the parse tree is created. There is therefore no control on order and/or context.
Here is quote from the book that I think is relevant:
The biggest difference between the listener and visitor mechanisms is that listener methods are called by the ANTLR-provided walker object, whereas visitor methods must walk their children with explicit visit calls. Forgetting to invoke visit() on a node’s children means those subtrees don’t get visited.
In visitor pattern you have the ability to direct tree walking while in listener you are only reacting to the tree walker.
If you plan to directly use the parser output for interpretation, the visitor is a good choice. You have full control of the traversal, so in conditionals only one branch is visited, loops can be visited n times and so on.
If you translate the input to a lower level, e.g. virtual machine instructions, both patterns may be useful.
You might take a look at "Language Implementation Patterns", which covers the basic interpreter implementations.
I mostly use the visitor pattern, as it's more flexible.
There's another important difference between these two patterns: a visitor uses the call stack to manage tree traversals, whereas the listener uses an explicit stack allocated on the heap, managed by a walker. This means that large inputs to a visitor could blow out the stack, while a listener would have no trouble.
If your inputs could be potentially unbounded, or you might call your visitor very deep in a call tree, you should use a Listener, rather than a Visitor, or at least validate that the parse tree is not too deep. Some companies' coding practices discourage or even outright forbid non-tail recursion for this reason.
From the book, page 120.
Visitors work very well if we need application-specific return values because we get to use the built-in Java return value mechanism. If we prefer not having to explicitly invoke visitor methods to visit children, we can switch to the listener mechanism. Unfortunately, that means giving up the cleanliness of using Java method return values.
This is why I use visitors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With