本文介绍了使用ANTLR进行Java表达式解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用Java编写一个使用Java表达式解析的工具包。我想我应该试着使用ANTLR,因为

  1. 它似乎无处不在地用于这类事情
  2. 开源替代方案似乎不多
  3. 不久前我实际上曾尝试编写自己的通用解析器,但最终放弃了。那东西很难。

我不得不说,在我感觉自己阅读和尝试了很多不同的东西(无论如何,比我预期的要多)之后,ANTLR似乎非常难以使用。该API非常不直观--我从来不太确定我调用它是否正确。

尽管ANTLR教程和示例比比皆是,但我还没有找到任何涉及解析Java表达式的示例--其他人似乎都想解析整个Java文件。

我一开始是这样称呼它的:

        Java8Lexer lexer = new Java8Lexer(CharStreams.fromString(text));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        Java8Parser parser = new Java8Parser(tokens);
        ParseTree result = parser.expression();

但这不会解析整个表达式。例如,对于TEXT&QOOT;A.B&QOOT;,它将返回只包含&QOOT;A&QOOT;部分的结果,仅在它可以分析的第一个内容之后退出。

好的。因此我更改为:

        String input = "return " + text + ";";
        Java8Lexer lexer = new Java8Lexer(CharStreams.fromString(input));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        Java8Parser parser = new Java8Parser(tokens);
        ParseTree result = parser.returnStatement();
        result = result.getChild(1);

认为这会迫使它解析整个表达式,然后我可以只提取我关心的部分。这适用于像";a.b";这样的名称表达式,但是如果我试图解析像";a.bc(D)";这样的方法表达式,它会给出一个错误:

line 1:12 mismatched input '(' expecting '.'

有趣的是,a()a.b()a.b.c解析正常,但a.b.c()也会死,但也会出现相同的错误。

这里有没有ANTLR专家可能知道我做错了什么?

另外,上面的错误被打印到stderr,但是我在Result对象中找不到它,这让我相当困扰。我希望能够向输入表达式的用户显示该错误消息(尽管很模糊)--他们可能没有查看控制台,即使他们正在查看控制台,也没有上下文。有没有办法在我返回的结果中找到该信息?

非常感谢您的帮助。

ANTLR

对于expression这样的规则,一旦识别到表达式,推荐答案将停止分析。

您可以通过将`EOF添加到您的启动规则来强制它继续。

(您不想修改实际的`表达式规则,但可以添加如下规则:

expressionStart: expressions EOF;

然后您可以使用:

ParseTree result = parser.expressionStart();

这将强制ANTLR继续分析您的输入,直到它到达您的输入的末尾。


Re:rereturn Statement

当我通过IntelliJ中的ANTLR预览运行return a.b.c();时,我得到以下解析树:

稍微遵循一下语法规则,我就偶然发现了这些规则:

typeName: Identifier | packageOrTypeName '.' Identifier;

packageOrTypeName
    : Identifier
    | packageOrTypeName '.' Identifier
    ;

这两个规则都包含packageOrTypeName '.' Identifier的替代规则,这在我看来是有问题的。

在树中,我们看到primaryNoNewArray_lfno_primary:2,表示匹配此规则中的第二个选项:

primaryNoNewArray_lfno_primary
    : literal
    | typeName ('[' ']')* '.' 'class' // <-- trying to match this rule
    | unannPrimitiveType ('[' ']')* '.' 'class'
    | 'void' '.' 'class'
    | 'this'
    | typeName '.' 'this'
    | '(' expression ')'
    | classInstanceCreationExpression_lfno_primary
    | fieldAccess_lfno_primary
    | arrayAccess_lfno_primary
    | methodInvocation_lfno_primary
    | methodReference_lfno_primary
    ;

我现在没时间了,但我会继续关注的。在Java8Parser.g4中似乎不太可能出现这个明显的错误,但目前看起来肯定是一个错误。我不确定上下文会改变它的解析方式(按上下文,这意味着语法中本地调用returnStatement的位置)。

我尝试了此输入(从compilationUnit规则开始:

class Test {
    class A {
       public B  b;
    }
    class B {
        String c() {
            return "";
        }
    }
    String test() {
        A a = new A();
        return a.b.c();
    }
}

并且它可以正确解析(因此,我们没有在Java8Parser语法😔中发现重大错误):

尽管如此,这似乎不太对。

越来越近:

如果我从block规则开始,并用大括号({return a.b.c();})括起来,它可以很好地解析。

我同意这样的理论,即ANTLR需要更多的前瞻来解决歧义(&Q;&Q;&Q;)。

这篇关于使用ANTLR进行Java表达式解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-20 15:05