Сдвиг/уменьшение конфликта в чашке java - проблема с зависанием

Я получаю следующую ошибку:

Warning : *** Shift/Reduce conflict found in state #116
between Statement ::= Matched (*) 
and     Unmatched ::= IF LPAREN Condition RPAREN Matched (*) ELSE Unmatched 
and     Matched ::= IF LPAREN Condition RPAREN Matched (*) ELSE Matched 
under symbol ELSE
Resolved in favor of shifting.

Теперь я знаю о проблеме с оборванным else, и я попытался сделать грамматику однозначной:

Statement ::= Matched | Unmatched ;


Matched ::= IF LPAREN Condition RPAREN Matched ELSE Matched
            |
            Others
             ;

Unmatched ::= IF  LPAREN Condition RPAREN Statement 
              | 
              IF  LPAREN Condition RPAREN Matched ELSE Unmatched
              ;

Есть ли способ решить эту проблему без оператора приоритета или что-то еще не так с грамматикой?


person Shibby    schedule 13.12.2015    source источник


Ответы (1)


В грамматике, представленной в вопросе, нет ничего плохого, поэтому я предполагаю, что конфликт сдвига/уменьшения является результатом взаимодействия с другим продуктом.

Идея разделения операторов на Matched и Unmatched:

Statement ::= Matched | Unmatched ;

заключается именно в том, чтобы убедиться, что else правильно сопоставляется с ближайшим несопоставленным if. Оператор Matched не может быть дополнен предложением else; заявление Unmatched могло быть. Таким образом, мы требуем, чтобы токены else в грамматике не могли следовать за операторами Unmatched, чтобы избежать преждевременного сокращения оператора, который мог бы быть расширен предложением else.

Таким образом, внутри оператора If else может следовать только за оператором Matched. Сам оператор имеет значение Unmatched, если в нем нет предложения else или если само предложение else имеет значение Unmatched. Таким образом, у нас есть три производства:

Unmatched_If ::= IF LPAREN Condition RPAREN Statement
               | IF LPAREN Condition RPAREN Matched ELSE Unmatched ;
Matched_If   ::= IF LPAREN Condition RPAREN Matched ELSE Matched ;

Но это еще не все, потому что возможны и другие составные операторы. Рассмотрим, например, оператор while. Если в языке есть такая конструкция, грамматика, вероятно, включает что-то вроде этого:

While        ::= WHILE LPAREN Condition RPAREN Statement ; /* Wrong! */

Это не сработает, потому что оператор while также может быть Unmatched точно так же, как может быть оператор if...else: если внутреннее Statement равно Unmatched.

Например, рассмотрим

while (x) if (y) do_x_and_y;

При указанном выше неправильном производстве While это будет уменьшено следующим образом:

   WHILE LPAREN Condition RPAREN Unmatched_If
-> WHILE LPAREN Condition RPAREN Statement
-> Matched

Но это нарушает требование, согласно которому за Unmatched не может следовать else. За Matched может следовать else, но в этом случае Matched заканчивается на Unmatched_If. И, следовательно, у нас есть конфликт сдвига/уменьшения:

if (w)
  while (x) if (y) do_this;
else do_that;

Это может быть проанализировано как

IF ( Condition:[w] ) Matched:[while(x)if(y)do_this;] ELSE Statement:[do_that;]

Но на самом деле это не предполагаемый анализ. (Отступ может привести нас к мысли, что это было намерением программиста, но не намерением разработчика языка.) else должно соответствовать второму if, а не первый, ведущий к:

if (w)
  while (x)
    if (y) do_this; else do_that;

Поэтому нам нужно различать совпадающие и несопоставленные операторы While, а не только совпадающие и несопоставленные операторы If:

Unmatched_While ::= WHILE LPAREN Condition RPAREN Unmatched ;
Matched_While   ::= WHILE LPAREN Condition RPAREN Matched ;

При этом while (x) if (y) do_x_and_y; будет проанализировано как Unmatched_While, и поэтому оно больше не может быть частью постановок, запускающих IF LPAREN Condition RPAREN Matched ELSE....

Конечно, то же самое нужно будет сделать и для других составных операторов, таких как операторы for.

Таким образом, окончательный результат будет примерно таким:

Matched   ::= Matched_If
            | Matched_While
            | Matched_For
            | ...
            | Simple_Statement
            ;
Unmatched ::= Unmatched_If
            | Unmatched_While
            | Unmatched_For
            | ...
            ;
person rici    schedule 13.12.2015