views:

92

answers:

2

In section 10.4, The Definitive ANTLR reference tells you to override mismatch() & recoverFromMismatchedSet() if you want to exit upon the first parsing error. But, at least in ANTLR 3.2, it appears that there is no mismatch() method, and the recoverFromMismatchedSet() documentation says that it is "Not Currently Used". So it appears things have changed since the book was published.

What am I supposed to do instead to exit upon the first parsing error in ANTLR 3.2?

A: 

If memory serves me well, you should let your parser override these methods from the BaseRecognizer class (the parent of Parser):

@parser::members {

  @Override
  public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) 
      throws RecognitionException {
    throw e;
  }

  @Override
  public void recover(IntStream input, RecognitionException re) {
    throw re;
  }  
}
Bart Kiers
recover() doesn't declare any exceptions, so the above won't compile. I tried wrapping the RecognitionException with a RuntimeException, but when I run my code no exceptions are thrown (I do get errors written to the log, so I'm pretty sure that there really is an error in the input.
Dan Becker
+2  A: 

I posted this question to anltr-interest, and Andrew Haritonkin answered. Bart K is half right; you need to override recoverFromMismatchedSet(), but also recoverFromMismatchedToken().

If you also want the lexer to exit upon the first error, there is a wiki page that explains what to do:

http://www.antlr.org/wiki/pages/viewpage.action?pageId=5341217

Briefly, it states that:

  1. If you want to throw RecognitionException (or anything inheriting from Exception) then you have to do sneaky java tricks, because the relevant methods don't declare any exceptions
  2. If it's OK to throw RuntimeException or Error, then you can either override nextToken() to throw an exception instead of calling recoverError(), or you can override recoverError(). to throw the exception.

Here is an example grammar that exits upon the first lexer or parser error:

grammar Test;

@parser::members {

  public static void main(String[] args) throws Exception {
    String text = args[0];
    ANTLRStringStream in = new ANTLRStringStream(text);
    TestLexer lexer = new TestLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    System.out.println(new TestParser(tokens).mainRule());
  }

  @Override
  protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException {
    throw new MismatchedTokenException(ttype, input);
  }

  @Override
  public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
    throw e;
  }

}

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

@lexer::members {
    @Override
    public void reportError(RecognitionException e) {
        throw new RuntimeException(e);
    }

}    

mainRule returns [List<String> words]
    @init{$words = new ArrayList<String>();}
  :  w=Atom {$words.add($w.text);} (',' w=Atom {$words.add($w.text);} )* EOF
  ;


Atom: '0' | '1';

WS  :  ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;

Sample output:

C:\Users\dan\workspace\antlrtest>java -cp .;antlr-3.2.jar TestParser "1,0" 
[1, 0]

C:\Users\dan\workspace\antlrtest>java -cp .;antlr-3.2.jar TestParser "1,,0"
Exception in thread "main" MismatchedTokenException(6!=4)
        at TestParser.recoverFromMismatchedToken(TestParser.java:45)
        at org.antlr.runtime.BaseRecognizer.match(BaseRecognizer.java:115)
        at TestParser.mainRule(TestParser.java:86)
        at TestParser.main(TestParser.java:40)

C:\Users\dan\workspace\antlrtest>java -cp .;antlr-3.2.jar TestParser "1,+0"   
Exception in thread "main" java.lang.RuntimeException: NoViableAltException('+@[])                                                                
        at TestLexer.reportError(TestLexer.java:16)                           
        at org.antlr.runtime.Lexer.nextToken(Lexer.java:94)                   
        at org.antlr.runtime.CommonTokenStream.fillBuffer(CommonTokenStream.java:119)                             at org.antlr.runtime.CommonTokenStream.LT(CommonTokenStream.java:238) 
        at org.antlr.runtime.Parser.getCurrentInputSymbol(Parser.java:54)     
        at org.antlr.runtime.BaseRecognizer.match(BaseRecognizer.java:104)    
        at TestParser.mainRule(TestParser.java:68)                            
        at TestParser.main(TestParser.java:40)                                
Caused by: NoViableAltException('+'@[])                                       
        at TestLexer.mTokens(TestLexer.java:165)                              
        at org.antlr.runtime.Lexer.nextToken(Lexer.java:84)
        ... 6 more              
Dan Becker
Thanks for the follow up Dan!
Bart Kiers