En Boost :: Spirit, ¿cómo puedo disparar un expectation_failure
desde una función vinculada con Boost::Bind
?¿Cómo arrojar un expectation_failure de una función en Boost Spirit?
Antecedentes: analizo un archivo grande que contiene entradas complejas. Cuando una entrada es inconsistente con una entrada anterior, quiero fallar y lanzar un expectation_failure
(que contiene la información de posición de análisis correcta). Cuando analizo una entrada, ato una función que decide si la entrada es inconsistente con algo visto anteriormente.
Inventé un pequeño ejemplo de juguete que muestra el punto. Aquí simplemente quiero lanzar una expectation_failure
cuando el int
no es divisible por 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;
}
Lanzar un expectation_failure
significaría que aparece un mensaje de error como este en un int que no es divisible por 10:
parse error at file <string> line 1 column 2
'11'
^- here
¿Se puede crear otra regla en lugar de int_, que coincidiría con entero solo cuando se satisfaga su condición? No conozco bien al Espíritu, pero supongo que hay una regla similar a r_bool en AX que envuelve un predicado, es una situación bastante común. –
Creo que necesitaré algo como esto, lamentablemente: http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank
Disculpe las ver eso, es muy desagradable para el usuario. Es por eso que necesitas AX :-) –