1

我有一块 Spirit 代码,通过用作主要属性,可以正确解析std::string input = "RED.MAGIC( 1, 2, 3 )[9].GREEN"为 simple 。std::vector<std::string>std::vector<std::string>

我想将 替换为包含 astd::vector<std::string>的结构,但如果可能的话,继续使用自动生成器。my_recstd::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 --------------------------------------------

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

2 回答 2

2

如评论中链接的问题所示,为了分配给具有单个成员的适应结构,您需要按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;
}
于 2012-11-30T22:26:05.497 回答
0

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

fun_call %= as<std::vector<std::string>>()[...];
于 2012-11-30T21:12:15.233 回答