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

c++ - Problemas con Boost Spirit skipper



boost-spirit boost-spirit-qi (1)

En general, las siguientes directivas son útiles para inhibir / cambiar patrones de media gramática:

  • qi::lexeme [ p ]
    que inhibe a un patrón, por ejemplo, si quiere estar seguro de analizar un identificador sin saltos internos)

  • qi::raw [ p ]
    que analiza como siempre, incluidos los saltos, pero devuelve el rango del iterador sin procesar de la secuencia de origen coincidente (incluidas las posiciones omitidas)

  • qi::no_skip [ p ]
    Inhibición de saltos sin saltos previos
  • qi::skip(s) [ p ]
    que reemplaza al patrón por otro skipper s (tenga en cuenta que debe usar instancias qi::rule<> declaradas apropiadamente dentro de una cláusula skip[] )

donde p es cualquier expresión del analizador.

Solución específica

Su problema, como ya sabe, podría ser que qi::space come todos los espacios en blanco. No puedo saber qué es lo que está mal en tu gramática (ya que no muestras ni la gramática completa ni la entrada relevante).

Por lo tanto, esto es lo que escribiría. Nota

  • el uso de qi::eol para exigir explícitamente saltos de línea en ubicaciones específicas
  • el uso de qi::blank como patrón (sin incluir eol )
  • por brevedad, combiné las gramáticas

Código:

#define BOOST_SPIRIT_DEBUG #include <boost/fusion/adapted.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> namespace qi = boost::spirit::qi; namespace phx = boost::phoenix; struct rowType { unsigned int number; std::list<unsigned int> list; }; struct problemType { unsigned int ROW; std::vector<rowType> rows; }; BOOST_FUSION_ADAPT_STRUCT(rowType, (unsigned int, number)(std::list<unsigned int>, list)) BOOST_FUSION_ADAPT_STRUCT(problemType, (unsigned int, ROW)(std::vector<rowType>, rows)) template<typename Iterator> struct problem_parser : qi::grammar<Iterator,problemType(),qi::blank_type> { problem_parser() : problem_parser::base_type(problem) { using namespace qi; list = ''['' >> -(int_ % '','') >> '']''; row = int_ >> list >> eol; problem = "ROW" >> int_ >> eol >> +row; BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list)); } qi::rule<Iterator, problemType() , qi::blank_type> problem; qi::rule<Iterator, rowType() , qi::blank_type> row; qi::rule<Iterator, std::list<unsigned int>(), qi::blank_type> list; }; int main() { const std::string input = "ROW 1/n" "2 [3, 4]/n" "5 [6, 7]/n"; auto f = begin(input), l = end(input); problem_parser<std::string::const_iterator> p; problemType data; bool ok = qi::phrase_parse(f, l, p, qi::blank, data); if (ok) std::cout << "success/n"; else std::cout << "failed/n"; if (f!=l) std::cout << "Remaining unparsed: ''" << std::string(f,l) << "''/n"; }

Si realmente no deseaba requerir saltos de línea:

template<typename Iterator> struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type> { problem_parser() : problem_parser::base_type(problem) { using namespace qi; list = ''['' >> -(int_ % '','') >> '']''; row = int_ >> list; problem = "ROW" >> int_ >> +row; BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list)); } qi::rule<Iterator, problemType() , qi::space_type> problem; qi::rule<Iterator, rowType() , qi::space_type> row; qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list; }; int main() { const std::string input = "ROW 1 " // NOTE whitespace, obviously required! "2 [3, 4]" "5 [6, 7]"; auto f = begin(input), l = end(input); problem_parser<std::string::const_iterator> p; problemType data; bool ok = qi::phrase_parse(f, l, p, qi::space, data); if (ok) std::cout << "success/n"; else std::cout << "failed/n"; if (f!=l) std::cout << "Remaining unparsed: ''" << std::string(f,l) << "''/n"; }

Actualizar

En respuesta al comentario: aquí hay un fragmento que muestra cómo leer la entrada de un archivo. Esto fue probado y funciona bien para mí:

std::ifstream ifs("input.txt"/*, std::ios::binary*/); ifs.unsetf(std::ios::skipws); boost::spirit::istream_iterator f(ifs), l; problem_parser<boost::spirit::istream_iterator> p;

Tengo problemas con los skippers de impulso de espíritu.

Necesito analizar un archivo como ese:

ROW int int [int, int] int [int, int] ...

Puedo analizarlo sin problemas (gracias a stackoverflow;) solo si agrego un ''_'' después de la primera int.

De hecho, creo que el capitán come el final de la línea después de la primera int, por lo que el primero y el segundo (en la segunda línea) se ven como solo uno int. No entiendo cómo mantener eol, pero comer espacios. He encontrado ejemplos para usar un analizador personalizado como aquí y aquí .

Probé qi :: blank, analizador personalizado con una sola regla encendida ('''') No importa qué patrón use, el espacio y la eol siempre están listos.

Mi gramática es:

una línea:

struct rowType { unsigned int number; std::list<unsigned int> list; };

el problema completo almacenado en una estructura:

struct problemType { unsigned int ROW; std::vector<rowType> rows; };

el analizador de filas:

template<typename Iterator> struct row_parser : qi::grammar<Iterator, rowType(), qi::space_type> { row_parser() : row_parser::base_type(start) { list = ''['' >> -(qi::int_ % '','') >> '']''; start = qi::int_ >> list; } qi::rule<Iterator, rowType(), qi::space_type> start; qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list; };

y el analizador del problema:

template<typename Iterator> struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type> { problem_parser() : problem_parser::base_type(start) { using boost::phoenix::bind; using qi::lit; start = qi::int_ >> lit(''_'') >> +(row); //BOOST_SPIRIT_DEBUG_NODE(start); } qi::rule<Iterator, problemType(),qi::space_type> start; row_parser<Iterator> row; };

Y lo uso así:

main() { static const problem_parser<spirit::multi_pass<base_iterator_type> > p; ... spirit::qi::phrase_parse(first, last , p, qi::space, pb); }

Por supuesto, el qi :: space es mi problema, y ​​una forma de resolver mi problema sería no usar un skipper, pero phrase_parse requiere uno, y entonces mi analizador requiere uno.

Estoy atrapado desde hace algunas horas ... Creo que es algo obvio que he entendido mal.

Gracias por tu ayuda.