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 skippers
(tenga en cuenta que debe usar instanciasqi::rule<>
declaradas apropiadamente dentro de una cláusulaskip[]
)
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 incluireol
) - 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.