Boost.Spirit X3 替代操作员
Boost.Spirit X3 Alternative Operator
我有以下代码:
#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 位 uint 向量,然后如果失败为 64 位 uint 向量。 如果列表中的第一个整数与足以容纳列表中任何其他内容的类型匹配,则此方法非常有用。即,
string ints32 = "1|2|3";
parse_int_list(being(ints32), end(ints32))
// prints vec(4): { 1, 2, 3, }
string ints64 = "10000000000|20000000000|30000000000";
parse_int_list(being(ints64), end(ints64))
// prints vec(8): { 10000000000, 20000000000, 30000000000, }
但是,当第一个数字是 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
实际上返回了解析成功。 我正在检查它是否已经解析了整个流,first == last
,以确定成功,如文档所示。 然而,这掩盖了一个事实,即由于klean star的贪婪性质并且不锚定到流的末端,它能够成功地解析部分输入。 谢谢大家。
这里的问题是"3"是(x3::uint32 % '|')
解析器的有效输入,因此替代的第一个分支通过,仅使用3。
解决此问题的最干净方法是使用替代项列表而不是列表的替代项。
即:
(x3::uint32 | x3::uint64) % '|'
但是,这意味着您必须在不同的结构中进行解析。
vector<x3::variant<uint32_t,uint64_t>> vecs;
编辑:
或者,如果您不打算将此解析器用作子解析器,则可以在每个分支中强制输入结束。
(x3::uint32 % '|' >> x3::eoi) | (x3::uint64 % '|' >> x3::eoi)
如果第一个分支没有到达流的末尾,这将强制它失败,从而掉入替代分支。
正如 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());
}
}
指纹
vec(4): { 1, 2, 3, }
vec(4): { 4294967295, }
vec(8): { 4294967296, }
vec(8): { 4294967295, 4294967296, }
相关文章:
- <<操作员在下面的行中工作
- C++ 与操作员不匹配<<
- 操作员C++的模棱两可的过载
- 提升精神 x3 - 懒惰解析器
- C++中>>操作员过载时出现问题?
- boost::spirit::x3 中的通用解析器生成器
- 增强精神 X3:错误:在"..."中没有名为"大小"的类型
- NaN 上的宇宙飞船操作员
- 提升精神 x3 解析为结构,如果它为空,则跳过成员
- 比根<操作员
- SFINAE不能防止模棱两可的操作员过载吗?
- 什么是现实中的"endl"(或任何输出操纵器)?它是如何实现的,它如何与操作员<<一起工
- 如何处理Boost Spirit X3导致Visual Studio 2019 "static initialization order fiasco"?
- Boost Spirit X3:将(一些)空格解析为枚举
- Boost Spirit x3 条件(三元)运算符解析器
- 你如何从 Boost Spirit X3 词法解析器中获取字符串?
- 将 Boost.Spirit.X3 解析器拆分为多个 TU
- 为什么"delete"操作员给我访问权限冲突
- boost::spirit::x3 中的简单字符串解析器不起作用
- Boost.Spirit X3 替代操作员