我试图在Boost.Spirit中编写一个shell语言解析器。但是,我不清楚有关语义的一些基本问题 rule
秒。
查看文档,有成员 r.alias()
和 r.copy()
的 rule
。 IIUC,这些成员应分别返回对规则的引用和规则内容的副本。但是,我没有明确说明当我在另一个规则的定义中使用该规则时会发生什么。从我的实验中,我发现相互递归规则可以通过以下方式定义:
rule<Iter> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;
这表明规则是通过解析器表达式中的引用来获取的。问题是,当变量超出范围时它会做什么,例如:
rule<Iter> r1;
{
rule<Iter> r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;
}
... // use r1
在同一个注释中,将从包含类型规则工作的右值的解析表达式分配规则(r.copy()
将是一个类型的右值 rule
也是,不是吗?例如。
rule<Iter> f() { return char_('a') << char_('b'); }
rule<Iter> r1 = ... << f();
任何人都可以在详细的语义上启发我 rule
的副本和参考,并可能纠正这篇文章中的任何误解?
答案取决于你所指的精神版本。
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 >> ...;
有时需要制作规则的深层副本,因此仍然存在成员功能 copy
。
更改的复制语义有另一个副作用。构造如:
r1 = r2;
现在正在创建一个(深层)副本 r2
,这可能不是你所期望的,特别是如果 r2
只有在被“分配”之后才会分配它的rhs r1
。因此,有新的成员函数 alias
为这个角点案例启用引用语义:
r1 = r2.alias();
在任何情况下,在两个版本的Spirit中,如果从解析器表达式引用的部分规则超出范围,您将最终得到悬空引用。
顺便说一下,Spirit版本都没有实现一个功能 rule::ref()
。
答案取决于你所指的精神版本。
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 >> ...;
有时需要制作规则的深层副本,因此仍然存在成员功能 copy
。
更改的复制语义有另一个副作用。构造如:
r1 = r2;
现在正在创建一个(深层)副本 r2
,这可能不是你所期望的,特别是如果 r2
只有在被“分配”之后才会分配它的rhs r1
。因此,有新的成员函数 alias
为这个角点案例启用引用语义:
r1 = r2.alias();
在任何情况下,在两个版本的Spirit中,如果从解析器表达式引用的部分规则超出范围,您将最终得到悬空引用。
顺便说一下,Spirit版本都没有实现一个功能 rule::ref()
。