天天看點

Antlr4的分析錯誤處理

(前文 通用型的中文程式設計語言探讨之一: 聯考

, 即使是這"第一步", 即使一切順利達到列出的功能恐怕也需要個人數年的業餘時間. 看到不少乎友都遠更有資本和實力更快速地完成這一工程. 希望随時告知類似項目, 省得在下作無用功)

初步打算用Antlr4生成Java實作的詞文法分析器, 主要是出于減少工作量的考慮, 但相應的需要深入學習這個工具. 根據至今看到的相關文檔以及Antlr項目本身, 感覺還蠻實用, 可持續性也不錯, 這些學習應該不會白費.

之前沒有實驗過它對錯誤文法的處理. 本文實作了

程式設計語言試驗之Antlr4+Java實作"圈2" 的Visitor版本. 再添加了定制的詞法文法錯誤處理. 源碼在 program-in-chinese/quan5 文法最簡單, 隻包含一個數:

grammar 圈5;
程式   : T數;

T數 : [0-9]+ ;
T空白     : [ \n\t]+ -> skip;           

定制的文法錯誤處理器, 隻有報告功能:

public class 文法錯誤監聽器 extends BaseErrorListener {

  @Override
  public void syntaxError(Recognizer<?, ?> 識别器, Object 問題符号, int 行, int 字元在行中位置, String 資訊,
      RecognitionException 例外) {
    List<String> 規則棧 = ((Parser) 識别器).getRuleInvocationStack();
    Collections.reverse(規則棧);
    System.err.println("[文法錯誤] 規則棧: " + 規則棧);
    System.err.println("行" + 行 + "列" + 字元在行中位置 + "非法符号: " + 問題符号 + ". 原始原因:" + 資訊);
  }

}           

下面是為文法分析器添加定制的錯誤分析(先除去預設的錯誤監聽器):

圈5Parser 文法分析器 = new 圈5Parser(new CommonTokenStream(詞法分析器));
    文法分析器.removeErrorListeners();
    文法分析器.addErrorListener(文法錯誤處理);           

類似的也可以為詞法分析器添加錯誤處理器. 其中為了取得錯誤的詞, 沒有找到現成的接口, 于是摘取了它源碼一部分. 初步的感覺是, 雖然API不一定很完善(很有可能是自己不熟悉工具導緻的), 但不少公開屬性可以比較友善定制:

public class 詞法錯誤監聽器 extends BaseErrorListener {

  @Override
  public void syntaxError(Recognizer<?, ?> 識别器, Object 問題符号, int 行, int 字元在行中位置, String 資訊,
      RecognitionException 例外) {
    Lexer 詞法分析器 = (Lexer)識别器;
    
    // 摘自org.antlr.v4.runtime.Lexer.notifyListeners
    String 文本 = 詞法分析器._input.getText(Interval.of(詞法分析器._tokenStartCharIndex, 詞法分析器._input.index()));
    String 錯詞 = 詞法分析器.getErrorDisplay(文本);

    System.err.println("[詞法錯誤] 行" + 行 + "列" + 字元在行中位置 + "錯誤詞: " + 錯詞);
  }

}           

下面是一個文法有誤的檔案:

a           

分析後的報錯輸出:

[詞法錯誤] 行2列3錯誤詞: a
[文法錯誤] 規則棧: [程式]
行2列4非法符号: [@0,5:4='<EOF>',<-1>,2:4]. 原始原因:missing T at '<EOF>'           

2018-01-11