当我尝试添加自定义错误消息时,ANTLR 将有用的错误消息转换为 "no viable alternative"

ANTLR turns useful error messages into "no viable alternative" when I try to add custom error messages

我正在为一种深奥的编程语言编写 ANTLR 语法。我正在尝试添加自定义错误消息,这些消息将在编写某些形式的语法时输出。

这是一个MCVE:

grammar Foo;

OPEN_BRACE: '{';
CLOSE_BRACE: '}';
SEMI_COLON: ';';
PERIOD: '.';
WS: ' ' -> skip;
NOOP: 'noop';

statements
    : NOOP
    | NOOP SEMI_COLON statements
    // other kind of statements
    ;

program
    : OPEN_BRACE
      statements
      CLOSE_BRACE
      EOF

假设我想在 programSEMICOLON 结尾或大括号中没有 statements 时输出自定义错误消息。在 this answer 之后,我添加了一些错误选项:

program
    : OPEN_BRACE
      statements
      CLOSE_BRACE
      EOF
    | invalidPrograms
    ;

invalidPrograms
    : OPEN_BRACE
      statements
      CLOSE_BRACE
      SEMI_COLON
      EOF { notifyErrorListeners($SEMI_COLON, "program must not end with semicolon!", null); }
    | OPEN_BRACE
      CLOSE_BRACE
      EOF { notifyErrorListeners($OPEN_BRACE, "program must have at least one statement!", null); }
    ;

然后我使用 ErrorListener 来收集解析器和词法分析器生成的所有错误。

这有效,但它也使 ANTLR 生成的其他默认错误消息全部变成一条“没有可行的替代方案”消息。例如,如果我尝试解析语法无效的:

{noop

在我添加错误选项之前,它会产生一个非常有用的错误消息:

line 1:5 missing '}' at '<EOF>'

或者如果我写

{noop.}

错误消息说:

line 1:5 extraneous input '.' expecting '}'

描述性很强。但是,如果我添加错误选项,错误消息将变为:

line 1:5 no viable alternative at input...

这是不可取的。我怎样才能保留良好的错误消息,同时仍然使用错误替代方法?

通过添加这些规则,您无意中破坏了 ANTLR 错误报告和错误恢复的某些功能(通过添加对解析器“有效”的规则,特别是通过使 <EOF>有效)。

一般来说,您尝试添加的两个示例通常都会被视为语义错误。最好通过使用侦听器或访问器评估解析器树来在您自己的代码中处理这些问题。

引入规则来匹配特定的错误语法以促进生成更多 user-friendly 错误消息可能是有效的,但您必须小心避免像这样破坏解析器错误恢复。

一般来说,您需要一个相对“接受”但在正确解释您的输入时毫不含糊的解析器。然后,您可以从该解析树中查找您已识别的语义错误。 (将“尽可能多的”放入语法中是一种常见的诱惑,但这可能会适得其反(如您所见))