Is it possible to throw an exception if the input isn't valid?
antlr4, c#, exception
Solution
@CoronA was right. The error happens in the lexer.. So, while I still think that creating an ErrorStrategy would be better, this is what actually worked for me and my goal of throwing an exception for undefined input.
First, I created a derived class that inherits from `BaseErrorListener` and implements `IAntlrErrorListener<T>`. The second part was my problem all along it seems. Because my visitor inherited from `FooBarBaseVistor<int>`, my error listener also needed to be of type to register it with my lexer.
class ThrowExceptionErrorListener : BaseErrorListener, IAntlrErrorListener<int>
{
//BaseErrorListener implementation; not called in my test, but left it just in case
public override void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
throw new ArgumentException("Invalid Expression: {0}", msg, e);
}
//IAntlrErrorListener<int> implementation; this one actually gets called.
public void SyntaxError(IRecognizer recognizer, int offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
throw new ArgumentException("Invalid Expression: {0}", msg, e);
}
}
And changed my `Calculator` class to attach my custom error listener to the lexer. Note that you don't have to remove the `ConsoleListener` like I did for the error to actually be thrown. Since I'm not really using it, I figured it best to go ahead and do so.
public static class Calculator
{
public static int Evaluate(string expression)
{
var lexer = new BasicMathLexer(new AntlrInputStream(expression));
lexer.RemoveErrorListeners(); //removes the default console listener
lexer.AddErrorListener(new ThrowExceptionErrorListener());
var tokens = new CommonTokenStream(lexer);
var parser = new BasicMathParser(tokens);
var tree = parser.compileUnit();
var visitor = new IntegerMathVisitor();
return visitor.Visit(tree);
}
}
And that's it. An argument exception is thrown and this test now passes.
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void BadInput()
{
var expr = "1 + 5 + 2(3)";
int value = Calculator.Evaluate(expr);
}
One last note. If you throw a `RecognitionException` here, it will just get swallowed up again. `ParseCancelationException` is recommended, because it does not derive from `RecognitionException`, but I choose an `ArgumentException` because I felt that made the most sense to the client C# code.
Problem
I have a simple ANLTR grammar and accompanying Visitor. Everything works great, unless the input is invalid. If the input is invalid, the errors get swallowed and my calculator comes out with the wrong output. I've tried implementing an error listener, over riding the `Recover` method of the lexer, and.. well... half a dozen other things today. Can someone show me how to simply throw an error instead of swallowing bad "tokens"? (I use quotes because they're not tokens at all. The characters are undefined in my grammar.) Valid Input: 1 + 2 * 3 - 4 Invalid Input: 1 + 2 + 3(4) I want to throw an `ArgumentException` if the parser/lexer comes across parenthesis (or any other undefined character). Currently, the invalid characters seem to just disappear into the ether and the parser just plods along like nothing is wrong. If I run it in the console with the `grun` command, I get the following output, so it recognizes the invalid tokens on some level. line 1:9 token recognition error at: '(' line 1:11 token recognition error at: ')' and this resulting parse tree. BasicMath.g4 ``` grammar BasicMath; /* * Parser Rules */ compileUnit : expression+ EOF; expression : expression MULTIPLY expression #Multiplication | expression DIVIDE expression #Division | expression ADD expression #Addition | expression SUBTRACT expression #Subtraction | NUMBER #Number ; /* * Lexer Rules */ NUMBER : INT; //Leave room to extend what kind of math we can do. INT : ('0'..'9')+; MULTIPLY : '*'; DIVIDE : '/'; SUBTRACT : '-'; ADD : '+'; WS : [ \t\r\n] -> channel(HIDDEN); ``` Calculator: ``` public static class Calculator { public static int Evaluate(string expression) { var lexer = new BasicMathLexer(new AntlrInputStream(expression)); var tokens = new CommonTokenStream(lexer); var parser = new BasicMathParser(tokens); var tree = parser.compileUnit(); var visitor = new IntegerMathVisitor(); return visitor.Visit(tree); } } ```