ANTLR4错误未报告给自定义词法分析器/解析器错误侦听器

问题描述

这个问题是关于如何向自定义词法分析器和解析器错误侦听器报告不同类型的ANTLR4词法分析器错误。从我的实验来看,似乎并非所有ANTLR4错误都在内部报告给认和自定义词法分析器/解析器错误侦听器。某些ANTLR4错误仅在控制台上报告。因此,我无法以编程方式检测到此类错误

示例

我在Visual Studio(C#)中有两个有效的语法(一个简单,一个复杂)和一个常见的ANTLR4安装程序。在下面的所有示例中,我唯一要做的更改是1)输入字符串错误,以及2)我使用的语法。所有其他代码(单元测试,注册错误侦听器的帮助程序类和自定义错误列表程序类)保持完全相同,未被触动。一切都会按预期进行重新生成,编译和执行(本文中的问题除外)。

我有一个正常工作的自定义错误侦听器,将它添加到lexer和解析器错误侦听器列表中,如下所示。我不删除认(控制台输出)侦听器,因为我想知道何时触发任何错误

  // add my custom ErrorListener (same object) into the lexer and parser error listener lists
  hellolexer.AddErrorListener(MyErrorListener.Instance);
  Parser.AddErrorListener(MyErrorListener.Instance);

当我给第一个简单语法错误的输入时,我同时从认词法分析器侦听器和自定义词法分析器侦听器中收到错误消息,如下所示。由此得出的结论是,我的自定义列表器可以正常工作,并且已正确安装到通用代码中。

Using Hello grammar and bad input.
Bad input: "h9ell%[o world"
Both the custom and default lexer error listeners were invoked.
My custom LEXER error listener printed the first three errors.
My custom PARSER error listener printed no errors.
The default error listener printed the other four errors.

A lexer or parser error occurred.
Custom error listener errors:
Line 1,0-offset1: token recognition error at: '9' '9ell%[o world'
Line 1,0-offset5: token recognition error at: '%' '%[o world'
Line 1,0-offset6: token recognition error at: '[' '[o world'

Default error listener console errors:
line 1:1 token recognition error at: '9'
line 1:0 mismatched input 'h' expecting 'hello'
line 1:5 token recognition error at: '%'
line 1:6 token recognition error at: '['

请注意已成功向认侦听器和自定义侦听器报告的词法分析器错误的类型。他们两个都报告token recognition错误,但是只有认的词法分析器错误侦听器报告mismatched input错误

现在,使用输入错误的第二个(更复杂的)工作语法,我会生成另一种类型的错误。我不知道这是词法分析器错误,解析器错误还是某种特殊类型的错误。但是以下输出显示错误侦听器获取了消息,但是我的自定义词法分析器和解析器错误侦听器均未调用

Using SendKeys grammar and a bad input string.
Bad input: "h9ell%[o world"
The custom error listener was not invoked (breakpoint not hit).
The same custom error listener instance was registered for both lexer and parser.

Default error listener console errors:
line 1:14 extraneous input '<EOF>' expecting {'(',']',LCOMMA,LCARET,...}

上面的输出表明调用代码没有沿着已安装的lexer / parser错误侦听器的列表移动,以全部调用它们。相反,我猜认的错误处理程序是直接被调用的吗?

请注意认侦听器报告的(lexer?parser?)错误类型:“ extraneous input。”

一些进一步的实验表明,以下错误均未传递给我的自定义词法分析器或解析器侦听器:

- extraneous input <EOF> 
- no viable alternative input
- mismatched input (from the first example)
- there may also be others that I don't kNow about

SendKeys grammar bad input "h9ell%[o world"
line 1:14 extraneous input '<EOF>' expecting {'(',SendKeys grammar bad input "h9ell%)o world"
line 1:6 no viable alternative at input '%)'

SendKeys grammar bad input "alt-ctl-shf-c"
line 1:18 no viable alternative at input 'alt-ctl-'

Q1。如果发生错误时未调用我正在工作的注册词法分析器和解析器错误侦听器,如何以编程方式接收有关此类错误错误通知

第二季度。如果无法通过已注册错误侦听器接收通知(因为它们从未被调用过),那么是否有其他方法可以在解析过程中以编程方式检测到错误的输入字符串?

谢谢

更新

根据要求,这里是简单语法,单元测试,解析器帮助器类和自定义错误侦听器的完整代码。这应该足以重现本文中显示的第一组错误消息。

我正在VStudio 16.7.5中使用以下Nuget软件包:

Antlr4 4.6.6
Antlr4.Code.Generator 4.6.6
Antlr4.Runtime 4.6.6

grammar Hello;

// match one or more tokenpairs
toprule  : (tokenpair)+ EOF ;

// a tokenpair has one child rule and one terminal token ID
tokenpair : helloworld ID ;

// this rule has two terminal tokens
helloworld : 'hello' 'world' ;

// ID is upper or lower characters and underscore
ID : [a-zA-Z_]+ ;

// skip all whitespace characters
WS : [ \t\r\n]+ -> skip ;


  [TestMethod()]
  public void MyParserHelpertest() {
    MyParserHelper.ParseText("h9ell%[o world");
    //MyParserHelper.ParseText("ctl-alt-shf-a alt-ctl-shf-c");
    if (MyParserHelper.ParSEOk) {
      Dprint($"No custom lexer or parse errors were received.\n");
    }
    else {
      MyParserHelper.PrintErrors();
      Dprint($"\nDefault error listener console errors:");
    }
  }

 public static void PrintErrors() {
     Console.WriteLine("Custom listener lexer or parser errors:");
     foreach (var errstring in ParseErrors) {
         Console.WriteLine(errstring);
     }
 } 

public static class MyParserHelper
{
  public static bool ParSEOk = true;
  public static List<string> ParseErrors = new List<string>();
  public static HelloParser Parser;

  public static HelloParser ParseText(string text) {
    try {
      var inputStream = new AntlrInputStream(text);
      var hellolexer = new Hellolexer(inputStream);
      var commonTokenStream = new CommonTokenStream(hellolexer);
      var helloParser = new HelloParser(commonTokenStream);
      Parser = helloParser;

      // install the custom ErrorListener into the lexer and parser 
      //hellolexer.RemoveErrorListeners();
      hellolexer.AddErrorListener(MyErrorListener.Instance);
      //Parser.RemoveErrorListeners();
      Parser.AddErrorListener(MyErrorListener.Instance);

      var ctx = Parser.toprule();
      if (ParseErrors.Count > 0) 
        Console.WriteLine("A lexer or parser error occurred.");
    }
    catch (Exception ex) {
      // each time a parse error occurs,add it to the error list
      ParSEOk = false;
      ParseErrors.Add(ex.Message);
    }

    return Parser;
  }


public class MyErrorListener : BaseErrorListener,IAntlrErrorListener<int>
{
  public static readonly MyErrorListener Instance = new MyErrorListener();

  public void SyntaxError(IRecognizer recognizer,int offendingSymbol,int line,int offset,string msg,RecognitionException e) {
    // build an error message from the input stream
    // the stream Could be a whole file,so only print what you need 
    var input = recognizer.InputStream.ToString();
    var maxLength = Math.Min(20,input.Length - offset);
    var badtoken = input.Substring(offset,maxLength);

    var errmsg = "Line " + line + ",0-offset" + offset + ": " + msg + $" '{badtoken}'";
    MyParserHelper.ParseErrors.Add(errmsg);
    MyParserHelper.ParSEOk = false;
  }
}

要使Visual Studio自动重新编译语法文件生成词法分析器/解析器文件,请将VS中的语法文件属性设置为下图所示。

enter image description here

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)