I'm writing a parser for an old proprietary report specification with ANTLR and I'm currently trying to implement a visitor of the generated parse tree extending the autogenerated abstract visito class.
I have little experience both with ANTLR (which I learned only recently) and with the visitor pattern in general, but if I understood it correctly, the visitor should encapsulate one single operation on the whole data structure (in this case the parse tree), thus sharing the same return type between each Visit*() method.
Taking an example from The Definitive ANTLR 4 Reference book by Terence Parr, to visit a parse tree generated by a grammar that parses a sequence of arithmetic expressions, it feels natural to choose the int return type, as each node of the tree is actually part of the the arithmetic operation that contributes to the final result by the calculator.
Considering my current situation, I don't have a common type: my grammar parses the whole document, which is actually split in different sections with different responsibilities (variable declarations, print options, actual text for the rows, etc...), and I can't find a common type between the result of the visit of so much different nodes, besides object of course.
I tried to think to some possible solutions:
I firstly tried implementing a stateless visitor using
objectas the common type, but the amount of type casts needed sounds like a big red flag to me. I was considering the usage of JSON, but I think the problem remains, potentially adding some extra overhead in the serialization process.I was also thinking about splitting the visitor in more smaller visitors with a specific purpose (get all the variables, get all the rows, etc.), but with this solution for each visitor I would implement only a small subset of the method of the autogenerated interface (as it is meant to support the visit of the whole tree), because each visiting operation would probably focus only on a specific subtree. Is it normal?
Another possibility could be to redesign the data structure so that it could be used at every level of the tree or, better, define a generic specification of the nodes that can be used later to build the data structure. This solution sounds good, but I think it is difficult to apply in this domain.
A final option could be to switch to a stateful visitor, which incapsulates one or more builders for the different sections that each
Visit*()method could use to build the data structure step-by-step. This solution seems to be clean and doable, but I have difficulties to think about how to scope the result of each visit operation in the parent scope when needed.
What solution is generally used to visit complex ANTLR parse trees?