¿Cómo lanzar un error de expectativa desde una función en Boost Spirit?

En Boost::Spirit, ¿cómo puedo activar un expectation_failure de una función ligada a Boost::Bind?

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 información de posición de análisis adecuada). Cuando analizo una entrada, vinculo una función que decide si la entrada es inconsistente con algo visto antes.

Inventé un pequeño ejemplo de juguete que muestra el punto. Aquí simplemente quiero lanzar un expectation_failure cuando 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;
}

Lanzando un expectation_failure significaría que recibo 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

preguntado el 22 de mayo de 12 a las 18:05

¿Puede crear otra regla en lugar de int_, que coincida con enteros solo cuando se cumpla su condición? No conozco bien a Spirit, 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, desafortunadamente: boost-spirit.com/home/articles/qi-example/… -

Lamento ver eso, es muy poco amigable para el usuario. Por eso necesitas AX :-) -

2 Respuestas

Puede utilizar el _aprobar marcador de posición en phoenix para hacer cumplir una falla de análisis. Algo como esto debemos trabajo.

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

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

Respondido 24 Abr '18, 20:04

@Frank, tenga en cuenta que establecer _pass en falso solo detendrá la regla actual, pero no el analizador en su conjunto con todas las demás reglas (también conocido como su gramática). - Konrad Kleine

Años tarde pero en fin:

Si absolutamente quiere lanzar una excepción y quiere que el on_error para atraparlo, tienes que tirar el expectation_exception from the qi espacio de nombres porque el controlador de errores on_error no atrapa nada más.

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

Se vería así:

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

sin que importe Exception es un qi::expactation_exception y nada más.

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

Puedes lanzar desde cualquier lugar dentro de un contexto custodiado por on_error.

Respondido el 14 de junio de 16 a las 04:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.