i've written rules parse floats 2 std::vector's of floats, in turn stored in struct:
data input:
# # object name01 # v -1.5701 33.8087 0.3592 v -24.0119 0.0050 21.7439 # comment vn 0.0000 0.5346 0.8451 vn 0.8331 0.5531 -0.0000 # comment
struct:
struct objparsedata { objparsedata() : verts(), norms() {} std::vector<float> verts; std::vector<float> norms; };
and relevant parsing code:
struct objgram : qi::grammar<std::string::const_iterator, objparsedata(), iso8859::space_type> { objgram() : objgram::base_type(start) { vertex = 'v' >> qi::double_ >> qi::double_ >> qi::double_; normal = "vn" >> qi::double_ >> qi::double_ >> qi::double_; comment = '#' >> qi::skip(qi::blank)[ *(qi::print) ]; vertexlist = *(vertex | comment); normallist = *(normal | comment); start = vertexlist >> normallist; } qi::rule<std::string::const_iterator, objparsedata(), iso8859::space_type> start; qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertexlist; qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> normallist; qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertex; qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> normal; qi::rule<std::string::const_iterator, iso8859::space_type> comment; } objgrammar; objparsedata resultdata; std::string::const_iterator f = data.cbegin(); bool res = qi::phrase_parse( f, data.cend(), objgrammar, iso8859::space, resultdata );
and works. parses floats preceded 'v' verts vector of struct , floats preceded "vn" norms. great, don't know why works.
now if understand correctly, rule defined below puts results std::vector of floats.
qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertex;
so, looking @ parsing code shown above , knowing rule vertex parses std::vector of floats, apparently rule vertexlist (the 1 shown above) concatenates results vertex 1 std::vector of floats? seeing behaviour, think write 2 rules (vertex , vertexlist) one, unfortunately doesn't work:
vertex = *('v' >> qi::double_ >> qi::double_ >> qi::double_) | comment; normal = *("vn" >> qi::double_ >> qi::double_ >> qi::double_) | comment; comment = '#' >> qi::skip(qi::blank)[ *(qi::print) ]; start = vertex >> normal;
the code compile , qi::phrase_parse return succesfull parse, std::vector's in struct aren't filled anymore.. missing here?
you missplaced grouping parentheses: expanding
vertexlist = *(vertex | comment); normallist = *(normal | comment);
by eliminating subrules leads to
vertex = *(('v' >> qi::double_ >> qi::double_ >> qi::double_) | comment); normal = *(("vn" >> qi::double_ >> qi::double_ >> qi::double_) | comment);
or, i'd prefer:
full working sample (please make code samples sscce next time? https://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions):
#include <iterator> #include <fstream> #include <boost/fusion/adapted.hpp> #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; struct objparsedata { objparsedata() : verts(), norms() {} std::vector<float> verts; std::vector<float> norms; }; boost_fusion_adapt_struct(objparsedata, (std::vector<float>, verts)(std::vector<float>, norms)) template <typename it, typename skipper = qi::space_type> struct parser : qi::grammar<it, objparsedata(), skipper> { parser() : parser::base_type(start) { using namespace qi; vertex = 'v' >> qi::double_ >> qi::double_ >> qi::double_; normal = "vn" >> qi::double_ >> qi::double_ >> qi::double_; comment = '#' >> qi::skip(qi::blank)[ *(qi::print) ]; #if 0 vertexlist = *(vertex | comment); normallist = *(normal | comment); start = vertexlist >> normallist; #else vertex = *(comment | ('v' >> qi::double_ >> qi::double_ >> qi::double_)); normal = *(comment | ("vn" >> qi::double_ >> qi::double_ >> qi::double_)); start = vertex >> normal; #endif boost_spirit_debug_node(start); } private: qi::rule<std::string::const_iterator, objparsedata(), qi::space_type> start; qi::rule<std::string::const_iterator, std::vector<float>(), qi::space_type> vertexlist; qi::rule<std::string::const_iterator, std::vector<float>(), qi::space_type> normallist; qi::rule<std::string::const_iterator, std::vector<float>(), qi::space_type> vertex; qi::rule<std::string::const_iterator, std::vector<float>(), qi::space_type> normal; qi::rule<std::string::const_iterator, qi::space_type> comment; }; bool doparse(const std::string& input) { typedef std::string::const_iterator it; auto f(begin(input)), l(end(input)); parser<it, qi::space_type> p; objparsedata data; try { bool ok = qi::phrase_parse(f,l,p,qi::space,data); if (ok) { std::cout << "parse success\n"; std::cout << "data: " << karma::format_delimited( "v: " << karma::auto_ << karma::eol << "n: " << karma::auto_ << karma::eol, ' ', data); } else std::cerr << "parse failed: '" << std::string(f,l) << "'\n"; if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n"; return ok; } catch(const qi::expectation_failure<it>& e) { std::string frag(e.first, e.last); std::cerr << e.what() << "'" << frag << "'\n"; } return false; } int main() { std::ifstream ifs("input.txt", std::ios::binary); ifs.unsetf(std::ios::skipws); std::istreambuf_iterator<char> f(ifs), l; bool ok = doparse({ f, l }); }
output:
parse success data: v: -1.57 33.809 0.359 -24.012 0.005 21.744 n: 0.0 0.535 0.845 0.833 0.553 0.0
Comments
Post a Comment