Boost Qi使用函数编写规则

时间:2015-01-07 05:04:17

标签: c++ boost boost-spirit boost-spirit-qi

我尝试为语言的多个子集定义一些Boost :: spirit :: qi解析器,并且代码重复最少。为此,我创建了一些基本的规则构建函数。原始解析器工作正常,但一旦我开始使用组合函数,我的解析器似乎不再起作用。

通用语言的形式如下:

A B: C

语言的子集中ABC必须是特定类型,例如A是int而BC是花车。这是我用于该子语言的解析器:

using entry = boost::tuple<int, float, float>;

template <typename Iterator>
struct sublang : grammar<Iterator, entry(), ascii::space_type>
{
   sublang() : sublang::base_type(start)
   {
       start = int_ >> float_ >> ':' >> float_;
   }
   rule<Iterator, entry(), ascii::space_type> start;
};

但是由于有很多子集,我尝试创建一个函数来构建我的解析器规则:

template<typename AttrName, typename Value>
auto attribute(AttrName attrName, Value value)
{
    return attrName >> ':' >> value;
}

这样我就可以更轻松地为每个子集构建解析器而无需重复信息:

// in sublang
start = int_ >> attribute(float_, float_);

然而这失败了,我不知道为什么。在我的clang测试中,解析失败了。在g ++中,程序似乎崩溃了。

以下是完整的示例代码:http://coliru.stacked-crooked.com/a/8636f19b2e9bff8d

当前代码有什么问题?这个问题的正确方法是什么?我想避免在每个子语言解析器中指定属性和其他元素的语法。

1 个答案:

答案 0 :(得分:3)

非常简单:使用auto与Spirit(或任何基于Boost Proto和Boost Phoenix的EDSL)很可能是UndefinedBehaviour¹

现在,您通常可以使用

解决此问题
  • BOOST_SPIRIT_AUTO
  • boost::proto::deep_copy
  • 最新版本的Boost(TODO添加链接)中的新设施

在这种情况下,

template<typename AttrName, typename Value>
auto attribute(AttrName attrName, Value value) {
    return boost::proto::deep_copy(attrName >> ':' >> value);
}

修正了它: Live On Coliru

替代地

  1. 您可以将qi::lazy[]与继承的属性一起使用。

    我在Reading JSON file with C++ and BOOSTprop_key规则中做了类似的事情。

  2. 您可以查看Spirit Repository中的 Keyword List Operator 。它的设计允许更容易构建语法,如:

    no_constraint_person_rule %=
        kwd("name")['=' > parse_string ]
      / kwd("age")   ['=' > int_]
      / kwd("size")   ['=' > double_ > 'm']
      ;
    
  3. 这可能会与Nabialek Trick结合使用。我在SO上搜索答案的例子。 (一个是Grammar balancing issue


  4. ¹除了完全无国籍的演员(Eric Niebler on this)和表达占位符之外。参见例如

    一些例子