I\'m working on a project using the ANTLR parser library for C#. I\'ve built a grammar to parse some text and it works well. However, when the parser comes across an illeg
I can tell you what's happening here...
Visual Studio is breaking because it thinks the exception is unhandled. What does unhandled mean? Well, in Visual Studio, there is a setting in the Tools... Options... Debugging... General... "Enable Just My Code (Managed only)". If this is checked and if the exception propagates out of your code and out to a stack frame associated with a method call that exists in an assembly which is "NOT YOUR CODE" (for example, Antlr), that is considered "unhandled". I turn off that Enable Just My Code feature for this reason. But, if you ask me, this is lame... let's say you do this:
ExternalClassNotMyCode c = new ExternalClassNotMyCode();
try {
c.doSomething( () => { throw new Exception(); } );
}
catch ( Exception ex ) {}
doSomething calls your anonymous function there and that function throws an exception...
Note that this is an "unhandled exception" according to Visual Studio if "Enable Just My Code" is on. Also, note that it stops as if it were a breakpoint when in debug mode, but in a non-debugging or production environment, the code is perfectly valid and works as expected. Also, if you just "continue" in the debugger, the app goes on it's merry way (it doesn't stop the thread). It is considered "unhandled" because the exception propagates through a stack frame that is NOT in your code (i.e. in the external library). If you ask me, this is lousy. Please change this default behavior Microsoft. This is a perfectly valid case of using Exceptions to control program logic. Sometimes, you can't change the third party library to behave any other way, and this is a very useful way to accomplish many tasks.
Take MyBatis for example, you can use this technique to stop processing records that are being collected by a call to SqlMapper.QueryWithRowDelegate.
Regardless of whether the assembly has been compiled as a release build the exception should certainly 'bubble' up to the caller, there's no reason an assembly not being compiled in debug mode should have any affect on that.
I'd agree with Daniel is suggesting that perhaps the exception is occurring on a separate thread - try hooking the thread exception event in Application.ThreadException. This should be raised when any unhandled thread exception occurs. You could adapt your code thus:-
using System.Threading;
...
void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
throw new ParserException(e.Exception.Message, e.Exception);
}
...
var exceptionHandler =
new ThreadExceptionEventHandler(Application_ThreadException);
Application.ThreadException += exceptionHandler;
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);
}
finally {
Application.ThreadException -= exceptionHandler;
}
I'm not sure if I'm being unclear, but if so, I'm seeing the debugger halt execution with an "Unhandled Exception" of type NoViableAltException. Initially, I didn't know anything about this Debug->Exceptions menu item because MS expects you, at VS install time, to commit to a profile when you have no idea how they are different. Apparently, I was not on the C# dev profile and was missing this option. After finally debugging all thrown CLR exceptions, I was unfortunately unable to discover any new behavior leading to the reason for this unhandled exception issue. All the exceptions thrown were expected and supposedly handled in a try/catch block.
I reviewed the external assembly and there is no evidence of multithreading. By that, I mean no reference exists to System.Threading and no delegates were used whatsoever. I'm familiar with that constitutes instantiating a thread. I verify this by observing the Threads toolbox at the time of the unhandled exception to view there is only one running thread.
I have an open issue with the ANTLR folks so perhaps they've been able to tackle this issue before. I've been able to replicate it in a simple console app project using .NET 2.0 and 3.5 under VS 2008 and VS 2005.
It's just a pain point because it forces my code to only work with known valid parser input. Using an IsValid()
method would be risky if it threw an unhandled exception based on user input. I'll keep this question up to date when more is learned of this issue.
I don't get it...your catch block just throws a new exception (with the same message). Meaning that your statement of:
The problem is that in some cases (not all) that my try/catch block won't catch it and instead stops execution as an unhandled exception.
is exactly what is expected to happen.
Steve Steiner is correct that the exception is originating in the antlr library, passing through the mTokens() method and being caught in the antlr library. The problem is that this method is auto-generated by antlr. Therefore, any changes to handle the exception in mTokens() will be overwritten when your generate your parser/lexer classes.
By default, antlr will log errors and try to recover parsing. You can override this so that the parser.prog() will throw an exception whenever an error is encountered. From your example code i think this is the behaviour you were expecting.
Add this code to your grammer (.g) file. You will also need to turn off "Enable Just My Code" in the debugging menu.
@members {
public override Object RecoverFromMismatchedSet(IIntStream input,RecognitionException e, BitSet follow)
{
throw e;
}
}
@rulecatch {
catch (RecognitionException e)
{
throw e;
}
}
This is my attempt at a C# version of the example given in the "Exiting the recogniser on first error" chapter of the "Definitive ANTLR Reference" book.
Hope this is what you were looking for.
have you tried to print (Console.WriteLine()) the exception inside the catch clause, and not use visual studio and run your application on console?