Копировать или ссылочную семантику boost :: spirit’s rule ?

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

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

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

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

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

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

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

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

Ответ зависит от того, какую версию Духа вы имеете в виду.


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

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

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

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

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

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

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

 r2 = r1.copy(); 

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


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

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

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

Измененная семантика копии имеет другой побочный эффект. Создает:

 r1 = r2; 

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

 r1 = r2.alias(); 

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

BTW, ни версия Spirit не реализует rule::ref() функции rule::ref() .