LINUX.ORG.RU

Bison конфликт вывода/вывода (reduce/reduce)

 


0

2

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

%union {
double     val; 
symrec  *tptr; 
}


%token <val>  NUM        /* Простое число двойной точности   */
%token <tptr> VAR        /* Переменная                       */
%token IF THEN ELSE REPEAT UNTIL LS GT LE GE EQ NE SEMICOL
%token WRITE WRITEN READ

%type  <val>  exp
%type  <val>  logical_expr

%right '='
%left '-' '+'
%left '*' '/'
%left NEG 
%right '^' 

%%
input: 
        | operator input 
;

operator: SEMICOL
        | exp SEMICOL
        | block
        | if_stmt
        | REPEAT block UNTIL '(' logical_expr ')' SEMICOL   
        | WRITE var_sequence SEMICOL                         
        | WRITEN var_sequence SEMICOL  
        | READ var_sequence SEMICOL  
;

if_stmt:
          IF '(' logical_expr ')' {действие} THEN block 
                                            {действие} ELSE block 
   
        | IF '(' logical_expr ')'  {действие}  THEN block
;         

var_sequence: 
          VAR                  
        | VAR ',' var_sequence 
;

logical_expr:
           exp LS exp 
        |  exp GT exp 
        |  exp LE exp 
        |  exp GE exp
        |  exp EQ exp 
        |  exp NE exp 
;

block: '{' input '}';

exp     : NUM     
        | VAR    
        | VAR '=' exp 
        | exp '+' exp 
        | exp '-' exp
        | exp '*' exp
        | exp '/' exp       
        | '-' exp %prec NEG  
        | exp '^' exp
        | '(' exp ')'  
;
%%

Результат:

interp.y: конфликты: 1 вывода/вывода interp.y:55.35-68: предупреждение: rule useless in parser due to conflicts: $@4: /* пусто */

строка 55 - второй IF (без ELSE) 35-68 - там действие написано

Спасибо.



Последнее исправление: annoynimous (всего исправлений: 1)
exp     : VAR '=' exp
        | term '+' exp
        | term '-' exp
        | term '*' exp
        | term '/' exp
        | term '^' exp
        | term
;

term    : NUM     
        | VAR    
        | '-' exp %prec NEG  
        | '(' exp ')'
;
k_andy ★★★
()
Ответ на: комментарий от igsilya

А вот, как выглядит грамматика после обработки бизоном:

Грамматика

    0 $accept: input $end

    1 input: operator
    2      | operator input

    3 operator: SEMICOL
    4         | exp SEMICOL
    5         | block
    6         | if_stmt

    7 $@1: /* пусто */

    8 operator: $@1 REPEAT block UNTIL '(' logical_expr ')' SEMICOL
    9         | WRITE var_sequence SEMICOL
   10         | WRITEN var_sequence SEMICOL
   11         | READ var_sequence SEMICOL

   12 $@2: /* пусто */

   13 $@3: /* пусто */

   14 if_stmt: IF '(' logical_expr ')' $@2 THEN block $@3 ELSE block

   15 $@4: /* пусто */

   16 if_stmt: IF '(' logical_expr ')' $@4 THEN block

   17 var_sequence: VAR
   18             | VAR ',' var_sequence

   19 logical_expr: exp LS exp
   20             | exp GT exp
   21             | exp LE exp
   22             | exp GE exp
   23             | exp EQ exp
   24             | exp NE exp

   25 block: '{' input '}'

   26 exp: NUM
   27    | VAR
   28    | VAR '=' exp
   29    | exp '+' exp
   30    | exp '-' exp
   31    | exp '*' exp
   32    | exp '/' exp
   33    | '-' exp
   34    | exp '^' exp
   35    | '(' exp ')'

igsilya
() автор топика
Ответ на: комментарий от igsilya

На сколько я понял конфликт возникает здесь:

состояние 50

   14 if_stmt: IF '(' logical_expr ')' . $@2 THEN block $@3 ELSE block
   16        | IF '(' logical_expr ')' . $@4 THEN block

    THEN      вывод с использованием правила 12 ($@2)
    THEN      [вывод с использованием правила 15 ($@4)]
    $default  вывод с использованием правила 12 ($@2)

    $@2  переход в состояние 59
    $@4  переход в состояние 60

ведь оба состояния $@2 и $@4 пусты.

igsilya
() автор топика
Ответ на: комментарий от nerh

Знаю. читал. Конфликта shift/reduce в первоначальной грамматике не возникает. Решение k_andy не решает первоначальную проблему, а лишь добавляет ещё конфликтов типа shift/reduce.

Первоначальный конфликт reduce/reduce, вызванный вставкой бизоном пустых(т.е. неразличимых), но разноназванных состояний. В результате не известно переходить по $@2 или $@4 и по дефолту делается переход всегда на $@2, при этом правило без else становится недостижимым, а конструкция без него - синтаксической ошибкой.

P.S. про плавающий else мне хорошо известно, если вы посмотрите грамматику, то видно, что её не возникает, т.к. я использую block.

igsilya
() автор топика
Ответ на: комментарий от igsilya

А вот, как выглядит грамматика

Ты бы русскую грамматику осилил...

anonymous
()
Ответ на: комментарий от igsilya

Reduce/reduce исправляется так:

if_prefix: IF '(' logical_expr ')' THEN block
;

if_stmt: if_prefix
         if_prefix ELSE block
;

Выражения всё же лучше переписать в леворекурсивном виде.

k_andy ★★★
()
Ответ на: комментарий от k_andy

Спасибо. Я чуть по-другому сделал, но ваше решение даже лучше.

я написал так:

if_stmt:
          IF '(' logical_expr ')'  THEN block else_stmt
;         

else_stmt:
          | ELSE block
;

P.S. левая рекурсия - это хорошо, но я всё же надеюсь, что никто не будет писать на ЭТОМ такие выражения, что аж стека не хватит.

igsilya
() автор топика
Ответ на: комментарий от igsilya

В ваших правилах у всех операций одинаковый приоритет. Да и ассоциативность непонятная. Эти вещи прийдётся делать отдельно в семантической части, хотя можно было бы возложить на синтаксический анализатор.

k_andy ★★★
()
25 апреля 2013 г.
Ответ на: комментарий от actics

А почему лучше в леворикурсивном виде

Тут несколько доводов.

  • Большинство операторов леворекурсивны (кроме возведения в степень);
  • В грамматике можно отразить приоритеты;
  • Для некоторых классов грамматик это обязательное требование (LL);
  • Автомат проще;
  • Так привычнее :)
k_andy ★★★
()

Попробуй убрать «действие» в IF '(' logical_expr ')' {действие}

или включить LR вместо LARL.

abacaba
()
Ответ на: комментарий от k_andy

Для некоторых классов грамматик это обязательное требование (LL);

Для LL граматик левая рекурсия наоборот запрещена)

actics
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.