Update
Answering your edited question: yes, you can do it without semantic actions, simply:
template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(matrix_) { matrixBlock_ = qi::lit(";") >> *qi::int_; matrix_ = qi::repeat(3)[ matrixBlock_ ]; } qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_; };
Please note that you can check the number of rows / columns. See my extended sample that uses an extra semantic action to check this out (note the subtle change from *int_ to +int_ to avoid blank lines):
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/phoenix.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; namespace phx = boost::phoenix; typedef std::vector<int> Matrix; template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(matrix_) { using namespace qi; matrixBlock_ = lit(";") >> +int_ >> eps( 0 == (phx::size(_val) % 3)); matrix_ = repeat(3)[ matrixBlock_ ]; } qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_; }; int main() { std::string test = ";42 45 -9; 3 2 1; 12 34 56"; std::string::const_iterator f(test.begin()), l(test.end()); Parser<std::string::const_iterator> parser; Matrix m; if (qi::phrase_parse(f,l,parser,qi::space, m)) std::cout << "Wokay\n"; else std::cerr << "Uhoh\n"; std::cout << karma::format(karma::auto_ % ", ", m) << "\n"; }
Old answer:
Yes, you can use Spirit customization points to treat your custom type as a container. A record of the documentation that I propose for this is given below:
Here is a simple example showing how to use it, live:
Side note regarding “phantom entries”, in general:
Note that there are few FAQs related to backtrace grammars and container attributes. The fact is that for performance reasons, parsers will not cancel ("rollback") to their base containers during backtracking. You can force this behavior to use qi::hold , but it may be worth the effort to rework the grammar into
- avoid return or
- pass attribute at a later stage (using semantic actions)
Full sample code:
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; struct Matrix { std::vector<int> data; }; namespace boost { namespace spirit { namespace traits { template <> struct is_container<Matrix> { }; template <typename Attrib> struct push_back_container<Matrix, Attrib> { static bool call(Matrix& c, Attrib const& val) { c.data.push_back(val); return true; } }; template <> struct container_value<Matrix> { typedef int type; }; } } } template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(start) { start = *qi::int_; } qi::rule<It, Matrix(), qi::space_type> start; }; int main() { std::string test = "42 45 -9"; std::string::const_iterator f(test.begin()), l(test.end()); Parser<std::string::const_iterator> parser; Matrix m; if (qi::phrase_parse(f,l,parser,qi::space, m)) std::cout << "Wokay\n"; else std::cerr << "Uhoh\n"; std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n"; }
Output:
Wokay 42, 45, -9
Update
A bit more background:
Of course, for such a trivial example, which simply wraps the standard supported by the type of container, it would be quite easy to use the mail merge adaptation instead: ( http://liveworkspace.org/code/56aea8619867451a21cd49fddb1e93bd )
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/fusion/adapted/struct.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; struct Matrix { std::vector<int> data; }; BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<int>, data)); int main() { std::string test = "42 45 -9"; std::string::const_iterator f(test.begin()), l(test.end()); Matrix m; if (qi::phrase_parse(f,l, qi::eps >> *qi::int_, qi::space, m)) std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n"; }
Note that qi::eps needed due to an error (AFAICT) with structures that contain only one data item. See discussion here (and some other references)