我正在开发一个使用 C# 的ANTLR解析器库的项目。我已经建立了一个语法来解析一些文本,并且效果很好。但是,当解析器遇到非法或意外标记时,它会抛出许多异常之一。问题是在某些情况下(不是全部)我的 try/catch 块不会捕获它,而是作为未处理的异常停止执行。
对我来说,问题是除了在我的完整代码中之外,我无法在其他任何地方复制这个问题。调用堆栈显示异常肯定发生在我的 try/catch(Exception) 块中。我唯一能想到的是,在我的代码和引发异常的代码之间发生了一些 ANTLR 程序集调用,并且这个库没有启用调试,所以我无法单步执行。我想知道不可调试的程序集是否会抑制异常冒泡?调用堆栈如下所示;外部程序集调用在 Antlr.Runtime 中:
Expl.Itinerary.dll!TimeDefLexer.mTokens() 第 1213 行 C# Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken() + 0xfc 字节 Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer() + 0x22c 字节 Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.LT(int k = 1) + 0x68 字节 Expl.Itinerary.dll!TimeDefParser.prog() 第 109 行 + 0x17 字节 C# Expl.Itinerary.dll!Expl.Itinerary.TDLParser.Parse(string Text = "", Expl.Itinerary.IItinerary Itinerary = {Expl.Itinerary.MemoryItinerary}) 第 17 行 + 0xa 字节 C#
Parse() 中最底层调用的代码片段如下所示:
try {
// Execution stopped at parser.prog()
TimeDefParser.prog_return prog_ret = parser.prog();
return prog_ret == null ? null : prog_ret.value;
}
catch (Exception ex) {
throw new ParserException(ex.Message, ex);
}
对我来说,一个 catch (Exception) 子句应该已经捕获了任何异常。有什么理由不这样做吗?
更新:我用 Reflector 追踪了外部组件,没有发现任何螺纹迹象。该程序集似乎只是 ANTLR 生成代码的运行时实用程序类。抛出的异常来自 TimeDefLexer.mTokens() 方法,其类型为 NoViableAltException,它派生自 RecognitionException -> Exception。当词法分析器无法理解流中的下一个标记时,将引发此异常;换句话说,无效输入。应该会发生此异常,但是它应该已被我的 try/catch 块捕获。
此外,重新抛出 ParserException 与这种情况确实无关。这是一个抽象层,它在解析期间接受任何异常并转换为我自己的 ParserException。我遇到的异常处理问题永远不会到达那行代码。事实上,我注释掉了“throw new ParserException”部分,仍然得到相同的结果。
还有一件事,我修改了原来的 try/catch 块,改为捕获 NoViableAltException,消除了任何继承混淆。我仍然收到相同的结果。
有人曾经建议,有时 VS 在调试模式下捕获处理的异常时过于活跃,但这个问题也发生在发布模式下。
伙计,我还是很难过!我之前没有提到它,但我正在运行 VS 2008,我所有的代码都是 3.5。外部程序集为 2.0。此外,我的一些代码子类化了 2.0 程序集中的一个类。版本不匹配会导致此问题吗?
更新 2:我能够通过将 .NET 3.5 代码的相关部分移植到 .NET 2.0 项目并复制相同的场景来消除 .NET 版本冲突。在 .NET 2.0 中持续运行时,我能够复制相同的未处理异常。
我了解到 ANTLR 最近发布了 3.1。所以,我从 3.0.1 升级并重试。事实证明,生成的代码进行了一些重构,但在我的测试用例中出现了相同的未处理异常。
更新 3: 我在一个简化的 VS 2008 项目中复制了这个场景。随意下载并亲自检查该项目。我已经应用了所有很棒的建议,但还没有能够克服这个障碍。
如果您能找到解决方法,请分享您的发现。再次感谢!
谢谢,但是 VS 2008 会自动中断未处理的异常。另外,我没有 Debug->Exceptions 对话框。抛出的 NoViableAltException 完全是有意的,并且被设计为被用户代码捕获。由于未按预期捕获,因此程序执行会作为未处理的异常意外停止。
抛出的异常是从 Exception 派生的,并且 ANTLR 没有进行多线程。