如何将 std::vector<std::string> 转换为 boost::spirit 中结构的成员?

How to convert a std::vector<std::string> to be a member of a struct in boost::spirit?

本文关键字:std boost spirit 成员 结构 string vector lt gt 转换      更新时间:2023-10-16

我有一大块 Spirit 代码,通过使用 std::vector<std::string> 作为主要属性,它正确地将std::string input = "RED.MAGIC( 1, 2, 3 )[9].GREEN"解析为一个简单的std::vector<std::string>

我想将std::vector<std::string>替换为包含std::vector<std::string>的结构my_rec,但如果可能的话,继续使用自动生成器。

当我用-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 --------------------------------------------

沙盒.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;
}

如注释中链接的问题所示,为了分配给具有单个成员的改编结构,您需要在序列中使用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;
}
您可以使用

boost::spirit::qi::as将解析的数据转换为vector,然后将其放入结构中。

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