Как заставить ANTLR генерировать NoViableAltException?

Я работаю с antlr 3.2. У меня есть простая грамматика, состоящая из атомов (которые являются символами «0» или «1»), и правило, которое накапливает их список, разделенный запятыми, в список.

Когда я передаю «00» в качестве ввода, я не получаю ошибку, что меня удивляет, потому что это не должно быть допустимым вводом:

C:\Users\dan\workspace\antlrtest\test>java -cp antlr-3.2.jar org.antlr.Tool Test.g
C:\Users\dan\workspace\antlrtest\test>javac -cp antlr-3.2.jar *.java
C:\Users\dan\workspace\antlrtest\test>java -cp .;antlr-3.2.jar TestParser
[0]

Как я могу заставить ошибку генерироваться в этом случае? Это особенно озадачивает, потому что когда я использую интерпретатор в ANTLRWorks для этого ввода, он действительно показывает исключение NoViableAltException.

Я обнаружил, что если я изменяю грамматику, требуя, скажем, точку с запятой в конце, генерируется ошибка , но это решение недоступно для меня в реальной грамматике, над которой я работаю.

Вот грамматика, которая самодостаточна и работоспособна:

grammar Test;

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

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


atom: '0' | '1';

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

person Dan Becker    schedule 17.02.2010    source источник


Ответы (1)


После вашего mainRule вы должны добавить токен EOF, в противном случае ANTLR прекратит синтаксический анализ, когда нет подходящего токена.

Кроме того, правило atom действительно должно быть правилом лексера, а не правилом парсера (правила лексера начинаются с заглавной буквы).

Попробуйте это вместо этого:

grammar Test;

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

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

ИЗМЕНИТЬ

Чтобы уточнить: как вы уже выяснили, EOF не является обязательным. Это только заставит синтаксический анализатор пройти весь ввод. NoViableAltException генерируется только тогда, когда лексер натыкается на токен/символ, который не обрабатывается вашей грамматикой лексера. Поскольку вы определяете три токена в своей грамматике (0, 1 и ,), и ваш ввод, "00", не содержит никаких символов, которые не обрабатываются вашей грамматикой, NoViableAltException не выдается. . Если вы измените ввод на что-то вроде "0?0", появится NoViableAltException.

Поскольку ваш синтаксический анализатор сначала находит 0, а затем не находит ,, он просто прекращает синтаксический анализ, поскольку вы не "сказали" ему, чтобы он анализировал весь файл до конца.

Надеюсь, что это проясняет ситуацию. Если нет, дайте мне знать.

person Bart Kiers    schedule 17.02.2010
comment
... ANTLR прекратит синтаксический анализ, если нет подходящего токена. Спасибо, Барт! Но разве он не должен сообщать об ошибке, когда остается текст, но нет действительных токенов? Это особенность ANTLR или по какой-то причине это правильно? - person Dan Becker; 18.02.2010
comment
кроме того, похоже, это означает, что вы всегда должны включать EOF в конце основных правил парсера, но я видел множество примеров ANTLR, где это не делается. - person Dan Becker; 18.02.2010
comment
В одном из комментариев режима я нашел сообщение на antlr-interest, которое здесь актуально. Похоже, вам не всегда нужен EOF, завершающий вашу грамматику, но в моем случае я думаю, что да. Ссылка: antlr.org/pipermail/antlr-interest/2009 -Январь/032219.html - person Dan Becker; 18.02.2010