Грамматическая проблема ANTLR с выражениями в скобках

#antlr #grammar

#antlr #грамматика

Вопрос:

Я использую ANTLRWorks 1.4.2 для создания простой грамматики с целью оценки предоставленного пользователем выражения как логического результата. В конечном итоге это станет частью более масштабной грамматики, но у меня есть несколько вопросов по этому текущему фрагменту. Я хочу, чтобы пользователи могли использовать такие выражения, как:

  1. 2 > 1
  2. 2 > 1 and 3 < 1
  3. (2 > 1 or 1 < 3) and 4 > 1
  4. (2 > 1 or 1 < 3) and (4 > 1 or (2 < 1 and 3 > 1))

Первые два выражения допустимы в моей грамматике, но последние два — нет, и я не уверен, почему. Кроме того, ANTLRWorks, похоже, предполагает, что ввод, такой как ((((1 > 2) с несовпадающими скобками, является законным, и я не уверен, почему. Итак, я, кажется, упускаю из виду некоторое представление о правильном способе обработки группировки в скобках в грамматике.

Как я могу изменить свою грамматику, чтобы правильно обрабатывать круглые скобки?

Моя грамматика приведена ниже:

 grammar conditional_test;

boolean
    :   boolean_value_expression
        EOF
    ;

boolean_value_expression
    :   boolean_term (OR boolean_term)*
        EOF
    ;

boolean_term
    :   boolean_factor (AND boolean_factor)*
    ;

boolean_factor
    :   (NOT)?  boolean_test
    ;

boolean_test
    :   predicate
    ;

predicate
    :   expression relational_operator expression
    |   LPAREN boolean_value_expression RPAREN
    ;

relational_operator
    :   EQ
    |   LT
    |   GT
    ;   

expression
    :   NUMBER
    ;


LPAREN      :   '(';
RPAREN      :   ')';
NUMBER      :   '0'..'9' ;

EQ          :   '=';
GT          :   '>';
LT          :   '<';

AND         :   'and';
OR          :   'or' ;
NOT         :   'not';
  

Ответ №1:

Крис Фармер написал:

Первые два выражения допустимы в моей грамматике, но последние два — нет, и я не уверен, почему. …

Вам следует удалить EOF токен из:

 boolean_value_expression
    :   boolean_term (OR boolean_term)*
        EOF
    ;
  

Обычно вы используете только EOF после точки входа вашей грамматики ( boolean в вашем случае). Будьте осторожны boolean — это зарезервированное слово в Java, и поэтому его нельзя использовать в качестве правила синтаксического анализа!

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

 bool
    :   boolean_value_expression
        EOF
    ;

boolean_value_expression
    :   boolean_term (OR boolean_term)*
    ;
  

И вы также можете захотеть игнорировать буквенные пробелы, добавив следующее правило лексера:

 SPACE : ' ' {$channel=HIDDEN;};
  

(вы можете включить табуляции и разрывы строк, конечно)

Теперь все входные данные вашего примера соответствуют должным образом (также протестировано с ANTLRWorks 1.4.2).

Крис Фармер написал:

Кроме того, ANTLRWorks, похоже, предполагает, что ввод, такой как ((((1 > 2) с несовпадающими скобками, является законным, …

Нет, ANTLRWorks действительно выдает ошибки, возможно, не очень заметные. Дерево синтаксического анализа, созданное ANTLRWorks, имеет NoViableAltException вид листа, и на вкладке «Консоль» есть некоторые ошибки.

Комментарии:

1. Спасибо! Я не уверен, как туда попал этот дополнительный EOF, но это определенно сбивало с толку некоторые вещи. Спасибо, что взглянули на это. Ваши предложения отлично работают.

2. @Chris, обратите внимание, что ваша грамматика не допускает круглых скобок вокруг таких чисел, как: 1 < (2) . Возможно, вы сделали это намеренно, но, возможно, и нет, и в этом случае вам следует перейти LPAREN boolean_value_expression RPAREN к expression правилу и изменить predicate на: predicate : expression (relational_operator expression)? ;