Copy or reference semantics of boost::spirit's rule<>?

前端 未结 1 912
情歌与酒
情歌与酒 2020-12-09 12:24

I am trying to write a shell language parser in Boost.Spirit. However, I am unclear about some basic issues regarding semantics of rules.

Looking at the

相关标签:
1条回答
  • 2020-12-09 12:49

    The answer depends on what version of Spirit you're referring to.


    Spirit.Classic (the former Spirit V1.x) implements special copy semantics for rules. The documentation says:

    When a rule is referenced anywhere in the right hand side of an EBNF expression, the rule is held by the expression by reference. It is the responsibility of the client to ensure that the referenced rule stays in scope and does not get destructed while it is being referenced.

    The assignment operator essentially references the rhs rule without creating a deep copy as well. This was done to allow:

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

    But this turned out to be highly confusion as it prevented handling rules the same way as 'normal' objects.

    For that reason there was the member function rule::copy(), allowing to make explicit deep copies of a rule (for instance to store them in an STL container).

    At the same time this:

    r2 = r1.copy();
    

    is plain wrong. r2 would refer to the (destructed) temporary copy of r1 returned from the function copy().


    In Spirit.Qi (i.e. Spirit V2.x) the behaviour is partially changed. rules are now behaving as expected when handled outside of parsers. You can store them normally in containers (the assignment operator exposes the expected behavior). But beware, that inside a parser expression rules are still held by reference, which still allows to refer to a rule the same way as before:

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

    Sometimes it's necessary to make a deep copy of a rule, so there is still the member functon copy.

    The changed copy semantics have another side effect. Constructs like:

    r1 = r2;
    

    are now creating a (deep) copy of r2, which might not be what you expect, especially if r2 will get its rhs assigned only after being 'assigned' to r1. For that reason there is the new member function alias enabling reference semantics for this corner case:

    r1 = r2.alias();
    

    In any case, in both versions of Spirit you will end up with dangling references if part of the rules referenced from a parser expression go out of scope.

    BTW, neither Spirit version implements a function rule::ref().

    0 讨论(0)
提交回复
热议问题