Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

You need to override the default behavior which tries to recover and keep lexing. Just There are two approaches depending upon if you care about the lexer throwing a proper RecognitionException or not. If not, just override the nextToken() method as shown in the following example:

...

You cannot throw an exception because the interface for TokenStream was designed to not transmit lexical errors through to the parser. What would the parser do with a lexical error? Better to throw an exception that makes the entire system go back to the invoking main method or whatever. Java Does (without some tricks) does not allow throwing exceptions without altering the method interface so we must use either an Error object or a RuntimeObject, which are considered unchecked. Other targets will not have this problem. just override and get rid of the catch-clause.

The second approach overrides the reportError method and causes it to throw the RecognitionException it is passed. Because this method does not declare that it will throw the checked exception RecognitionException a trick must be used to make this work. This will bail out all the way to the code that invoked the parser (or lexer) and allow that code to deal with the problem.

Code Block

@lexer::members {
  @Override
  public void reportError(RecognitionException e) {
    Thrower.sneakyThrow(e);
  }

  /**
   * See "Puzzle 43: Exceptionally Unsafe" from Bloch Gafter, <i>Java Puzzlers</i>. Addison Wesley 2005.
   */
  static class Thrower {
    private static Throwable t;
    private Thrower() throws Throwable {
      throw t;
    }
    public static synchronized void sneakyThrow(Throwable t) {
      Thrower.t = t;
      try {
        Thrower.class.newInstance();
      } catch (InstantiationException e) {
        throw new IllegalArgumentException(e);
      } catch (IllegalAccessException e) {
        throw new IllegalArgumentException(e);
      } finally {
        Thrower.t = null; // Avoid memory leak
      }
    }
  }
}