How would one create a rule for reading integers in sets of 3. I.e., ...
1 2 3 OK, 1 set of 3 ints
1 2 3 4 5 6 OK, 2 sets of 3 ints
1 2 3 4 5 ERROR, 1 set of 3 ints, 1 short for 2nd
1 2 3 4 5 6 7 8 9 OK, 3 sets of 3 ints
1 2 3 4 5 6 7 8 9 10 ERROR, 3 sets of 3 ints, 1 short for 4th
I'm having issue with the fusion adapt struct (how to make the number of args variable) ...
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, n1, n2, n3, n4, n5, n6)
And not sure why this rule wouldn't work.
... = *(int_ >> int_ >> int_);
Here's my attempt ... http://coliru.stacked-crooked.com/a/cb10e8096c95fc55
//#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 {
int n1, n2, n3, n4, n5, n6;
};
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, n1, n2, n3) // , n4, n5, n6) error
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_;
// auto const number = rule<struct _n, ast::number> {"number"} = *(int_ >> int_ >> int_); error
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");
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: " << boost::fusion::as_deque(item) << "\n"; }
}
Printing
Parsed: 71.0526%
ok = 1
comment: (any char string here 0)
number: (1 2 3)
Operator Kleene-star synthesizes into a container attribute (docs show:
vector<T>
)Your struct
number
is not a container attribute. So.Also, it's completely unclear to me what you want to achieve. Your struct is supposedly 6 ints, but you want to parse groups of 3? What is the meaning of the groups? I'd probably do:
This then is compatible with the parser expression
Live Demo
Two notes:
using number = std::vector<number_group>;
)\n
at the end of input (considereol | eoi
)Live On Coliru
Prints