How to get ANTLR 3.2 to exit upon first error?

2019-02-09 07:55发布

问题:

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?

回答1:

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