Как заставить ANTLR 3.2 выйти при первой ошибке? - PullRequest
8 голосов
/ 15 марта 2010

В разделе 10.4 ссылка Definitive ANTLR говорит вам переопределить mismatch () и recoverFromMismatchedSet (), если вы хотите выйти при первой ошибке синтаксического анализа. Но, по крайней мере, в ANTLR 3.2, кажется, что нет метода mismatch (), а в документации recoverFromMismatchedSet () говорится, что он «не используется». Похоже, что с момента выхода книги все изменилось.

Что я должен сделать вместо того, чтобы выйти при первой ошибке синтаксического анализа в ANTLR 3.2?

1 Ответ

13 голосов
/ 16 марта 2010

Я отправил этот вопрос на anltr-интереса, и Андрей Харитонкин ответил. Барт K наполовину прав; вам нужно переопределить restoreFromMismatchedSet (), но также recoverFromMismatchedToken ().

Если вы также хотите, чтобы лексер завершил работу при первой ошибке, есть вики-страница, объясняющая, что делать:

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

Вкратце, говорится, что:

  1. Если вы хотите выбросить RecognitionException (или что-либо, наследуемое от Exception), то вам нужно выполнить хитрые Java-трюки, потому что соответствующие методы не объявляют никаких исключений
  2. Если можно сгенерировать RuntimeException или Error, вы можете либо переопределить nextToken (), чтобы сгенерировать исключение, вместо вызова recoveryError (), либо переопределить recoveryError (). бросить исключение.

Вот пример грамматики, которая возникает при первой ошибке лексера или синтаксического анализатора:

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; } ;

Пример вывода:

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              
...