How to throw an expectation_failure from a function in Boost Spirit?

boost, boost-spirit, boost-spirit-qi, c++

Solution

You can use the _pass placeholder in phoenix to enforce a parse fail. Something like this should work.

bool myfunc(int i) {return i%10 == 0;}

...
_int [ _pass = phoenix::bind(myfunc,_1)] 

Problem

In Boost::Spirit, how can I trigger an `expectation_failure` from a function bound with `Boost::Bind`? Background: I parse a large file that contains complex entries. When an entry is inconsistent with a previous entry I want to fail and throw an `expectation_failure` (containing proper parse position information). When I parse an entry I bind a function that decides if the entry is inconsistent with something seen before. I made up a little toy example that shows the point. Here I simply want to throw an `expectation_failure` when the `int` is not divisible by 10: ``` #include <iostream> #include <iomanip> #include <boost/spirit/include/qi.hpp> #include <boost/bind.hpp> #include <boost/spirit/include/classic_position_iterator.hpp> namespace qi = boost::spirit::qi; namespace classic = boost::spirit::classic; void checkNum(int const& i) { if (i % 10 != 0) // >> How to throw proper expectation_failure? << std::cerr << "ERROR: Number check failed" << std::endl; } template <typename Iterator, typename Skipper> struct MyGrammar : qi::grammar<Iterator, int(), Skipper> { MyGrammar() : MyGrammar::base_type(start) { start %= qi::eps > qi::int_[boost::bind(&checkNum, _1)]; } qi::rule<Iterator, int(), Skipper> start; }; template<class PosIter> std::string errorMsg(PosIter const& iter) { const classic::file_position_base<std::string>& pos = iter.get_position(); std::stringstream msg; msg << "parse error at file " << pos.file << " line " << pos.line << " column " << pos.column << std::endl << "'" << iter.get_currentline() << "'" << std::endl << std::setw(pos.column) << " " << "^- here"; return msg.str(); } int main() { std::string in = "11"; typedef std::string::const_iterator Iter; typedef classic::position_iterator2<Iter> PosIter; MyGrammar<PosIter, qi::space_type> grm; int i; PosIter it(in.begin(), in.end(), "<string>"); PosIter end; try { qi::phrase_parse(it, end, grm, qi::space, i); if (it != end) throw std::runtime_error(errorMsg(it)); } catch(const qi::expectation_failure<PosIter>& e) { throw std::runtime_error(errorMsg(e.first)); } return 0; } ``` Throwing an `expectation_failure` would mean that I get an error message like this on an int that is not divisible by 10: ``` parse error at file <string> line 1 column 2 '11' ^- here ```

Original source