Правило antlr4 не игнорирует отдельную открытую скобку

Ситуация:

rule   : block+ ;
block  : '[' String ']' ;
String : ([a-z] | '[' | '\\]')+ ;

Хитрость заключается в том, что String может содержать [ без обратной косой черты и ] с обратной косой чертой, поэтому в этом примере:

[hello\]world][hello[[world]

Первый блок может быть проанализирован правильно, но второй... парсер пытается найти ] для каждого [. Есть ли способ сказать парсеру antlr игнорировать этот автономный [? Я не могу изменить формат, но мне нужно найти обходной путь с помощью antlr.

PS: Без antlr есть алгоритм, чтобы избежать этого, что-то вроде: собрать [ в очереди, прежде чем мы найдем первый ] и использовать только начало очереди. Но мне очень нужен antlr =_=


person doubledeath    schedule 20.01.2016    source источник


Ответы (1)


Вы можете использовать режимы Lexer.

Лексические режимы позволяют нам разделить одну грамматику лексера на несколько подлексеров. Лексер может возвращать только токены, соответствующие правилам из текущего режима.

Подробнее о правилах лексера можно прочитать в документации antlr здесь .

Сначала вам нужно будет разделить грамматику на отдельные lexer и parser. Чем просто использовать другой режим после того, как вы увидите открытую скобку.

Грамматика парсера:

parser grammar TestParser;

options { tokenVocab=TestLexer; }

rul   : block+ ;
block  : LBR STRING RBR ;

Грамматика лексера:

lexer grammar TestLexer;

LBR: '[' -> pushMode(InString);

mode InString;

STRING : ([a-z] | '\\]' | '[')+ ;
RBR: ']' -> popMode;

Рабочий пример находится здесь.

Вы можете прочитать документацию по режимам лексера

person Dzmitry Paulenka    schedule 24.01.2016
comment
Да, действительно работает, спасибо! Но можете ли вы объяснить, как именно это работает, в деталях? Я имею в виду, кажется, важен даже порядок определения токенов и режима... поэтому, если я собираюсь расширить эту грамматику, мне нужно понять, что я делаю =) - person doubledeath; 25.01.2016
comment
Я добавил ссылку на документ в ответ. И да, токены, объявленные после директивы mode ModeName, соответствуют этому режиму. - person Dzmitry Paulenka; 25.01.2016