ANTLR not throwing errors on invalid input
Asked Answered
C

2

16

I'm using ANTLR to parse logical expressions in a Java tool I'm writing, and I'm having issues because passing invalid input strings to the generated ANTLR lexer and parser doesn't cause any exceptions. Instead of throwing a RecognitionException, like I would expect, the generated files just print the error message to the console and return as if no errors occurred, causing my program to crash when it runs into the empty data later.

I used ANTLRWorks version 1.4.3 to generate the files, and it seems like there should be some sort of option to have it actually throw errors rather than print to the console, but I haven't found anything. Does anyone know how to get ANTLR to actually throw error messages? I saw that this same issue in C# was solved by using an older version of ANTLR, is that what I need to do?

EDIT: After Bart pointed me in the direction of what I was looking for, I found this page

https://theantlrguy.atlassian.net/wiki/display/ANTLR3/Migrating+from+ANTLR+2+to+ANTLR+3

whose "Error handling" section had code that did what I want more exactly. To change the way ANTLR catches exceptions, you can say this in the grammar file:

@rulecatch {
   catch (RecognitionException e) {
    throw e;
   }
}

This forces ANTLR to throw the exception instead of handling it and recovering. There's also some stuff in that section about overriding the mismatch and recovery functions to make sure all possible exceptions are thrown.

Criswell answered 28/12, 2011 at 16:47 Comment(0)
J
17

An easy fix would be to override your lexer's and parser's reportError(...) and throw an exception of your own instead of letting ANTLR trying to recover from the incorrect syntax/input:

grammar YourGrammar;

// options/header/tokens

@parser::members {
  @Override
  public void reportError(RecognitionException e) {
    throw new RuntimeException("I quit!\n" + e.getMessage()); 
  }
}

@lexer::members {
  @Override
  public void reportError(RecognitionException e) {
    throw new RuntimeException("I quit!\n" + e.getMessage()); 
  }
}

// lexer & parser rules

More on error reporting (and recovery): https://theantlrguy.atlassian.net/wiki/display/ANTLR3/Error+reporting+and+recovery

Jorgan answered 28/12, 2011 at 18:41 Comment(1)
Oh, thank you sooo much, I knew there had to be a straightforward way to just edit the grammar file to do what I want, but ANTLR is just so big, I didn't know exactly what to look for.Criswell
B
4

You should use an error listener as suggested in this answer

However, for a quick migration from antlr3 to antlr4 / antlr v4, you could use this as your grammer:

@parser::members 
{
  private final Logger log = LogManager.getLogger(this.getClass().getName());
  public java.util.HashMap<String, Double> memory = new java.util.HashMap<String, Double>();

  @Override
  public void notifyErrorListeners(Token offendingToken, String msg, RecognitionException ex)
  {
    throw new RuntimeException(msg); 
  }
}

@lexer::members 
{
  @Override
  public void recover(RecognitionException ex) 
  {
    throw new RuntimeException(ex.getMessage()); 
  }
}
Beatrice answered 30/1, 2015 at 20:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.