了解列表操作符(%)在Boost.Spirit [英] Understanding the List Operator (%) in Boost.Spirit

查看:109
本文介绍了了解列表操作符(%)在Boost.Spirit的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你能帮助我理解 A%B 解析器和其扩展 A&GT之间的差别;&GT; *(B&GT;&GT; A)形式Boost.Spirit?尽管<一个href=\"http://www.boost.org/doc/libs/1_59_0/libs/spirit/doc/html/spirit/qi/reference/operator/list.html\">the参考手册指出,它们是等价的,


  

该列表操作符, A%B ,是匹配 A 的出现分离b 。这相当于 A&GT;&GT; *(B&GT;&GT; A)。


下面的程序产生取决于所使用的不同的结果:

 的#include&LT;&iostream的GT;
#包括LT&;串GT;
#包括LT&;矢量&GT;#包括LT&;升压/融合/有/ adapt_struct.hpp&GT;
#包括LT&;升压/精神/有/ qi.hpp&GT;结构记录{
  INT ID;
  的std ::矢量&lt;&INT GT;值;
};BOOST_FUSION_ADAPT_STRUCT(录音,
  (INT,ID)
  (性病::矢量&lt; INT&gt;中值)
)诠释主(){
  命名空间补气=的boost ::精神::补气;  常量汽车海峡=标准::字符串{1:2,3,4};  常量自动规则1 =补气:: int_&GT;&GT; ':'&GT;&GT; (齐:: int_%',')&GT;&GT;补气::意向书;
  常量自动规则2 =补气:: int_&GT;&GT; ':'&GT;&GT; (齐:: int_&GT;&GT; *(','&GT;&GT;气虚:: int_))&GT;&GT;补气::意向书;  记录RECORD1;
  如果(气:: phrase_parse(str.begin(),str.end(),规则1,补气::空间,RECORD1)){
    性病::法院LT&;&LT; record1.id&LT;&LT; :;
    对于(const的汽车和放大器;值:record1.values​​){性病::法院LT&;&LT;值&LT;&LT; ,; }
    性病::法院LT&;&LT;的'\\ n';
  }其他{
    的std :: CERR&LT;&LT; 语法错误。\\ n;
  }  记录RECORD2;
  如果(气:: phrase_parse(str.begin(),str.end(),规则2,补气::空间,RECORD2)){
    性病::法院LT&;&LT; record2.id&LT;&LT; :;
    对于(const的汽车和放大器;值:record2.values​​){性病::法院LT&;&LT;值&LT;&LT; ,; }
    性病::法院LT&;&LT;的'\\ n';
  }其他{
    的std :: CERR&LT;&LT; 语法错误。\\ n;
  }
}

住在Coliru

  1:2,3,4,
1:2,

规则1 规则2 仅在不同的规则1 使用列表操作符((气:: int_%','))和规则2 使用它的扩展形式( (气:: int_&GT;&GT; *(','&GT;&GT;气虚:: INT _)))。然而,规则1 制作 1:2,3,4,(预期)和规则2 制作 1:2,。我无法理解规则2 的结果:1)为什么是从规则1 它的不同,2)为什么是 3 4 不包含在 record2.values​​ 即使 phrase_parse 返回真不知何故?


解决方案

  

更新 X3版本添加


首先,你陷入了深深的陷​​阱在这里:

齐规则不符合汽车工作。使用齐::复制或只是用齐::规则&LT;&GT; 。你的程序有不确定的行为,实际上坠毁我(的valgrind指出在那里晃来晃去引用起源)。

所以,第一关:

 常量自动规则=齐::复制(气:: int_&GT;&GT;':'&GT;&GT;(气:: int_%',')&GT;&GT;齐:: EOI);

现在,当你在程序中删除冗余,您可以:

再现的问题

<大骨节病> 住在Coliru

  INT的main(){
    测试(气::复制(气:: int_&GT;&GT;':'&GT;&GT;(气:: int_%',')));
    测试(气::复制(气:: int_&GT;&GT;':'&GT;&GT;(气:: int_&GT;&GT; *(','&GT;&GT;气虚:: int_))));
}

打印

  1:2,3,4,
1:2,

的原因和修复

发生了什么事 3,4 这是<强>成功解析

那么,属性传播规则表明齐:: int_&GT;&GT; *(','&GT;&GT;气虚:: INT _)公开了一个元组LT; INT,矢量&lt;&INT GT; &GT; 。力图神奇DoTheRightThing(TM)精神不慎擦枪走火和assigngs的 INT 进入属性参照,忽视了其余的矢量&lt; INT&GT;

