我尝试调整此示例以使用组向量而不是硬编码3个整数(n1,n2,n3)来使用可变数量的元素,但无济于事。
以下是我尝试修改的示例。 coliru.stacked-crooked.com/a/90110f91a4ac466a
这是代码。
#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
namespace client {
namespace ast {
struct number {
//struct group { int n1, n2, n3; }; // instead of 3 ints ...
struct group {
std::vector<int> persons; // get a variable number
//bool dummy;
};
std::vector<group> groups;
bool dummy;
};
struct comment {
std::string text;
bool dummy;
};
struct input {
std::vector<comment> comments;
std::vector<number> numbers;
};
}
}
BOOST_FUSION_ADAPT_STRUCT(client::ast::comment, text, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number::group, persons)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, groups, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, comments, numbers)
namespace client {
namespace parser {
namespace x3 = boost::spirit::x3;
using namespace x3;
typedef std::string::const_iterator It;
using namespace x3;
auto const comment = rule<struct _c, ast::comment> {"comment"} = lexeme[*(char_ - eol)] >> attr(false);
auto const number = rule<struct _n, ast::number> {"number"} = *(int_ >> int_ >> int_) >> attr(false);
auto lines = [](auto p) { return *(p >> eol); };
auto const input =
repeat(1)[comment] >> eol >>
lines(number);
}
}
int main() {
namespace x3 = boost::spirit::x3;
std::string const iss("any char string here\n1 2 3\n1 2 3 4 5 6\n1 2 3 4 5 6 7 8 9\n");
auto iter = iss.begin(), eof = iss.end();
client::ast::input types;
bool ok = phrase_parse(iter, eof, client::parser::input, x3::blank, types);
if (iter != eof) {
std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
}
std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
std::cout << "ok = " << ok << std::endl;
for (auto &item : types.comments) {
std::cout << "comment: " << boost::fusion::as_deque(item) << "\n";
}
/*for (auto& item : types.numbers) {
std::cout << "number: ";
for (auto& g : item.groups)
std::cout << boost::fusion::as_deque(g) << " ";
std::cout << "\n";
}*/
}
错误消息在模板的深处看起来总是一样。因此,不是对要解析的int的数量进行硬编码,而是int的数量应该是可变的,但仍然可以被3整除(即,一行上的整数总数是3,6,9等等)。
答案 0 :(得分:2)
这是一个极大的简化。
如果您只想解析带有n个数字的行:
*int_
如果要验证数字n可以被3整除:
(*int_) [is_valid_group]
语义操作可以进行检查
auto is_valid_group = [](auto& ctx) {
_pass(ctx) = 0 == (_val(ctx).size() % 3);
};
现在整个AST可以简单地:
using person = int;
using groups_line = std::vector<person>;
using comment_line = std::string;
struct input {
comment_line comments;
std::vector<groups_line> numbers;
};
整个语法:
auto const comment_line
= lexeme[*(char_ - eol)];
auto const groups_line
= rule<struct _n, ast::groups_line, true> {"groups_line"}
= *int_ >> eps [ is_valid_group ];
auto const input =
comment_line >> eol >>
*(groups_line >> eol);
<强> Live On Coliru 强>
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace client {
namespace ast {
using person = int;
using groups_line = std::vector<person>;
using comment_line = std::string;
struct input {
comment_line comments;
std::vector<groups_line> numbers;
};
}
}
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, comments, numbers)
namespace client {
namespace parser {
namespace x3 = boost::spirit::x3;
using namespace x3;
typedef std::string::const_iterator It;
using namespace x3;
auto is_valid_group = [](auto& ctx) {
_pass(ctx) = 0 == (_val(ctx).size() % 3);
};
auto const comment_line
//= rule<struct _c, ast::comment_line> {"comment_line"}
= lexeme[*(char_ - eol)];
auto const groups_line
= rule<struct _n, ast::groups_line, true> {"groups_line"}
= *int_ >> eps [ is_valid_group ];
auto const input =
comment_line >> eol >>
*(groups_line >> eol);
}
}
int main() {
namespace x3 = boost::spirit::x3;
std::string const iss("any char string here\n1 2 3\n1 2 3 4 5 6\n1 2 3 4 5 6 7 8 9\n1 2 3 4");
auto iter = iss.begin(), eof = iss.end();
client::ast::input types;
bool ok = phrase_parse(iter, eof, client::parser::input, x3::blank, types);
if (iter != eof) {
std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
}
std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
std::cout << "ok = " << ok << std::endl;
std::cout << "comment: " << types.comments << "\n";
for (auto& group : types.numbers) {
std::cout << "number: ";
for (auto& person : group) std::cout << person << " ";
std::cout << "\n";
}
}
打印
Remaining unparsed: '1 2 3 4'
Parsed: 89.0625%
ok = 1
comment: any char string here
number: 1 2 3
number: 1 2 3 4 5 6
number: 1 2 3 4 5 6 7 8 9