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

Я новичок в Bison, и я долгое время пытался создать массив и правила для конкатенации и многого другого, и не могу понять, почему я получаю сокращение сдвига здесь и как я могу его решить:

arr:
  T_OPEN expr       {$$ = (void *)(new vector<int>());((vector<int>*)$$)->push_back($2);}
| arr ',' expr      {((vector<int>*)($1))->push_back($3);}
| arr T_CLOSE       {}
| arr '@' arr       {/*will add it later*/}

T_OPEN — это «[», а T_CLOSE — это «]». @ должен объединить два массива. arr имеет тип void*. Часть :

arr '@' arr

вызывает сдвиг, уменьшает конфликт. Любое решение будет высоко оценено


person Shirli    schedule 29.11.2015    source источник


Ответы (1)


Продукция, как

arr: arr '@' arr;

всегда будет вызывать конфликты сдвига и сокращения, потому что они неоднозначны. Предположим, у вас есть два оператора @ в исходном коде:

...1 @ ...2 @ ...3

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

arr1: ...1 @ ...2
arr2: ...3
arr3: arr1 @ arr2

or

arr1: ...1
arr2: ...2 @ ...3
arr3: arr1 @ arr2

Другими словами, @ ассоциируется слева или справа? Грамматика не указывает, и поэтому это неоднозначно.

Обычный способ решить эту проблему — с помощью объявления приоритета (см. руководство по bash), но его можно написать непосредственно в грамматике (см. ниже).

Однако, даже если оставить в стороне оператор @, ваша грамматика на самом деле не делает того, что вы хотите. Для начала вы, вероятно, захотите, чтобы основные литералы массивов соответствовали этой грамматике: [Примечание 1]

arr: '[' expr_list ']'    { $$ = $2; }
   | '[' ']'              { $$ = new std::vector<int>; }
expr_list
   : expr                 { $$ = new std::vector<int>; $$->push_back($1); }
   | expr_list ',' expr   { $1->push_back($3); }

И затем вы можете определить выражения конкатенации:

arr_concat
   : arr
   | arr_concat '@' arr   { std::copy($3->begin(), $3->end,
                                      std::back_inserter(*$1));
                            delete $3; // Note 2
                          }

Обратите внимание, что приведенное выше производство явно указывает на ассоциативность @. Никакая двусмысленность невозможна.


Примечания:

  1. Здесь я предполагаю, что вы объявили семантическое объединение, одним из типов которого является std::vector<int>*, потому что все эти приведения типов void* уродливы и небезопасны. Это будет что-то вроде:

    %union {
       std::vector<int>*   array_pointer;
       // ...
    }
    %type <array_pointer> arr expr_list arr_concat
    %%
    
  2. delete необходим, чтобы избежать утечки памяти, но где вы это сделаете, зависит от вашего подхода к управлению памятью. К сожалению, как только вы решите сохранить указатели на векторы, а не на самом деле векторы (и в этом случае у вас мало выбора, поскольку копирование векторов с каждым уменьшением было бы нелепым), вы берете на себя ответственность за управление памятью. Удаление семантических значений, как только они были включены в другие семантические значения, является простым решением, но это означает, что вы должны быть осторожны с другими копиями указателя на выделенный объект. Если вы следите за тем, чтобы на каждый выделенный объект всегда был только один указатель, немедленное delete сделает свое дело; в противном случае вам понадобится какая-то сборка мусора, возможно, на основе подсчета ссылок.

person rici    schedule 29.11.2015
comment
большое спасибо. Но, во-первых, я написал в приоритете следующее правило: %left '@', и оно все равно не сработало. Кроме того, второй способ, который вы предложили, действительно проблематичен в моей программе из-за времени, в которое я должен инициализировать векторы. Я просто не могу понять, как это сделать так, как вы предложили, и я пробовал это раньше. - person Shirli; 30.11.2015
comment
@shirli: ваша декларация %left, вероятно, не помогла из-за конфликта с ,. Этот конфликт является ошибкой, если я неправильно понимаю, что вы подразумеваете под конкатенацией. Желаемый синтаксис не [2,4]@[7]? Я вообще не понимаю, что у вас проблема со временем. - person rici; 30.11.2015
comment
@shirli: я добавил семантические правила, основываясь на своем предположении о том, что вы имеете в виду под синтаксисом и семантикой @. Действия expr_list ничем не отличаются от ваших действий arr, за исключением удаления всех уродливых пустых* слепков. Я не вижу проблемы со временем. - person rici; 30.11.2015
comment
Спасибо. Вы были правы в том, что написали о сроках — вы показали мне способ заставить то, что беспокоило меня о сроках, работать. Но все же ваше решение проблематично для того, что мне нужно, потому что: 1. arr_concat также должен быть arr - я хотел бы использовать его как любой другой массив типа arr для других функций, которые мне нужно реализовать.. 2. например если я хочу добавить: | '(' arr_concat ')' {$$ = $2;} в arr_concat, это: ([1]@[2])@[3] будет работать. Но, наоборот: [1]@([2]@[3]) не будет. Добавление: | arr '@' arr_concat в arr_concat приведет к конфликту сдвиг-уменьшение.. - person Shirli; 30.11.2015
comment
Кроме того, почему может возникнуть конфликт с ','? - person Shirli; 30.11.2015
comment
@shirli: Если вы хотите заключить объединение массивов в скобки, вам нужно добавить '(' arr_concat ')' к arr, а не к arr_concat. Посмотрите на любую стандартную грамматику выражений для других примеров. Имена нетерминалов, конечно, произвольны. Вы можете использовать arr_term и arr соответственно вместо arr и arr_concat, если хотите, чтобы самый верхний нетерминал назывался arr. - person rici; 30.11.2015
comment
Конфликт с , в исходной грамматике возникает из-за двусмысленности с ...1 @ ...2 , expr. Здесь либо ...1 @ ...2, либо ...2 , expr можно сократить до arr; в обоих случаях результат также может быть сведен к arr, и грамматика не позволяет решить, какая интерпретация верна. Есть и другие, более важные проблемы с вашей оригинальной формулировкой; в частности, используя первую, а затем повторно используя третью продукцию для arr, ваша грамматика примет [expr]]]]]]]. - person rici; 30.11.2015