2012-05-22 10 views
5

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 
+0

¿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. –

+0

Creo que necesitaré algo como esto, lamentablemente: http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank

+0

Disculpe las ver eso, es muy desagradable para el usuario. Es por eso que necesitas AX :-) –

Respuesta

5

No estoy seguro, pero creo que puede usar el marcador de posición _pass en phoenix para aplicar un error de análisis. Algo así debería funcionar.

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

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

Sí, eso funciona. ¡Gracias! – Frank

+1

@Frank tenga en cuenta que la configuración _pass a false solo detendrá la regla actual, pero no el analizador como un todo con todas las otras reglas (también conocida como su gramática). –

0

años de retraso, pero de todos modos:

Si a pesar de todo quiere lanzar una excepción y desea que el on_error para cogerlo, hay que tirar la expectation_exception del qi espacio de nombres debido a que el controlador de errores on_error hace capturas nada más.

Esto podría aplicarse a una acción semántica o a una implementación de analizador personalizado.

se vería así:

boost::throw_exception(Exception(first, last, component.what(context))); 

donde Exception es una nada qi::expactation_exception y demás.

Si no tiene un componente a mano como en una acción semántica, debe proporcionar su propio objeto qi::info en lugar de component.what(..).

Puede lanzar desde cualquier lugar dentro de un contexto protegido por on_error.

Cuestiones relacionadas