微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ANTLR查找和捕获解析错误的最佳做法

如何解决ANTLR查找和捕获解析错误的最佳做法

此问题与如何从Visual Studio中的C#中的ANTLR4解析器中获取错误消息有关。我向ANTLR解析器提供了一个已知的错误输入字符串,但是在(错误)解析过程中没有看到任何错误或解析异常。因此,我的异常处理程序没有机会在解析期间创建和存储任何错误消息。

我使用的是正确的ANTLR4语法,因为我可以看到图形化的正确解析操作输出,并带有Visual Studio Code的ANTLR扩展。我知道生成的解析器代码是正确的,因为我可以正确编译它而不会出错,可以覆盖基层访问者类,并使用覆盖的VisitXXX方法从解析树中打印出各种信息。

这时,我正在运行一个非常简单的测试用例,该用例提供了错误的输入字符串,并在我存储的解析错误列表中查找非零计数。我对错误处理代码很有信心,因为它可以在另一种语法下以类似的方式工作。但是错误处理代码必须捕获一个解析异常才能生成错误消息。 (也许这不是捕获/检测解析错误(例如意外令牌或输入流中的其他错误)的正确方法。)

这是我用来替换认词法分析器和解析器错误侦听器的代码

 // install the custom ErrorListener into the parser object
 sendLexer.RemoveErrorListeners();
 sendLexer.AddErrorListener(MyErrorListener.Instance);
 Parser.RemoveErrorListeners();
 Parser.AddErrorListener(MyErrorListener.Instance);

我已经附上了图形输出的屏幕快照,显示了输入字符串中存在意外的标记

Q1。为什么意外的标记不会引起我可以用异常处理程序捕获的解析异常?所有解析错误都应该引发异常吗?

第二季度。如果捕获解析异常不是正确的方法,有人可以建议我采取一种策略来检测意外的令牌错误(或其他不会引发解析异常的错误)吗?

Q3。是否有捕获或查找解析错误的最佳实践方法,例如从遍历解析树时生成错误,而不是希望ANTLR为每个意外令牌抛出解析异常? (我想知道意外令牌是否应该生成解析异常,而不是恰好包含意外令牌的产生和合法的语法分析树?如果是这样,它们是否只是在语法分析树中显示为意外子级?)

谢谢。

屏幕截图显示了(故意)错误的输入字符串中的意外令牌以触发错误

enter image description here

更新:

当前,解析器和单元测试正在运行。如果我在解析器中输入了错误的输入字符串,则认的解析器错误侦听器会生成适当的错误消息。但是,当我安装自定义错误侦听器时,永远不会调用它。我不知道为什么在未安装自定义错误侦听器的情况下看到错误消息时为什么没有调用它。

我现在正在使用解析器和单元测试。当我注入错误的输入字符串时,认的解析错误侦听器会打印出一条消息。但是,当我安装自定义错误侦听器时,它永远不会被调用。 1)永远不会命中错误侦听器中的断点,并且2)(因此)不会收集或打印错误消息。

这是我对ParseText进行单元测试调用的C#代码

// the unit test
public void ModkeyComboThreetest() {
  SendKeysHelper.ParseText("this input causes a parse error);
  Assert.AreEqual(0,ParseErrors.Count);


// the helper class that installs the custom error listener
public static class SendKeysHelper {
  public static List<string> ParseErrorList = new List<string>();
  public static MyErrorListener MyErrorListener;

  public static SendKeysParser ParseText(string text) {
    ParseErrors.Clear();
    try {
      var inputStream = new AntlrInputStream(text);
      var sendLexer = new SendKeysLexer(inputStream);
      var commonTokenStream = new CommonTokenStream(sendLexer);
      var sendKeysParser = new SendKeysParser(commonTokenStream);
      Parser = sendKeysParser;

      MyErrorListener = new MyErrorListener(ParseErrorList);
      Parser.RemoveErrorListeners();
      Parser.AddErrorListener(MyErrorListener);

      // parse the input from the starting rule
      var ctx = Parser.toprule();
      if (ParseErrorList.Count > 0) {
        Dprint($"Parse error count: {ParseErrorList.Count}");
      }
 ...
}


// the custom error listener class
public class MyErrorListener : BaseErrorListener,IAntlrErrorListener<int>{
  public List<string> ErrorList { get; private set; }

  // pass in the helper class error list to this constructor
  public MyErrorListener(List<string> errorList) {
    ErrorList = errorList; 
  }

  public void SyntaxError(IRecognizer recognizer,int offendingSymbol,int line,int offset,string msg,RecognitionException e) {
    var errmsg = "Line " + line + ",0-offset " + offset + ": " + msg;              

    ErrorList.Add(errmsg);
  }
}

因此,我仍在尝试回答有关如何从失败的解析中获取错误信息的原始问题。安装时没有语法错误,1)错误消息消失了(建议已安装我的自定义错误侦听器),但是2)我的自定义错误侦听器SyntaxError方法调用注册错误

或者,或者,我将认的错误侦听器保留在原处,并添加我的自定义错误侦听器。在调试器中,我可以看到它们都已在解析器数据结构中注册。发生错误时,将调用认侦听器,但不会调用我的自定义错误侦听器(这意味着自定义侦听器中的断点不会被命中)。除了我的自定义错误侦听器似乎没有被调用之外,单元测试中没有语法错误或操作错误

即使我可以在解析器数据结构中看到它,对自定义侦听器的引用也可能以某种方式损坏或无法正常工作。或者,也许正在调用我的自定义侦听器的基类版本。很奇怪。

更新

主题的有用讨论/答案由于某种原因被删除。它为编写用于ANTLR4的自定义错误侦听器和错误策略提供了很多有用的信息。

我在ANTLR4 errors not being reported to custom lexer / parser error listeners处提出了第二个问题,该问题提出了为什么我无法从ANTLR4中获取错误消息的根本原因。但是第二个问题并未解决本文的主要问题,即最佳实践。我希望删除此线程的管理员将其删除以使最佳做法信息再次可见。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。