使用ANTLR进行Java表达式解析

本教程将介绍使用ANTLR进行Java表达式解析的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

问题描述

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

    它似乎无处不在地用于这类事情

    开源替代方案似乎不多

    不久前我实际上曾尝试编写自己的通用解析器,但最终放弃了。那东西很难。

我不得不说,在我感觉自己阅读和尝试了很多不同的东西(无论怎么,比我预期的要多)之后,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表达式解析的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。

0
没有账号?注册  忘记密码?