如何捕捉小错误?
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);
}
});
我有一点 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);
}
});