#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ecgp { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace fusion = boost::fusion; namespace phoenix = boost::phoenix; struct constituent { int constituent_kind; std::string left; std::string right; std::vector probs; void print(std::ostream& o) const { using namespace std; o << constituent_kind << " " << left << " " << right << "["; BOOST_FOREACH(double p, probs) { o << p << ", "; } o << "]"; o << endl; } }; std::ostream& operator<<(std::ostream& o, const constituent& b) { b.print(o); return o; }; } BOOST_FUSION_ADAPT_STRUCT( // global scope required ecgp::constituent, (int, constituent_kind) (std::string, left) (std::string, right) (std::vector, probs) ) namespace ecgp { template struct constituent_grammar : qi::grammar(),ascii::space_type> { constituent_grammar() : constituent_grammar::base_type(start,"constituents") { using namespace qi::labels; using qi::eps; using qi::lit; using qi::_val; using qi::fail; using qi::lexeme; using qi::double_; using qi::on_error; using ascii::alpha; using ascii::alnum; using phoenix::construct; using phoenix::val; constitkind %= ((lit("extraposed") [_val = 2]) | (lit("optional") [_val = 1]) | (eps [_val = 0]) ); probs %= ("[" > (double_ % ',') > "]") | eps; id %= lexeme[(('_' | alpha) >> *(alnum | '_' | '-'))]; /* Questions: My original fully functioning grammar was this: start %= (constitkind >> id >> ':' >> id >> probs) % ","; // WORKS where - constitkind exposes unsigned, - id exposes string, - probs exposes a list of doubles, - start exposes a list of constituent structures (Is that jargon acceptable?) It recognizes strings such as a:b, foo:bar [ 0.00 ], extraposed x:y [ 0.00, 0.50, 0.99, 1.0 ], optional z:a [ 0.00, 0.50, 0.99, 1.0 ] I wanted to replace the grammar with this (note the expectation points which replace sequence operators): start %= (constitkind > id > ':' > id >> probs) % ","; // FAILS It won't compile. All I can glean from the error report is that I've induced a type mismatch. What's wrong? I got as far as this by thrashing: start %= (constitkind >> (id > ':') >> id >> probs) % ","; // WORKS Why do the parentheses in (id > ':') permit compilation? */ start %= (constitkind >> (id > ':') >> id >> probs) % ","; // WORKS constitkind.name("constituent_kind"); id.name("identifier"); probs.name("probabilities"); on_error ( start , std::cout << val("constituent: expected ") << _4 // what failed? << val(" here: \"") << construct(_3, _2) // iterators to error-pos, end << val("\"") << std::endl ); } qi::rule id; qi::rule constitkind; qi::rule(), ascii::space_type> probs; qi::rule(), ascii::space_type> start; }; } int main() { using boost::spirit::ascii::space; typedef std::string::const_iterator string_iterator; std::vector cxn; ecgp::constituent_grammar c; std::string str = "a:b," "foo:bar [ 0.00 ]," "extraposed x:y [ 0.00, 0.50, 0.99, 1.0 ]," "optional z:a [ 0.00, 0.50, 0.99, 1.0 ]" ; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); bool r = phrase_parse(iter, end, c, space, cxn); if (r && iter == end) { std::cout << "OK\n"; } else { std::string rest(iter, end); std::cout << "fail: " << rest << "\n"; } return 0; }