上下文相关的 ANTLR4 ParseTreeVisitor 实现

Context dependent ANTLR4 ParseTreeVisitor implementation

我正在开展一个项目,我们将 大量 (超过 12000)个视图从 Oracle 迁移到 Hadoop/Impala。我已经编写了一个小的 Java 实用程序来从 Oracle 中提取视图 DDL,并希望使用 ANTLR4 遍历 AST 并生成一个 Impala 兼容的视图 DDL 语句。

大部分工作相对简单,只涉及将一些 Oracle 特定的语法怪癖重写为 Impala 风格。但是,我面临一个问题,我不确定我是否有最佳答案:我们有许多特殊情况,在多个嵌套函数调用中提取日期字段中的值。例如,以下从日期字段中提取日期:

TO_NUMBER(TO_CHAR(d.R_DATE , 'DD' ))

我有一个为 Oracle SQL 声明的 ANTLR4 语法,因此当它到达 TO_NUMBERTO_CHAR 时也会得到访问者回调,但我想对这个特例。

除了外层函数实现handler方法,然后通过手动遍历嵌套结构看看有没有别的办法

我在生成的访客中有类似的东西 class:

    @Override
    public String visitNumber_function(PlSqlParser.Number_functionContext ctx) {

        // FIXME: seems to be dodgy code, can it be improved? 
        String functionName = ctx.name.getText();
        if (functionName.equalsIgnoreCase("TO_NUMBER")) {

            final int childCount = ctx.getChildCount();
            if (childCount == 4) {

                final int functionNameIndex = 0;
                final int openRoundBracketIndex = 1;
                final int encapsulatedValueIndex = 2;
                final int closeRoundBracketIndex = 3;

                ParseTree encapsulated = ctx.getChild(encapsulatedValueIndex);
                if (encapsulated instanceof TerminalNode) {
                    throw new IllegalStateException("TerminalNode is found at: " + encapsulatedValueIndex);
                }

                String customDateConversionOrNullOnOtherType =
                        customDateConversionFromToNumberAndNestedToChar(encapsulated);

                if (customDateConversionOrNullOnOtherType != null) {
                    // the child node contained our expected child element, so return the converted value
                    return customDateConversionOrNullOnOtherType;
                }
                // otherwise the child was something unexpected, signalled by null
                // so simply fall-back to the default handler
            }
        }

        // some other numeric function, default handling
        return super.visitNumber_function(ctx);
    }

    private String customDateConversionFromToNumberAndNestedToChar(ParseTree parseTree) {
        // ...
    }

对于遇到同样问题的任何人,要走的路似乎是:

  1. 更改语法定义并引入自定义子类型 嵌套函数的封装表达式。

  2. 然后,我就可以准确地在 Parse 树的所需位置挂接处理。

  3. 使用第二个自定义 ParseTreeVisitor 捕获函数调用的值并将其余子树的处理委托给主树,"outer" ParseTreeVisitor

一旦第二个自定义 ParseTreeVisitor 完成了对所有子 ParseTree 的访问,我就获得了所需的上下文信息,并且正确访问了所有子树。