如何捕捉小错误?

how to catch minor errors?

我有一点 ANTLR v4 语法,我正在用它实现一个访问者。

假设这是一个简单的计算器,每个输入都必须以“;”结尾。

e.g. x=4+5;

如果我不放;最后,它也能正常工作,但我得到了终端的输出。

line 1:56 missing ';' at '<EOF>'

似乎能找到规则,或多或少忽略了缺少的终端“;”。

我更喜欢严格的错误或异常而不是这些软信息。

输出由行

生成

ParseTree tree = parser.input ()

有什么方法可以加强错误处理并检查此类错误吗?

是的,你可以。和你一样,我想要 100% 完美地解析用户提交的文本,因此创建了一个严格的错误处理程序,即使是简单的错误也能防止恢复。

第一步是删除默认错误侦听器并添加您自己的 STRICT 错误处理程序:

 AntlrInputStream inputStream = new AntlrInputStream(stream);
 BailLexer lexer = new BailLexer(inputStream);  // TALK ABOUT THIS AT BOTTOM

 CommonTokenStream tokenStream = new CommonTokenStream(lexer);
 LISBASICParser parser = new LISBASICParser(tokenStream);
 parser.RemoveErrorListeners();                    // UNHOOK ERROR HANDLER
 parser.ErrorHandler = new StrictErrorStrategy();  // REPLACE WITH YOUR OWN
 LISBASICParser.CalculationContext context = parser.calculation();
 CalculationVisitor visitor = new CalculationVisitor();
 visitor.VisitCalculation(context);

这是我的 StrictErrorStrategy class。它继承自 DefaultErrorStrategy class 并覆盖两个 'recovery' 方法,这两个 'recovery' 方法可以恢复像分号错误这样的小错误:

public class StrictErrorStrategy : DefaultErrorStrategy
{
    public override void Recover(Parser recognizer, RecognitionException e)
    {
        IToken token = recognizer.CurrentToken;
        string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
        throw new Exception(message, e);
    }


    public override IToken RecoverInline(Parser recognizer)
    {
        IToken token = recognizer.CurrentToken;
        string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
        throw new Exception(message, new InputMismatchException(recognizer));
    }


    public override void Sync(Parser recognizer) { }
}

重写这两个方法允许您在出现任何解析器错误时停止(在这种情况下,在其他地方捕获异常)。将 Sync 方法设为空可以防止正常的 're-sync after error' 行为发生。

最后一步是捕获所有 LEXER 错误。您可以通过创建一个继承自主词法分析器 class 的新 class 来做到这一点;它像这样覆盖 Recover() 方法:

public class BailLexer : LISBASICLexer
{
    public BailLexer(ICharStream input) : base(input) { }

    public override void Recover(LexerNoViableAltException e)
    {
        string message = string.Format("lex error after token {0} at position {1}", _lasttoken.Text, e.StartIndex);
        BasicEnvironment.SyntaxError = message;
        BasicEnvironment.ErrorStartIndex = e.StartIndex;
        throw new ParseCanceledException(BasicEnvironment.SyntaxError);
    }
}

(编辑:在这段代码中,BasicEnvironment 是我在应用程序中用来保存设置、错误、结果等的高级上下文对象。因此,如果您决定使用它,请按照另一位 reader 在下方评论,或替换为您自己的 context/container。)

有了这个,即使是词法分析步骤中的小错误也会被捕获。有了这两个覆盖的 classes,我的应用程序的用户必须提供绝对完美的语法才能成功执行。给你!

因为我的 ANTLR 在 Java 我也在这里添加答案。但这与接受的答案是相同的想法。

        TempParser parser = new TempParser (tokens);
        parser.removeErrorListeners ();
        parser.addErrorListener (new BaseErrorListener ()       
        {
            @Override
            public void syntaxError (final Recognizer <?,?> recognizer, Object sym, int line, int pos, String msg, RecognitionException e) 
            {
                throw new AssertionError ("ANTLR - syntax-error - line: " + line + ", position: " + pos + ", message: " + msg);
            }
        });