Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to throw an exception if the input isn't valid?

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.

enter image description here

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);
    }
}
like image 806
RubberDuck Avatar asked Apr 23 '15 21:04

RubberDuck


People also ask

How do you throw an exception for invalid input?

User-Defined Exception for Invalid Input in Java Let's create an exception if the user enters an ID. If it is not present in the database, the invalid id exception is thrown. The code creates an exception thrown when the input ID is invalid, which means not present in the database.

Is it possible to throw an exception?

Any code can throw an exception: your code, code from a package written by someone else such as the packages that come with the Java platform, or the Java runtime environment. Regardless of what throws the exception, it's always thrown with the throw statement.

What causes an exception to be thrown?

An exception is thrown for one of three reasons: An abnormal execution condition was synchronously detected by the Java virtual machine. Such conditions arise because: evaluation of an expression violates the normal semantics of the language, such as an integer divide by zero, as summarized in §15.6.

How do you throw an invalid exception in Java?

For example, we can check an input parameter to our method and throw an IllegalArgumentException if it is invalid: public void calculate(int n) { if (n > MAX_VALUE) { throw new IllegalArgumentException("Value too big (" + n + ")"); } ... }


1 Answers

Actually each error message is caused by an exception. This exception is caught and the parser tries to recover. The parse tree is the result of the recovering.

Since the error occurs in the lexer (the lexer just does not know the characters ( or )), the error handling must be attached to the lexer. In Java this would look like:

    lexer.addErrorListener(new BaseErrorListener()  {
        @Override
        public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
            throw new RuntimeException(e);
        }
    });

The C# Syntax should not be far from that. Yet I recommend not to throw an exception. Better collect the errors into a list and report them after the lexer finished and do not start parsing if the list of errors is not empty.

like image 64
CoronA Avatar answered Sep 19 '22 01:09

CoronA