Как разобрать разнородный список списков без предварительного тега?

Как мне изменить этот код boost :: spirit для анализа любой комбинации диапазонов или списков?

Обратите внимание, что этот вопрос несколько отличается от моего предыдущий вопрос. В этом случае у меня нет специального предварительного тега, как RANGE: а также LIST: это помогает мне разобраться, так что я не уверен, что нам нужен какой-то прогноз здесь.

Тем не менее, мне нужно разделить анализ, поскольку это поможет мне зафиксировать результаты в разных структурах данных.

задача пройти все четыре теста

РЕДАКТИРОВАТЬ ОТВЕТ, который, кажется, работает с более сложными выражениями

// #define BOOST_SPIRIT_DEBUG

#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/tuple.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>

#include <iostream>

namespace qi = boost::spirit::qi;

typedef std::vector<boost::tuple<std::string,std::vector<int>>>   MY_TYPE;

template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, MY_TYPE(), Skipper>
{
my_grammar() :
my_grammar::base_type( entries )
{
entries %=
*(
+(qi::char_ - '-')
>> qi::lit( "->" )
>> ( comma | range )
)
;

range %= '{' >> qi::int_ >> ':' >> qi::int_ >> ':' >> qi::int_ >> '}';
comma %= '{' >> (qi::int_ % ',') >> '}';

BOOST_SPIRIT_DEBUG_NODE( range   );
BOOST_SPIRIT_DEBUG_NODE( comma   );
BOOST_SPIRIT_DEBUG_NODE( entries );
}

qi::rule<Iterator, std::vector<int>(), Skipper>
range, comma;

qi::rule<Iterator, MY_TYPE(), Skipper>
entries;
};

// -----------------------------------------------------------------------------

static void TryParse( const std::string& input, const std::string& label )
{
MY_TYPE entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::space_type> entry_grammar;

if (qi::phrase_parse(it, end, entry_grammar, qi::space, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}

int
main( int argc, char* argv[] )
{
std::string range_first = "foo -> {1:9:1}\nbar -> {1,2,3,4,5}\n";
std::string comma_first = "foo -> {1,2,3,4,5}\nbar -> {1:9:1}\n";
std::string comma_only  = "foo -> {1,2,3,4,5}\n";
std::string range_only  = "foo -> {1:9:1}\n";

TryParse( range_first, "RANGE FIRST" );
TryParse( comma_first, "COMMA FIRST" );
TryParse( range_only,  "RANGE ONLY"  );
TryParse( comma_only,  "COMMA ONLY"  );
}

РЕДАКТИРОВАТЬ НОВЫЙ ВЫХОД (ЕЩЕ НЕ МОЖЕТ ОБРАЩАТЬСЯ ГЕТЕРОГЕННЫЙ СПИСОК)

/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox
COMMA FIRST FAIL
RANGE FIRST FAIL
COMMA ONLY SUCCESS
RANGE ONLY SUCCESS
/tmp$

РЕДАКТИРОВАТЬ УЛУЧШЕННЫЙ КОД (ЕЩЕ НЕ МОЖЕТ ОБРАЩАТЬСЯ ГЕТЕРОГЕННЫЙ СПИСОК)

// #define BOOST_SPIRIT_DEBUG

#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>

namespace qi = boost::spirit::qi;

template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, std::vector<int>(), Skipper>
{
my_grammar() :
my_grammar::base_type(entries)
{
entries %=
*('{' >> qi::int_
>> ( range_tail | comma_tail ))
;

range_tail %= ':' >> qi::int_ >> ':' >> qi::int_ >> '}';
comma_tail %= *( ',' >> qi::int_ ) >> '}';

BOOST_SPIRIT_DEBUG_NODE(entries   );
BOOST_SPIRIT_DEBUG_NODE(comma_tail);
BOOST_SPIRIT_DEBUG_NODE(range_tail);
}

qi::rule<Iterator, std::vector<int>(), Skipper> entries, comma_tail, range_tail;
};

// -----------------------------------------------------------------------------

static void TryParse( const std::string& input, const std::string& label )
{
std::vector<int> entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::blank_type> entry_grammar;

if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}

int
main( int argc, char* argv[] )
{
std::string range_first = "{3:5:7}\n{1,2,3,4,5}";
std::string comma_first = "{1,2,3,4,5}\n{3:5:7}";
std::string comma_only  = "{1,2,3,4,5}";
std::string range_only  = "{3:5:7}";

TryParse( comma_first, "COMMA FIRST" );
TryParse( range_first, "RANGE FIRST" );
TryParse( comma_only,  "COMMA ONLY"  );
TryParse( range_only,  "RANGE ONLY"  );
}

ОРИГИНАЛЬНЫЙ КОД

скомпилировать и запустить

/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox
COMMA FIRST FAIL
RANGE FIRST FAIL
COMMA ONLY SUCCESS
RANGE ONLY FAIL
/tmp$

sandbox.cpp

// #define BOOST_SPIRIT_DEBUG

#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>namespace qi = boost::spirit::qi;
typedef int Entry;

template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, std::vector<Entry>(), Skipper>
{
my_grammar() :
my_grammar::base_type(entries)
{
entries %=
*(
'{' >>
( comma_list | range_list )
>> '}'
)
;

comma_list %= qi::int_ % ',';
range_list %= qi::int_ >> ':' >> qi::int_ >> ':' >> qi::int_;

BOOST_SPIRIT_DEBUG_NODE(entries);
BOOST_SPIRIT_DEBUG_NODE(comma_list);
BOOST_SPIRIT_DEBUG_NODE(range_list);
}

qi::rule<Iterator, std::vector<Entry>(), Skipper> entries, comma_list, range_list;
};

// -----------------------------------------------------------------------------
static void TryParse( const std::string& input, const std::string& label )
{
std::vector<Entry> entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::blank_type> entry_grammar;

if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}

int
main( int argc, char* argv[] )
{
std::string range_first = "{3:5:7}\n{1,2,3,4,5}";
std::string comma_first = "{1,2,3,4,5}\n{3:5:7}";
std::string comma_only  = "{1,2,3,4,5}";
std::string range_only  = "{3:5:7}";

TryParse( range_first, "COMMA FIRST" );
TryParse( comma_first, "RANGE FIRST" );
TryParse( comma_only,  "COMMA ONLY"  );
TryParse( range_only,  "RANGE ONLY"  );
}

2

Решение

Поглотить ведущий номер в общем коде. После этого числа есть либо хвост диапазона, либо хвост списка. Хвосты списка начинаются с a, а хвосты диапазона начинаются с:.

Возможно, сложите} в хвост, так что хвост списка ((, number) *} и хвост диапазона: number: number}, что облегчает анализ пустого списка.

3

Другие решения

Других решений пока нет …