ANTLR4: Можно ли вообще проверить части правила синтаксического анализатора?

Используя ANTLR4, я постоянно возвращаюсь к той же проблеме - как реализовать проверку алгоритмических правил в парсере.

Например, мне нужен синтаксический анализатор для проверки части «год» даты, записанной «месяц день год», перед тем, как соответствовать правилу. Я узнал, что могу сделать это с помощью следующего предиката:

date :
    {isYear(_input.LT(3).getText())}?
        month  day=INTEGER  year=INTEGER     { ... }

Но это решение не является общим, поскольку оно зависит от правила month, которое всегда имеет длину в один токен.

Я думал, что нашел способ обойти эту проблему, изменив правило на это:

date :  month  day=INTEGER  yearInt     { ... } ;

yearInt returns [int i]
     :   {isYear(_input.LT(1).getText())}?
             yr=INTEGER                 { $i = $yr.int; }
     ;

К сожалению, эта грамматика принимает за дату «11 июля 6», хотя isYear("6") не работает. Когда я отслеживаю сгенерированный ANTLR код в XXParser.java для yearInt(), я вижу, что он вызывает

throw new FailedPredicateException(this, "isYear(_input.LT(1).getText())");

но затем код продолжает действовать и все равно принимает yearInt().

Это ошибка ANTLR или моя ошибка? Есть ли «правильный» способ написать грамматику, которая должна проверять правильность частей правила?


person Ken Homer    schedule 06.08.2013    source источник


Ответы (1)


Пытаться

date :
    month  day=INTEGER  year=INTEGER {isYear($year)}?<fail="A sensible error msg"> { ... }
;

or

date :
    month  day=INTEGER  year=INTEGER {if ( ! isYear($year) ) 
                                       notifyErrorListeners("A sensible error msg");
                                     }     
    { ... }
;

Один из них будет выдавать более понятные сообщения об ошибках. notifyErrorListeners () устанавливает ошибку, но позволяет синтаксическому анализу «завершиться успешно» в том, что касается текущего синтаксического анализа. {isYear ($ year)}? потерпит неудачу и сделает больше в поисках совпадения.

Признаюсь, на самом деле я не пробовал этот код. Может быть, вам нужен $ year.text, и я не уверен, что опция отказа и notifyErrorListeners () действительны в версии C #, а также в версии Java.

Джордж

person cowang    schedule 22.08.2013