Как преобразовать std :: vector & lt; std :: string & gt; быть членом структуры в boost :: spirit?

У меня есть фрагмент кода Spirit, который правильно анализирует std::string input = "RED.MAGIC( 1, 2, 3 )[9].GREEN" в простой std::vector<std::string>, используя std::vector<std::string> в качестве основного атрибута.

Я хотел бы заменить std::vector<std::string> в структуру my_rec который содержит std::vector<std::string>, но продолжайте использовать автоматический генератор, если это возможно.

Когда я собираю с -DUSE_MY_RECЯ получаю стену непроходимых ошибок компиляции.

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

/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox
Finished.
MATCHED
/tmp$ g++ -DUSE_MY_REC -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox
WALL OF COMPILE ERRORS --------------------------------------------

sandbox.cpp

// #define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

#ifdef USE_MY_REC
struct my_rec
{
std::vector<std::string>    m_pieces;
};

BOOST_FUSION_ADAPT_STRUCT(
my_rec,
(std::vector<std::string>,  m_pieces)
)

typedef struct my_rec            MY_TYPE;
#else
typedef std::vector<std::string> MY_TYPE;
#endif

template <typename ITERATOR>
struct my_parser :
qi::grammar<ITERATOR, MY_TYPE(), ascii::space_type>
{
my_parser() :
my_parser::base_type( start )
{
start %= ( color | fun_call ) % '.'
;

color %=
qi::string( "RED" )
| qi::string( "GREEN" )
| qi::string( "BLUE" )
;

fun_call %=
qi::string( "MAGIC" )
>> '('
>> +qi::char_("0-9") % ','
>> ')'
>> '['
>> +qi::char_("0-9")
>> ']'
;
}
qi::rule<ITERATOR, MY_TYPE(),     ascii::space_type> start, fun_call;
qi::rule<ITERATOR, std::string(), ascii::space_type> color;
};

int
main( int argc, char* argv[] )
{
namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

MY_TYPE                  v;
std::string              str = "RED.MAGIC( 1, 2, 3 )[9].GREEN";
std::vector<std::string> exp = {{ "RED", "MAGIC", "1", "2", "3", "9", "GREEN" }};
auto                     it  = str.begin(), end = str.end();
my_parser<decltype(it)>  g;

if( qi::phrase_parse( it, end, g, ascii::space, v ) && it==end )
{
std::cout << "Finished." << std::endl;
#ifndef USE_MY_REC
if ( !std::equal( v.begin(), v.end(), exp.begin() ))
{
std::cout << "MISMATCH" << std::endl;
for( const auto& x : v )
std::cout << x << std::endl;
} else {
std::cout << "MATCHED" << std::endl;
}
#endif
} else
std::cout << "Error." << std::endl;

return 0;
}

1

Решение

Как показано в вопросе, связанном в комментариях, чтобы назначить адаптированную структуру с одним членом, который вам нужно использовать qi::eps в последовательности. Также вам нужно изменить атрибут вашего промежуточного звена fun_call Правило для std::vector<std::string>(),

// #define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;struct my_rec
{
std::vector<std::string>    m_pieces;
};

BOOST_FUSION_ADAPT_STRUCT(
my_rec,
(std::vector<std::string>,  m_pieces)
)

typedef struct my_rec            MY_TYPE;template <typename ITERATOR>
struct my_parser :
qi::grammar<ITERATOR, MY_TYPE(), ascii::space_type>
{
my_parser() :
my_parser::base_type( start )
{
start %= qi::eps >>( color | fun_call ) % '.' //add qi::eps to make the adaptation of the single member struct work
;

color %=
qi::string( "RED" )
| qi::string( "GREEN" )
| qi::string( "BLUE" )
;

fun_call %=
qi::string( "MAGIC" )
>> '('
>> +qi::char_("0-9") % ','
>> ')'
>> '['
>> +qi::char_("0-9")
>> ']'
;
}
qi::rule<ITERATOR, MY_TYPE(),     ascii::space_type> start;
qi::rule<ITERATOR, std::vector<std::string>(), ascii::space_type> fun_call; //changed this rule's attribute to vector<string>
qi::rule<ITERATOR, std::string(), ascii::space_type> color;
};

int
main( int argc, char* argv[] )
{
namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

MY_TYPE                  v;
std::string              str = "RED.MAGIC( 1, 2, 3 )[9].GREEN";
std::vector<std::string> exp;
exp.push_back("RED");
exp.push_back("MAGIC");
exp.push_back("1");
exp.push_back("2");
exp.push_back("3");
exp.push_back("9");
exp.push_back("GREEN");
auto                     it  = str.begin(), end = str.end();
my_parser<decltype(it)>  g;

if( qi::phrase_parse( it, end, g, ascii::space, v ) && it==end )
{
std::cout << "Finished." << std::endl;

if ( !std::equal( v.m_pieces.begin(), v.m_pieces.end(), exp.begin() ))
{
std::cout << "MISMATCH" << std::endl;
for( const auto& x : v.m_pieces )
std::cout << x << std::endl;
} else {
std::cout << "MATCHED" << std::endl;
}

} else
std::cout << "Error." << std::endl;

return 0;
}
2

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

Вы можете использовать boost::spirit::qi::as преобразовать проанализированные данные в vector и затем поместите это в свою структуру.

fun_call %= as<std::vector<std::string>>()[...];
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector