C++ Boost.Spirit X3替代运营商
我有以下代码:C++ Boost.Spirit X3替代运营商,c++,boost-spirit,boost-spirit-x3,C++,Boost Spirit,Boost Spirit X3,我有以下代码: #include <boost/spirit/home/x3.hpp> #include <boost/spirit/home/x3/support/ast/variant.hpp> struct printer { template <typename int_type> void operator()(std::vector<int_type> &vec) { std::cout <
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
struct printer {
template <typename int_type>
void operator()(std::vector<int_type> &vec) {
std::cout << "vec(" << sizeof(int_type) << "): { ";
for( auto const &elem : vec ){
std::cout << elem << ", ";
}
std::cout << "}\n";
}
};
template <typename Iterator>
void parse_int_list(Iterator first, Iterator last) {
namespace x3 = boost::spirit::x3;
x3::variant<vector<uint32_t>, vector<uint64_t>> vecs;
x3::parse( first, last,
(x3::uint32 % '|') | (x3::uint64 % '|'), vecs );
boost::apply_visitor(printer{}, vecs);
}
但是,当第一个数字是32位,后面的数字是64位时,它不起作用
string ints_mixed = "1|20000000000|30000000000";
parse_int_list(being(ints_mixed), end(ints_mixed))
// prints vec(4): { 1, }
x3::parse
的返回值表示解析失败。但根据我对它的理解,若它不能用第一种方法解析,那个么应该尝试第二种方法
有没有关于我如何错误地阅读此内容以及替代解析器如何实际工作的指针
编辑:在看到响应后,我意识到x3::parse
实际上返回了一个parse成功。我正在检查它是否解析了整个流,first==last
,以确定是否成功,如文档中所示。然而,这隐藏了一个事实,即由于klean star的贪婪性质,并且没有锚定到流的末尾,它成功地解析了输入的一部分。谢谢大家。这里的问题是“3”是(x3::uint32%'|')
解析器的有效输入,因此可选过程的第一个分支只使用3
解决这个问题的最干净的方法是使用一个替代列表,而不是列表的替代
i、 e:
但是,这意味着您必须在不同的结构中进行解析
vector<x3::variant<uint32_t,uint64_t>> vecs;
这将迫使第一个分支在未到达流的末尾时失败,并掉入备选分支。这里的问题是,“3”是(x3::uint32%'|')
解析器的有效输入,因此备选分支的第一个分支通过,只使用3
解决这个问题的最干净的方法是使用一个替代列表,而不是列表的替代
i、 e:
但是,这意味着您必须在不同的结构中进行解析
vector<x3::variant<uint32_t,uint64_t>> vecs;
这将迫使第一个分支失败,如果它没有到达流的末尾,就会掉入另一个分支。正如Frank评论的那样,Kleene list操作符贪婪,接受尽可能多的匹配元素,并认为这是一个“匹配” 如果您希望它在“某些元素尚未解析”时拒绝输入,请执行以下操作:
parse(first, last, x3::uint32 % '|' >> x3::eoi | x3::uint64 % '|' >> x3::eoi, vecs);
演示
#include <boost/spirit/home/x3.hpp>
#include <iostream>
struct printer {
template <typename int_type> void operator()(std::vector<int_type> &vec) const {
std::cout << "vec(" << sizeof(int_type) << "): { ";
for (auto const &elem : vec) {
std::cout << elem << ", ";
}
std::cout << "}\n";
}
};
template <typename Iterator> void parse_int_list(Iterator first, Iterator last) {
namespace x3 = boost::spirit::x3;
boost::variant<std::vector<uint32_t>, std::vector<uint64_t> > vecs;
parse(first, last, x3::uint32 % '|' >> x3::eoi | x3::uint64 % '|' >> x3::eoi, vecs);
apply_visitor(printer{}, vecs);
}
int main() {
for (std::string const input : {
"1|2|3",
"4294967295",
"4294967296",
"4294967295|4294967296",
}) {
parse_int_list(input.begin(), input.end());
}
}
正如Frank所评论的,Kleene列表操作符的问题在于贪婪,接受尽可能多的匹配元素,并认为这是一个“匹配” 如果您希望它在“某些元素尚未解析”时拒绝输入,请执行以下操作:
parse(first, last, x3::uint32 % '|' >> x3::eoi | x3::uint64 % '|' >> x3::eoi, vecs);
演示
#include <boost/spirit/home/x3.hpp>
#include <iostream>
struct printer {
template <typename int_type> void operator()(std::vector<int_type> &vec) const {
std::cout << "vec(" << sizeof(int_type) << "): { ";
for (auto const &elem : vec) {
std::cout << elem << ", ";
}
std::cout << "}\n";
}
};
template <typename Iterator> void parse_int_list(Iterator first, Iterator last) {
namespace x3 = boost::spirit::x3;
boost::variant<std::vector<uint32_t>, std::vector<uint64_t> > vecs;
parse(first, last, x3::uint32 % '|' >> x3::eoi | x3::uint64 % '|' >> x3::eoi, vecs);
apply_visitor(printer{}, vecs);
}
int main() {
for (std::string const input : {
"1|2|3",
"4294967295",
"4294967296",
"4294967295|4294967296",
}) {
parse_int_list(input.begin(), input.end());
}
}
我不确定X3的情况,但常规spirit list(%)解析器是贪婪的,因为它们在第一个元素通过时就匹配。我不确定X3的情况,但常规spirit list(%)解析器是贪婪的,因为它们在第一个元素通过时就匹配。所以。基本上,你根本不知道这是否是一种修复它的方法:)我同意,AST的选择一开始似乎是一个糟糕的设计。无论如何,我认为,注意解析器的问题比猜测解决方案更有趣。你最终提出了和我一样的语义修正+1您能详细解释一下解析器和子解析器之间的区别吗?有文件记录吗?(我感觉X3文档遗漏了一些人们可能已经知道的东西,如果这些东西来自Qi)。基本上,你根本不知道这是否是一种修复它的方法:)我同意,AST的选择一开始似乎是一个糟糕的设计。无论如何,我认为,注意解析器的问题比猜测解决方案更有趣。你最终提出了和我一样的语义修正+1您能详细解释一下解析器和子解析器之间的区别吗?有文件记录吗?(我感觉X3文档遗漏了一些人们可能已经知道的东西,如果他们来自Qi的话。)添加了一个演示。不知道为什么我忘了早些时候。添加了一个演示。不知道为什么我忘得更早。
vec(4): { 1, 2, 3, }
vec(4): { 4294967295, }
vec(8): { 4294967296, }
vec(8): { 4294967295, 4294967296, }