Reputation: 162
Based on an answer here, I wrote the following parser:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <fstream>
#include <iostream>
#include <vector>
namespace x3 = boost::spirit::x3;
int main() {
std::ifstream input("input.txt");
boost::spirit::istream_iterator begin(input >> std::noskipws), end;
std::vector<float> data1, data2;
auto capture1 = [&](auto& ctx){ data1.emplace_back(_attr(ctx)); };
auto capture2 = [&](auto& ctx){ data2.emplace_back(_attr(ctx)); };
auto sequence1 = "v" >> x3::float_[capture1] >> x3::float_[capture1] >> x3::float_[capture1];
auto sequence2 = "vn" >> x3::float_[capture2] >> x3::float_[capture2] >> x3::float_[capture2];
auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> (x3::eol|x3::eoi);
auto rule = x3::skip(skipper) [ *x3::eol >>
*( +(sequence1 >> (x3::eoi|+x3::eol) ) >>
*(sequence2 >> (x3::eoi|+x3::eol) ) )
];
if (x3::parse(begin, end, rule)) {
std::cout << "data1 size: " << data1.size() << "\n";
for(float& i:data1)
std::cout << i << ", ";
std::cout << '\n';
std::cout << "data2 size: " << data2.size() << "\n";
for(float& i:data2)
std::cout << i << ", ";
std::cout << '\n';
} else
std::cout << "failed to parse!\n";
if(begin!=end)
std::cerr<< "did not parsed completely!";
//---------------------------------
std::cout << "\ndone!\n";
return EXIT_SUCCESS;
}
And my input file looks something like this:
# group 1
v -111.11 -0.017928 0.005579
v -0.014504 -0.017928 0.010577
v -0.010538 -0.017928 0.014543
v -0.005540 -0.017928 0.017090
vn -111.11 -0.017928 0.005579
vn -0.014504 -0.017928 0.010577
vn -0.010538 -0.017928 0.014543
# group 2
v 0.005540 -0.017928 0.017090
v 0.010538 -0.017928 0.014543
v 0.014504 -0.017928 0.010577
vn 0.014504 -0.017928 0.010577
vn 0.017050 -0.017928 0.005579
vn 0.017928 -0.017928 0.000039
vn -0.010538 -0.017928 0.014543
# group 3
# and so on..
The same code was compiled and parsed correctly with the following settings:
However I was not able to compile it on ubuntu 18.04 with boost-1.65.1 and gcc (7.5.0 , 9.3.0, and 10.1.0) with (c++14, c++17 or c++20).
Here is a part of error msg:
In file included from /usr/include/boost/spirit/home/x3/directive/expect.hpp:12,
from /usr/include/boost/spirit/home/x3/auxiliary/guard.hpp:11,
from /usr/include/boost/spirit/home/x3/auxiliary.hpp:13,
from /usr/include/boost/spirit/home/x3.hpp:14,
from parser.cpp:1:
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp: In instantiation of 'static bool boost::spirit::x3::detail::parse_into_container_impl<Parser, Context, RContext, typename boost::enable_if<boost::spirit::x3::traits::handles_container<Parser, Context> >::type>::call(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, mpl_::true_) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; mpl_::true_ = mpl_::bool_<true>]':
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:281:24: required from 'static bool boost::spirit::x3::detail::parse_into_container_impl<Parser, Context, RContext, typename boost::enable_if<boost::spirit::x3::traits::handles_container<Parser, Context> >::type>::call(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:293:74: required from 'bool boost::spirit::x3::detail::parse_into_container(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&) [with Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:378:33: required from 'bool boost::spirit::x3::detail::parse_sequence(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, boost::spirit::x3::traits::container_attribute) [with Parser = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >; Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:463:32: required from 'static bool boost::spirit::x3::detail::parse_into_container_impl<boost::spirit::x3::sequence<L, R>, Context, RContext>::call(const parser_type&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, mpl_::false_) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Right = boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; boost::spirit::x3::detail::parse_into_container_impl<boost::spirit::x3::sequence<L, R>, Context, RContext>::parser_type = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >; mpl_::false_ = mpl_::bool_<false>]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:496:24: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/spirit/home/x3/operator/kleene.hpp:32:48: required from 'bool boost::spirit::x3::kleene<Subject>::parse(Iterator&, const Iterator&, const Context&, RContext&, Attribute&) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type; Subject = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >]'
/usr/include/boost/spirit/home/x3/operator/sequence.hpp:32:37: required from 'bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>; Right = boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > >]'
/usr/include/boost/spirit/home/x3/directive/skip.hpp:75:39: required from 'bool boost::spirit::x3::skip_directive<Subject, Skipper>::parse(Iterator&, const Iterator&, const Context&, RContext&, Attribute&) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type; Subject = boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >; Skipper = boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >]'
/usr/include/boost/spirit/home/x3/core/parse.hpp:35:34: required from 'bool boost::spirit::x3::parse_main(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Parser = boost::spirit::x3::skip_directive<boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >, boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > > >; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/core/parse.hpp:71:26: required from 'bool boost::spirit::x3::parse(Iterator&, Iterator, const Parser&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Parser = boost::spirit::x3::skip_directive<boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >, boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > > >]'
parser.cpp:28:35: required from here
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:254:22: error: 'const struct boost::spirit::x3::unused_type' has no member named 'empty'
254 | if (attr.empty())
| ~~~~~^~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:22: error: 'const struct boost::spirit::x3::unused_type' has no member named 'insert'
259 | attr.insert(attr.end(), rest.begin(), rest.end());
| ~~~~~^~~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:34: error: 'const struct boost::spirit::x3::unused_type' has no member named 'end'
259 | attr.insert(attr.end(), rest.begin(), rest.end());
| ~~~~~^~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:46: error: 'const struct boost::spirit::x3::unused_type' has no member named 'begin'
259 | attr.insert(attr.end(), rest.begin(), rest.end());
| ~~~~~^~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:60: error: 'const struct boost::spirit::x3::unused_type' has no member named 'end'
259 | attr.insert(attr.end(), rest.begin(), rest.end());
|
.
.
.
.
I also tried a suggestion as in this answer, but it still won't compile!
Can someone point out where I'm doing it wrong, or at least what MIGHT BE causing this? Thanks
Upvotes: 1
Views: 196
Reputation: 392833
It's a known and fixed bug in 1.65.0, 1.65.1 and 1.66
See it for yourself: https://wandbox.org/permlink/32WK3LoPb8yqmfsV (switch boost versions on the left).
Here's a simplified version - the parser is unchanged but more readable (that's me reviewing the code) and the input is hard-coded for Compiler Explorer:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <fstream>
#include <fmt/ranges.h>
namespace x3 = boost::spirit::x3;
int main() {
std::string const& input = R"(# group 1
v -111.11 -0.017928 0.005579
vn -111.11 -0.017928 0.005579
# group 2
v 0.005540 -0.017928 0.017090
vn 0.014504 -0.017928 0.010577
# and so on..)";
auto triplet = [](auto id, auto& v) {
auto action = [&v](auto& ctx){ v.emplace_back(x3::_attr(ctx)); };
return id >> x3::repeat(3) [x3::double_ [action]];
};
auto NL = x3::eoi|+x3::eol;
auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> NL;
std::vector<float> v, vn;
auto rule = x3::skip(skipper) [ -NL >>
*( +(triplet("v", v) >> NL) >>
*(triplet("vn", vn) >> NL) )
];
if (x3::parse(begin(input), end(input), rule >> x3::eoi)) {
fmt::print("v: {}\nvn: {}\n", v, vn);
}
}
Prints
v: {-111.11, -0.017928, 0.005579, 0.00554, -0.017928, 0.01709}
vn: {-111.11, -0.017928, 0.005579, 0.014504, -0.017928, 0.010577}
Note how this, due the semantic actions, conflates data sequences from different groups. Compare to below!
Now switching to 1.66.0 also fails: https://godbolt.org/z/bjvETE
However, here's even further simplified but without any semantic actions:
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <fstream>
#include <fmt/ranges.h>
namespace x3 = boost::spirit::x3;
int main() {
std::string const& input = R"(# group 1
v -111.11 -0.017928 0.005579
vn -111.11 -0.017928 0.005579
# group 2
v 0.005540 -0.017928 0.017090
vn 0.014504 -0.017928 0.010577
# and so on..)";
auto NL = x3::eoi|+x3::eol;
auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> NL;
auto triplet = x3::repeat(3) [x3::double_];
using V = std::vector<float>;
using VN = std::vector<float>;
using Group = std::tuple<V, VN>;
auto group
= x3::rule<struct rule_id, Group> {"group"}
= +("v" >> triplet >> NL) >>
*("vn" >> triplet >> NL)
;
auto rule = x3::skip(skipper) [ -NL >> *group ];
std::vector<Group> groups;
if (x3::parse(begin(input), end(input), rule >> x3::eoi, groups)) {
fmt::print("{}\n", fmt::join(groups, "\n"));
}
}
Most importantly, it no longer conflates groups:
({-111.11, -0.017928, 0.005579}, {-111.11, -0.017928, 0.005579})
({0.00554, -0.017928, 0.01709}, {0.014504, -0.017928, 0.010577})
Printing the data without libfmt (Live On Coliru)
for (auto& [v,vn] : groups) {
std::cout << "\nv"; for (auto&& f : v) std::cout << " " << f;
std::cout << "\nvn"; for (auto&& f : vn) std::cout << " " << f;
}
Output:
v -111.11 -0.017928 0.005579
vn -111.11 -0.017928 0.005579
v 0.00554 -0.017928 0.01709
vn 0.014504 -0.017928 0.010577
Just upgrade your boost version. Spirit is entirely header-only, so you might just be able to drop in 1.67.0 headers from boost/spirit/x3
into a project folder if you need.
Off-topic: Semantic actions have drawbacks: Boost Spirit: "Semantic actions are evil"?.
Upvotes: 1