如何捕捉小错误?

时间:2018-08-04 06:26:33

标签: antlr antlr4

我有一个ANTLR v4语法小工具,正在实现访客。

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

  

例如x = 4 + 5;

如果我不放;最后,它也可以正常工作,但是我得到了输出端。

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

似乎它可以找到规则,或多或少会忽略缺少的终端“;”。

我希望使用严格的错误或例外来代替此软信息。

输出是由行生成的

  

ParseTree树= parser.input()

有没有一种方法可以加强错误处理并检查这种错误?

2 个答案:

答案 0 :(得分:2)

是的,可以。像您一样,我希望对用户提交的文本进行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类。它继承自DefaultErrorStrategy类,并且覆盖了两个“ 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方法设置为空可防止正常的“出错后重新同步”行为发生。

最后一步是捕获所有LEXER错误。为此,您可以创建一个新的类,该类继承自您的主要lexer类;它将像这样覆盖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);
    }
}

有了这个适当的位置,在词法化步骤中甚至会发现很小的错误。有了这两个重写的类,我的应用程序的用户必须提供绝对完美的语法才能成功执行。你去了!

答案 1 :(得分:0)

由于我的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);
            }
        });