2016-10-04 7 views
2

Я пытался использовать ANTLR4, чтобы определить диапазон обозначения как <1..100>, и вот моя попытка:семантические предикаты неудачу, но не переходите к следующему один

@parser::members { 
def evalRange(self, minnum, maxnum, num): 
    if minnum <= num <= maxnum: 
     return True 
    return False 
} 
range_1_100 : INT { self.evalRange(1, 100, $INT.int) }? ; 

Но он не работает в течение более чем одного диапазон нравится:

some_rule : range_1_100 | range_200_300 ; 

Когда я ввести номер (200), он просто останавливается на первом правиле:

200 
line 3:0 rule range_1_100 failed predicate: { self.evalRange(1, 100, $INT.int) }? 
(top (range_1_100 200)) 

Это не так, как я ожидал. Как я могу сделать соответствие токена следующим правилом (range_200_300)?

ответ

0

Вот отрывок из the docs (курсив мой):

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

[...]

общей стратегия принятия решений Antlr в том, чтобы найти все жизнеспособные альтернативы, а затем игнорировать альтернативы охранялись с предикатами, которые в настоящее время оценивают ложные. (Жизнеспособной альтернативой является та, которая соответствует текущему вводу.) Если остается более одной жизнеспособной альтернативы, парсер выбирает альтернативу, указанную первым в решении.

Который в основном означает, что ваш предикат обязательно быть первым элементом в чередовании должны быть приняты во внимание во время фазы предсказания.

Конечно, вы не сможете использовать $INT, поскольку он не был еще подбираются на данный момент, но вы можете заменить его чем-то вроде _input.LA(1) вместо (опережения одного маркера) - точный синтаксис зависит от вашего языковой цели.


Как примечание стороны, я бы посоветовал вам не проверки входных сигналов с помощью грамматики, это проще и лучше выполнять отдельные проверки проходят после разбора. Пусть грамматика обрабатывает синтаксис, а не семантику.

+0

Я понимаю, но с ними трудно справиться после разбора. Если есть два правила: 'some_rule2: INT; some_rule3: INT; '. Они имеют разные диапазоны, и это вызывает неоднозначный синтаксис. Как я могу победить? – Wirelessr

+1

Если вы хотите обработать проверку после разбора, используйте только одно правило 'range: INT;', а затем обработайте валидацию с посетителем. ANTLR генерирует базовые классы для них. Таким образом, вы устраняете неоднозначность и не смешиваете синтаксис и семантику. –

+0

Я пробовал посетителя, но у меня большая проблема. Несмотря на то, что правило принимает более одного диапазона с разными числовыми диапазонами, psudocode похож на 'more_than_one: range_1_10 range_20_30? range_40_50? ', а реальное правило -' more_than_one: range + '. Как я могу различать эти диапазоны в 'visitMore_than_one()'? – Wirelessr