代码之家  ›  专栏  ›  技术社区  ›  jpalecek

复制或引用Boost::Spirit规则的语义<>?

  •  11
  • jpalecek  · 技术社区  · 14 年前

    我正试图用boost.spirit编写一个shell语言解析器。但是,我不清楚关于 rule S.

    查看文档时,有个成员 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
    

    同样,将从包含rule work类型右值的解析表达式分配给规则( 拷贝() 将是类型的右值 规则 也是吗?如。

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

    有人能告诉我 规则 的副本和参考资料,并可能纠正任何误解在这篇文章?

    1 回复  |  直到 14 年前
        1
  •  13
  •   hkaiser    14 年前

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


    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() .