复制或引用boost :: spirit的规则<>的语义?

jpa*_*cek 11 c++ boost-spirit

我试图在Boost.Spirit中编写一个shell语言解析器.但是,我不清楚有关rules 语义的一些基本问题.

综观文档,有成员r.alias()r.copy()rule.IIUC,这些成员应分别返回对规则的引用和规则内容的副本.但是,我没有明确说明当我在另一个规则的定义中使用该规则时会发生什么.从我的实验中,我发现相互递归规则可以通过以下方式定义:

rule<Iter> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;
Run Code Online (Sandbox Code Playgroud)

这表明规则是通过解析器表达式中的引用来获取的.问题是,当变量超出范围时它会做什么,例如:

rule<Iter> r1;
{ 
  rule<Iter> r2;
  r1 = ... >> r2 >> ...;
  r2 = ... >> r1 >> ...;
}
... // use r1
Run Code Online (Sandbox Code Playgroud)

在同一个注释中,将从包含类型规则工作的rvalue的解析表达式中分配规则(r.copy()也将是类型的右值rule,不是吗)?例如.

rule<Iter> f() { return char_('a') << char_('b'); }
rule<Iter> r1 = ... << f();
Run Code Online (Sandbox Code Playgroud)

任何人都可以启发我rule的副本和引用的详细语义,并可能纠正这篇文章中的任何误解吗?

hka*_*ser 14

答案取决于你所指的精神版本.


Spirit.Classic(前Spirit V1.x)为规则实现特殊的复制语义.文件说:

当在EBNF表达式的右侧任何地方引用规则时,该规则由引用表达式保存.客户端有责任确保引用的规则保留在范围内,并且在引用时不会被破坏.

赋值运算符实际上引用了rhs规则,而不创建深层副本.这样做是为了允许:

rule<> r1, r2;
r1 = ...;
r2 = r1;
Run Code Online (Sandbox Code Playgroud)

但事实证明这是一种高度混乱,因为它与"正常"对象一样阻止了处理规则.

出于这个原因,有成员函数rule::copy(),允许制定规则的显式深层副本(例如将它们存储在STL容器中).

同时这个:

r2 = r1.copy();
Run Code Online (Sandbox Code Playgroud)

是完全错的.r2将引用r1从函数返回的(破坏的)临时副本copy().


在Spirit.Qi(即Spirit V2.x)中,行为被部分改变.当在解析器之外处理时,规则现在按预期运行.您可以将它们正常存储在容器中(赋值运算符公开预期的行为).但请注意,在解析器中,表达式规则仍然通过引用保留,这仍然允许以与以前相同的方式引用规则:

rule<> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;
Run Code Online (Sandbox Code Playgroud)

有时需要制作规则的深层副本,因此仍然存在成员功能copy.

更改的复制语义具有另一个副作用.构造如:

r1 = r2;
Run Code Online (Sandbox Code Playgroud)

现在正在创建一个(深层)副本r2,这可能不是您所期望的,特别是如果r2仅在被"分配"后才分配其rhs r1.出于这个原因,有一个新的成员函数alias为这个角点案例启用了引用语义:

r1 = r2.alias();
Run Code Online (Sandbox Code Playgroud)

在任何情况下,在两个版本的Spirit中,如果从解析器表达式引用的部分规则超出范围,您将最终得到悬空引用.

顺便说一下,Spirit版本都没有实现一个功能rule::ref().