Бизон уменьшает/уменьшает конфликты

Я написал следующую грамматику:

%union{
    string *s;
    float num;
}
%token div_token mod_token sqrt_token it_token abs_token
%token <num> num_token 
%token <s> Stampa
%type <num> E


%left '+' '-'
%left '*' '/' div_token mod_token
%left UMINUS
%left abs_token sqrt_token


%%

Program: Program Line '\n'   { }
| Line  '\n' { }
;

Line: Stampa    {cout<<*$1<<endl;}
| E         {cout<<$1<<endl; broj = $1;}
| it_token      {cout<<broj<<endl;}
;

E: E '+' E {$$ = $1 + $3;}
| E '-' E {$$ = $1 - $3;}
| E '*' E {$$ = $1 * $3;}
| E '/' E {if($3!=0) 
              $$ = $1 / $3;
            else
              yyerror("Deljenje nulom");
            }
| mod_token E E {$$ = (float)((int)$2 % (int)$3);}
| div_token E E {$$ = (float)((int)($2 / $3));}
| sqrt_token E  { $$ = sqrt($2); }
| '(' E ')' {$$=$2;}
| abs_token E { $$ = abs($2);}
| '-' E %prec UMINUS {$$=-$2;}
| num_token {$$ = $1;}
;

Теперь bison обнаружил 8 конфликтов уменьшения/уменьшения. Когда я удаляю строку

| '-' E %prec UMINUS {$$=-$2;}

их нет. Я думаю, что приоритеты и ассоциативные свойства хорошо определены. Может кто подскажет как разрешать конфликты?


person Laika_Boss    schedule 10.07.2017    source источник


Ответы (2)


Теперь bison обнаружил 8 конфликтов уменьшения/уменьшения. Когда я удаляю строку

| '-' E %prec UMINUS {$$=-$2;}

их нет. Я думаю, что приоритеты и ассоциативные свойства хорошо определены. Может кто подскажет как разрешать конфликты?

Это должно решить проблему:

%union{
      string *s;
      float num;
}
%token div_token mod_token sqrt_token it_token abs_token
%token <num> num_token 
%token <s> Stampa
%type <num> E

%left '+' '-'
%left '*' '/' div_token mod_token
%left UMINUS
%left abs_token sqrt_token

%%

Program: Program Line '\n'   { }
| Line  '\n' { }
;

Line: Stampa    {cout<<*$1<<endl;}
| E         {cout<<$1<<endl; broj = $1;}
| it_token      {cout<<broj<<endl;}
;

E: E '+' E {$$ = $1 + $3;}
| E '-' E {$$ = $1 - $3;}
| E '*' E {$$ = $1 * $3;}
| E '/' E {if($3!=0) 
                $$ = $1 / $3;
                    else
                yyerror("Deljenje nulom");
          }
| E mod_token E {$$ = (float)((int)$1 % (int)$3);}
| E div_token E {$$ = (float)((int)($1 / $3));}
| sqrt_token E  { $$ = sqrt($2); }
| '(' E ')' {$$=$2;}
| abs_token E { $$ = abs($2);}
| '-' %prec UMINUS E {$$=-$2;}
| num_token {$$ = $1;}
;

Это устраняет пару проблем. Вы, вероятно, имели в виду:

| E mod_token E {$$ = (float)((int)$1 % (int)$3);}
| E div_token E {$$ = (float)((int)($1 / $3));}

А понятнее написать следующее:

| '-' %prec UMINUS E {$$=-$2;}

Вы можете увидеть конфликты с опцией bison -v, которая создает xyz.output:

state 35

    6 E: E . '+' E
    7  | E . '-' E
    7  | E '-' E .
    8  | E . '*' E
    9  | E . '/' E
   15  | '-' E 

.

    div_token   reduce using rule 7 (E)
    div_token   [reduce using rule 15 (E)]
    mod_token   reduce using rule 7 (E)
    mod_token   [reduce using rule 15 (E)]
    sqrt_token  reduce using rule 7 (E)
    sqrt_token  [reduce using rule 15 (E)]
    abs_token   reduce using rule 7 (E)
    abs_token   [reduce using rule 15 (E)]
    num_token   reduce using rule 7 (E)
    num_token   [reduce using rule 15 (E)]
    '+'         reduce using rule 7 (E)
    '+'         [reduce using rule 15 (E)]
    '-'         reduce using rule 7 (E)
    '-'         [reduce using rule 15 (E)]
    '*'         reduce using rule 15 (E)
    '/'         reduce using rule 15 (E)
    '\n'        reduce using rule 15 (E)
    '('         reduce using rule 7 (E)
    '('         [reduce using rule 15 (E)]
    ')'         reduce using rule 15 (E)
    $default    reduce using rule 7 (E)

