Search code examples
javaantlr4visitor-pattern

Antlr4 generated java code visitor pattern confusion


When antlr generates java code for visitor pattern, we get a base visitor class.

public class YxBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements YxVisitor<T> {
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public T visitProgram(YxParser.ProgramContext ctx) { return visitChildren(ctx); }
}

I have a derived class called ASTBuilder from YxBaseVisitor. So when I need to use the ASTBuilder to visit the ParseTree node, I will call function

            ParseTree parseTreeRoot = parser.program();
            ASTBuilder astBuilder = new ASTBuilder(gScope);
            ASTRoot = (RootNode)astBuilder.visit(parseTreeRoot);

This piece of code calls the visit method of ASTBuilder, but ASTBuilder didn't define visit method, instead, it inherit visit from AbstractParseTreeVisitor, which is also generated by antlr.

However, the visit is define with return null;, and I didn't find other override of visit to distribute different types of ParseTree node.

How did the visit pattern work?


Solution

  • it inherit visit from AbstractParseTreeVisitor, which is also generated by antlr.

    AbstractParseTreeVisitor is not generated, it's part of the runtime library. YxVisitor and YxBaseVisitor are the ones that are being generated.

    However, the visit is define with return null;

    I'm not sure how you came to that conclusion, but that's not true. It's actually defined as return tree.accept(this); (source).

    Now, the accept method that's being called here will be overridden in each of the generated tree classes to call the corresponding visitFoo method in YxVisitor, e.g. ProgramContext.accept will be overridden to call YxVisitor.visitProgram(this) and that's how your visitProgram method ends up being called.