【问题标题】:Compound Attribute generation in Boost::Spirit parse ruleBoost::Spirit 解析规则中的复合属性生成
【发布时间】:2013-07-25 23:44:35
【问题描述】:

我的解析规则如下:

filter = (input >> (qi::repeat(0,2)[char_(';') >> input]))

input 是一个返回std::vector<int> 的规则,我将简称为vec

问题是:filter 规则会返回什么复合属性?

我试过了:

fusion::vector <vec,std::vector <fusion::vector <char,vec> > >

但它失败了,我不知道为什么。

【问题讨论】:

标签: boost boost-spirit boost-spirit-qi


【解决方案1】:

解析器表达式生成的属性类型为quite well-documented。但这可能会让人迷失方向且耗时。

这里有个技巧:发送一个哨兵来检测属性类型:

struct Sniffer
{
    typedef void result_type;

    template <typename T>
    void operator()(T const&) const { std::cout << typeid(T).name() << "\n"; }
};

然后使用后面的解析器表达式

 (input >> (qi::repeat(0,2)[qi::char_(';') >> input])) [ Sniffer() ]

将转储:

N5boost6fusion7vector2ISt6vectorIsSaIsEES2_INS1_IcS4_EESaIS5_EEEE

c++filt -1 会告诉你代表:

boost::fusion::vector2<
    std::vector<short, std::allocator<short> >, 
    std::vector<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > >, 
                std::allocator<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > > 
            > > 
 >

在 Coliru 上现场观看:http://coliru.stacked-crooked.com/view?id=3e767990571f8d0917aae745bccfa520-5c1d29aa57205c65cfb2587775d52d22

boost::fusion::vector2<std::vector<short, std::allocator<short> >, std::vector<std::vector<short, std::allocator<short> >, std::allocator<std::vector<short, std::allocator<short> > > > >

它可能如此复杂,部分原因是char_(";") 可能是';'(或更明确地说是lit(';'))。 Constrast with this (Coliru):

boost::fusion::vector2<
    std::vector<short, ... >, 
    std::vector<std::vector<short, std::allocator<short> >, ... > >

这应该可以回答您的问题。

旁注:解析事物

不要低估 Spirit 中的自动属性传播。通常,您不必为 exact 公开的属性类型而烦恼。相反,依靠 Spirit 使用的(许多)属性转换将它们分配给您提供的属性引用。

我相信您在精神上了解列表操作员 (%)?我会告诉你如何使用它,不用多说:

vector<vector<short>> data;

qi::parse(f, l, qi::short_ % ',' % ';', data);

现在,如果您需要强制它可能是 1-3 个元素,您可以使用带有 Phoenix 操作的 eps 来声明最大大小:

const string x = "1,2,3;2,3,4;3,4,5";
auto f(begin(x)), l(end(x));

if (qi::parse(f, l, 
        (qi::eps(phx::size(qi::_val) < 2) > (qi::short_ % ',')) % ';'
        , data))
{
    cout << karma::format(karma::short_ % ',' % ';', data) << "\n";
}
cout << "remaining unparsed: '" << std::string(f,l) << "'\n";

打印:

1,2,3;2,3,4
remaining unparsed: ';3,4,5'

【讨论】:

  • 首先,感谢您提供详细而翔实的答案!奇怪的是,您的代码建议的属性与我尝试的属性相同!唯一的区别是您明确指定了fusion::vector2,而我只是将其命名为fusion::vector,它接受2 个模板参数。据我了解,两者应该是等价的。总而言之,这有效:fusion::vector &lt;vec,std::vector &lt;fusion::vector2 &lt;char,vec&gt; &gt; &gt; 而这无效:fusion::vector &lt;vec,std::vector &lt;fusion::vector &lt;char,vec&gt; &gt; &gt; 我不知道这是一个错误还是什么。
  • 请注意我从来没有在第一个中指定fusion::vector2,所以我真的不知道为什么我必须在第二个中指定(可能是错误?)。你的答案和属性检测器引导我朝着正确的方向前进,所以我认为你的答案是正确的,但我仍然不知道为什么在这种情况下我不得不使用 fusion::vector2
  • @jay1189947 嗯。我认为最重要的收获是 this:请注意我什至从未指定 any fusion::* 类型 at all。在我看来,fusion 序列是一个实现细节,你应该只在编写自定义点时处理,或者可能在调整结构时处理 (BOOST_FUSION_ADAPT_STRUCT)。
  • 另外,请注意容器属性具有更多“神奇”属性(例如 *int_ &gt;&gt; ';' &gt;&gt; *int_ 可以与仅公开单个 std::vector&lt;int&gt; 的规则一起使用。但这一切都变得有点遥远。我建议进行一些试验(也许在这样做的同时查看机制)是了解 Boost Spirit 必须提供的便利程度(有时是惊喜)的最佳方式。
  • 问题是我正在处理更复杂的结构,所以我不能使用默认的合成属性,需要使用规则上下文通过语义动作自己构建属性。我已经多次仔细阅读文档,所以我知道复合属性是如何合成的,这正是我很困惑的原因,以至于我的第一个示例不起作用(而且我仍然声称这是一个错误)。再次感谢您的时间和回复!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多