了解列表操作符(%)在Boost.Spirit [英] Understanding the List Operator (%) in Boost.Spirit
问题描述
你能帮助我理解 A%B
解析器和其扩展 A&GT之间的差别;> *(B>> 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 $ C $的一个或多个重复的列表的二元运算符C>按
的出现分离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;
}
}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 expandeda >> *(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 ofa
separated by occurrences ofb
. This is equivalent toa >> *(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"; } }
1: 2, 3, 4, 1: 2,
rule1
andrule2
are different only in thatrule1
uses the list operator ((qi::int_ % ',')
) andrule2
uses its expanded form ((qi::int_ >> *(',' >> qi::int_))
). However,rule1
produced1: 2, 3, 4,
(as expected) andrule2
produced1: 2,
. I cannot understand the result ofrule2
: 1) why is it different from that ofrule1
and 2) why were3
and4
not included inrecord2.values
even thoughphrase_parse
returned true somehow?解决方案Update X3 version added
First off, you fallen into a deep trap here:
Qi rules don't work with
auto
. Useqi::copy
or just usedqi::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
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 atuple<int, vector<int> >
. In a bid to magically DoTheRightThing(TM) Spirit accidentally misfires and "assigngs" theint
into the attribute reference, ignoring the remainingvector<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:#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屋!