【问题标题】:How to convert a std::vector<std::string> to be a member of a struct in boost::spirit?如何将 std::vector<std::string> 转换为 boost::spirit 中结构的成员?
【发布时间】:2012-11-30 20:51:46
【问题描述】:

我有一段 Spirit 代码,通过使用 std::vector&lt;std::string&gt; 作为主要属性,可以将 std::string input = "RED.MAGIC( 1, 2, 3 )[9].GREEN" 正确解析为简单的 std::vector&lt;std::string&gt;

我想将std::vector&lt;std::string&gt; 替换为包含std::vector&lt;std::string&gt; 的结构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 --------------------------------------------

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 是一个有趣的发现,但不确定是否可行,因为在我的真实代码中,start 深深嵌入在我的真实解析规则中(不像这个玩具示例那样在开头) - 不确定是否eps 还可以(不是 eps 总是强制匹配吗?)...

标签: c++ boost boost-spirit boost-fusion


【解决方案1】:

如 cmets 中链接的问题所示,为了分配给具有单个成员的适应结构,您需要按顺序使用 qi::eps。您还需要将中间fun_call 规则的属性更改为std::vector&lt;std::string&gt;()

// #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;
}

【讨论】:

  • +1 一个可行的解决方案 - 尝试看看我们是否也可以让 fun_call 以某种方式成为 my_rec...
  • 好的 - 在复杂的解析(真实代码)中深入调整这个解决方案是可以的。 ty - 已接受。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多