2012-11-30 24 views
1

我有一大堆Spirit编码,它通过使用std::vector<std::string>作为主要属性,将std::string input = "RED.MAGIC(1, 2, 3)[9].GREEN"正确解析为一个简单的std::vector<std::string>如何将std :: vector <std::string>转换为boost :: spirit中的结构体的成员?

我想给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 -------------------------------------------- 

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

[精神不能分配属性到单个元件结构](http://stackoverflow.com/questions/7770791/spirit-unable-to-assign-attribute-to-single-element-struct-or-融合序列)。 – 2012-11-30 22:01:26

+0

+1对于一个有趣的发现,但不知道如果可行,因为在我的真实代码中,开始深深嵌入在我真正的分析规则中(不像在这个玩具的例子中的开始) - 不知道eps是否还没有好(doesn )... – kfmfe04

回答

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; 
} 
+0

+1的工作解决方案 - 试图看看我们是否也可以做fun_call my_rec以某种方式... – kfmfe04

+0

好 - 适应深层复杂的解析(真实代码)很好。 ty - 接受。 – kfmfe04

0

您可以使用boost::spirit::qi::as来解析的数据转换为vector,然后把它放到你的结构。

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