如果你想使容器的属性解析为原子团,使用齐::为&lt;&GT;

 试验(气::复制(气:: int_&GT;&GT;':'&GT;&GT;气虚::为&lt;记录:: values​​_t&GT;()[齐:: int_&GT;&GT; *(','&GT;&GT;气虚:: int_)));

下面为&lt;&GT; 充当属性兼容性启发式的障碍和语法都知道你是什么意思:

<大骨节病> 住在Coliru

 的#include&LT;&iostream的GT;
#包括LT&;串GT;
#包括LT&;矢量&GT;#包括LT&;升压/融合/有/ adapt_struct.hpp&GT;
#包括LT&;升压/精神/有/ qi.hpp&GT;结构记录{
  INT ID;
  使用values​​_t =的std ::矢量&lt; INT取代;
  values​​_t值;
};BOOST_FUSION_ADAPT_STRUCT(录音,ID,价值观)命名空间补气=的boost ::精神::补气;模板&LT; typename的T&GT;
无效测试(T const的&安培;规则){
    常量的std ::字符串str =1:2,3,4;    录音记录;    如果(气:: phrase_parse(str.begin(),str.end(),规则和GT;&GT;气虚:: EOI,补气::空间,记录)){
        性病::法院LT&;&LT; record.id&LT;&LT; :;
        对于(const的汽车和放大器;值:record.values​​){性病::法院LT&;&LT;值&LT;&LT; ,; }
        性病::法院LT&;&LT;的'\\ n';
    }其他{
        的std :: CERR&LT;&LT; 语法错误。\\ n;
    }
}诠释主(){
    测试(气::复制(气:: int_&GT;&GT;':'&GT;&GT;(气:: int_%',')));
    测试(气::复制(气:: int_&GT;&GT;':'&GT;&GT;(气:: int_&GT;&GT; *(','&GT;&GT;气虚:: int_))));
    测试(气::复制(气:: int_&GT;&GT;':'&GT;&GT;气虚::为&lt;记录:: values​​_t&GT;()[齐:: int_&GT;&GT; *(','&GT; &GT;气虚:: int_)));
}

打印

  1:2,3,4,
1:2,
1:2,3,4,

Can you help me understand the difference between the a % b parser and its expanded a >> *(b >> a) form in Boost.Spirit? Even though the reference manual states that they are equivalent,

The list operator, a % b, is a binary operator that matches a list of one or more repetitions of a separated by occurrences of b. This is equivalent to a >> *(b >> a).

the following program produces different results depending on which is used:

#include <iostream>
#include <string>
#include <vector>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

struct Record {
  int id;
  std::vector<int> values;
};

BOOST_FUSION_ADAPT_STRUCT(Record,
  (int, id)
  (std::vector<int>, values)
)

int main() {
  namespace qi = boost::spirit::qi;

  const auto str = std::string{"1: 2, 3, 4"};

  const auto rule1 = qi::int_ >> ':' >> (qi::int_ % ',')                 >> qi::eoi;
  const auto rule2 = qi::int_ >> ':' >> (qi::int_ >> *(',' >> qi::int_)) >> qi::eoi;

  Record record1;
  if (qi::phrase_parse(str.begin(), str.end(), rule1, qi::space, record1)) {
    std::cout << record1.id << ": ";
    for (const auto& value : record1.values) { std::cout << value << ", "; }
    std::cout << '\n';
  } else {
    std::cerr << "syntax error\n";
  }

  Record record2;
  if (qi::phrase_parse(str.begin(), str.end(), rule2, qi::space, record2)) {
    std::cout << record2.id << ": ";
    for (const auto& value : record2.values) { std::cout << value << ", "; }
    std::cout << '\n';
  } else {
    std::cerr << "syntax error\n";
  }
}

Live on Coliru

1: 2, 3, 4, 
1: 2, 

rule1 and rule2 are different only in that rule1 uses the list operator ((qi::int_ % ',')) and rule2 uses its expanded form ((qi::int_ >> *(',' >> qi::int_))). However, rule1 produced 1: 2, 3, 4, (as expected) and rule2 produced 1: 2,. I cannot understand the result of rule2: 1) why is it different from that of rule1 and 2) why were 3 and 4 not included in record2.values even though phrase_parse returned true somehow?

解决方案

Update X3 version added

First off, you fallen into a deep trap here:

Qi rules don't work with auto. Use qi::copy or just used qi::rule<>. Your program has undefined behaviour and indeed it crashed for me (valgrind pointed out where the dangling references originated).

So, first off:

const auto rule = qi::copy(qi::int_ >> ':' >> (qi::int_ % ',')                 >> qi::eoi); 

Now, when you delete the redundancy in the program, you get:

Reproducing the problem

Live On Coliru

int main() {
    test(qi::copy(qi::int_ >> ':' >> (qi::int_ % ',')));
    test(qi::copy(qi::int_ >> ':' >> (qi::int_ >> *(',' >> qi::int_))));
}

Printing

1: 2, 3, 4, 
1: 2, 

The cause and the fix

What happened to 3, 4 which was successfully parsed?

Well, the attribute propagation rules indicate that qi::int_ >> *(',' >> qi::int_) exposes a tuple<int, vector<int> >. In a bid to magically DoTheRightThing(TM) Spirit accidentally misfires and "assigngs" the int into the attribute reference, ignoring the remaining vector<int>.

If you want to make container attributes parse as "an atomic group", use qi::as<>:

test(qi::copy(qi::int_ >> ':' >> qi::as<Record::values_t>() [ qi::int_ >> *(',' >> qi::int_)]));

Here as<> acts as a barrier for the attribute compatibility heuristics and the grammar knows what you meant:

Live On Coliru

#include <iostream>
#include <string>
#include <vector>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

struct Record {
  int id;
  using values_t = std::vector<int>;
  values_t values;
};

BOOST_FUSION_ADAPT_STRUCT(Record, id, values)

namespace qi = boost::spirit::qi;

template <typename T>
void test(T const& rule) {
    const std::string str = "1: 2, 3, 4";

    Record record;

    if (qi::phrase_parse(str.begin(), str.end(), rule >> qi::eoi, qi::space, record)) {
        std::cout << record.id << ": ";
        for (const auto& value : record.values) { std::cout << value << ", "; }
        std::cout << '\n';
    } else {
        std::cerr << "syntax error\n";
    }
}

int main() {
    test(qi::copy(qi::int_ >> ':' >> (qi::int_ % ',')));
    test(qi::copy(qi::int_ >> ':' >> (qi::int_ >> *(',' >> qi::int_))));
    test(qi::copy(qi::int_ >> ':' >> qi::as<Record::values_t>() [ qi::int_ >> *(',' >> qi::int_)]));
}

Prints

1: 2, 3, 4, 
1: 2, 
1: 2, 3, 4, 

这篇关于了解列表操作符(%)在Boost.Spirit的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