我有一个ANTLR v4语法小工具,正在实现访客。
可以说这是一个简单的计算器,每个输入都必须以“;”结尾。
例如x = 4 + 5;
如果我不放;最后,它也可以正常工作,但是我得到了输出端。
line 1:56 missing ';' at '<EOF>'
似乎它可以找到规则,或多或少会忽略缺少的终端“;”。
我希望使用严格的错误或例外来代替此软信息。
输出是由行生成的
ParseTree树= parser.input()
有没有一种方法可以加强错误处理并检查这种错误?
答案 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);
}
});