Сокращения оператора на div_token и mod_token вызывают подозрение. Неоднозначность грамматики вызвана тем, что эти операторы применяются к двум выражениям E.

ИЗМЕНИТЬ

Возможно, вы хотите сохранить префикс операторов div и mod. Если это так, вам нужно устранить неоднозначность грамматики. Одно из возможных решений:

| mod_token F F {$$ = (float)((int)$2 % (int)$3);}
| div_token F F {$$ = (float)((int)($2 / $3));}
| F
;
F: '(' E ')' {$$=$2;}
| sqrt_token E  { $$ = sqrt($2); }
| abs_token E { $$ = abs($2);}
| '-' %prec UMINUS E {$$=-$2;}
| num_token {$$ = $1;}
;

и добавьте тип F:

%type <num> E F
person Dr. Alex RE    schedule 10.07.2017
comment
Это просто неправда. Декларация приоритета применяется к правилу (производству) в целом, а не к какой-либо лексеме в правиле, и в соответствии с Руководство по Bison пишется после компонентов правила (хотя я считаю, что bison фактически позволяет размещать его в любом месте правила). - person rici; 10.07.2017
comment
Я добавил результат со всеми изменениями, которые необходимы, чтобы заставить его работать. Действие %prec направлено на повышение ясности в отношении оператора, затронутого ИМО. - person Dr. Alex RE; 10.07.2017
comment
Наоборот, вы перемещаете объявление %prec не в то место (неверно, поскольку в документации довольно конкретно указано, куда оно должно идти). Это может не работать на других вариантах yacc. И это не только не улучшает ясность, но и приводит к неправильному пониманию природы объявления %prec и алгоритма приоритета в целом. ИМХО. (Кроме того, я не вижу никаких доказательств того, что OP предполагал, что эти операторы будут инфиксными операторами. Но, возможно, вы правы.) - person rici; 10.07.2017
comment
Я преподавал компиляторы более 20 лет. Я предпочитаю видеть %prec как можно раньше в правиле, предпочтительно рядом с оператором. Конечно, это не основная проблема здесь, но понимание того, почему %prec существует в первую очередь, поскольку оно связано с оператором, имеет смысл. - person Dr. Alex RE; 10.07.2017
comment
Что ж, я думаю, нам просто придется согласиться, что мы расходимся в этом вопросе. - person rici; 10.07.2017

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

Имея это в виду, рассмотрим процесс разбора выражения:

div 7 - 3 - 2

(при условии, что div — это то, как вы пишете div_token).

Каждый - может быть либо инфиксным оператором вычитания, либо префиксным оператором отрицания. В этом контексте, поскольку за div должны следовать ровно два выражения, ровно один из знаков минус должен быть инфиксным. Но какой? Это

div (7-3) (-2)

or

div (7) (-3-2)

Но, конечно, возможны и другие контексты. Если бы выражение было div 7 - 3 - 2 a, то единственным допустимым синтаксическим анализом был бы div ((7-3)-2) 8, а если бы выражение было div div 7 - 3 - 2, то синтаксический анализ должен был бы быть div (div 7 (-3)) (-2).

Вы можете получить больше информации о конфликте, попросив bison создать отчет о синтаксическом анализе, используя параметр -v и просмотрев полученный файл .output. С вашей грамматикой этот отчет показывает, что конфликт уменьшения/уменьшения находится в состоянии 35, а именно:

State 35

    6 E: E . '+' E
    7  | E . '-' E
    7  | E '-' E .
    8  | E . '*' E
    9  | E . '/' E
   15  | '-' E .

    div_token   reduce using rule 7 (E)
    div_token   [reduce using rule 15 (E)]

(actions truncated for space)

Возможные сокращения соответствуют элементам LR с . в конце, то есть E '-' E . и '-' E .. Для большинства (но не для всех) прогнозных токенов возможно любое из этих сокращений. (Приоритет * над правилом E: E '-' E исключает возможность первого сокращения, если * является опережающим символом; аналогично для /.)

Подобное смешивание инфиксных и префиксных выражений обычно не является хорошей идеей именно из-за этой двусмысленности.

person rici    schedule 10.07.2017