Копировать или ссылаться на семантику boost :: spirit's rule <>?

Я пытаюсь написать анализатор языка оболочки в Boost.Spirit. Однако мне неясно, какие основные вопросы касаются семантики правила правила с.

Глядя на документацию, есть члены r.alias () и r.copy. () Правило . IIUC, эти члены должны возвращать ссылку на правило и копию содержания правила, соответственно. Однако неясно, что происходит, когда я просто использую правило в определении другого правила. Из моих экспериментов я обнаружил, что взаимно рекурсивные правила могут быть определены с помощью:

rule<Iter> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;

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

rule<Iter> r1;
{ 
  rule<Iter> r2;
  r1 = ... >> r2 >> ...;
  r2 = ... >> r1 >> ...;
}
... // use r1

В той же заметке, будет ли присвоение правилу из выражения синтаксического анализа, содержащего r-значение работы правила типа ( r.copy () также будет r-значением правила типа )? например,

rule<Iter> f() { return char_('a') << char_('b'); }
rule<Iter> r1 = ... << f();

Может ли кто-нибудь просветить меня в отношении подробной семантики копий и ссылок правила , и, возможно, исправить какие-либо неправильные представления в этом посте?

11
задан jpalecek 13 August 2010 в 21:02
поделиться

1 ответ

Ответ зависит от того, о какой версии Spirit вы имеете в виду.


Spirit.Classic (бывший Spirit V1.x) реализует специальную семантику копирования для правил. В документации говорится:

Когда на правило ссылаются где-нибудь в правая часть EBNF выражение, правило проводится выражение по ссылке. Это ответственность клиента за обеспечение что указанное правило остается в область действия и не разрушается пока на него ссылаются.

Оператор присваивания по существу ссылается на правило rhs, не создавая также полную копию. Это было сделано для того, чтобы разрешить:

rule<> r1, r2;
r1 = ...;
r2 = r1;

Но это оказалось большой путаницей, поскольку не позволяло обрабатывать правила так же, как «нормальные» объекты.

По этой причине существовала функция-член rule :: copy () , позволяющая делать явные глубокие копии правила (например, сохранять их в контейнере STL).

В то же время это:

r2 = r1.copy();

совершенно неверно. r2 будет относиться к (разрушенной) временной копии r1 , возвращенной функцией copy () .


В Spirit.Qi (т.е. Spirit V2.x) поведение частично изменено.правила теперь работают должным образом при обработке вне парсеров. Вы можете хранить их обычно в контейнерах (оператор присваивания показывает ожидаемое поведение). Но имейте в виду, что внутри выражения синтаксического анализатора правила по-прежнему хранятся по ссылке, что по-прежнему позволяет ссылаться на правило так же, как и раньше:

rule<> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;

Иногда необходимо сделать полную копию правила, чтобы член все еще оставался функция копия .

У измененной семантики копирования есть еще один побочный эффект. Такие конструкции, как:

r1 = r2;

теперь создают (глубокую) копию r2 , что может быть не тем, что вы ожидаете, особенно если r2 получит свои права доступа только после 'назначения 'на r1 . По этой причине существует новая функция-член псевдоним , разрешающая семантику ссылок для этого углового случая:

r1 = r2.alias();

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

Кстати, ни одна из версий Spirit не реализует функцию rule :: ref () .

14
ответ дан 3 December 2019 в 08:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: