2010-07-20 2 views
3

문제를 설명하기 위해 테스트 응용 프로그램을 만들었습니다. "a ="또는 "b ="로 시작하고 "\ r \ n"으로 구분되는 정수 목록을 구문 분석합니다. 목록에는 임의의 순서로 해당 필드가 여러 번 나타납니다.boost :: phoenix :: at_c와 boost :: spirit :: qi :: grammar의 조합이 있습니까

#include <string> 
#include <vector> 
#include <iostream> 

#include <boost/spirit/include/qi.hpp> 

#include <boost/spirit/include/phoenix.hpp> 

#include <boost/fusion/include/adapt_struct.hpp> 


typedef std::vector<unsigned int> uint_vector_t; 

std::ostream& operator<<(std::ostream& out, const uint_vector_t &data) 
{ 
    for (unsigned int i(0); i < data.size(); i++) 
    { 
     out << data[i] << '\n'; 
    } 
    return out; 
} 

struct MyStruct 
{ 
    uint_vector_t m_aList; 
    uint_vector_t m_bList; 
}; 

BOOST_FUSION_ADAPT_STRUCT 
(
    MyStruct, 
    (uint_vector_t, m_aList) 
    (uint_vector_t, m_bList) 
) 
; 

template<typename Iterator> 
struct MyParser : public boost::spirit::qi::grammar<Iterator, 
     MyStruct()> 
{ 
    MyParser() : 
     MyParser::base_type(Parser, "Parser") 
    { 
     using boost::spirit::qi::uint_; 
     using boost::spirit::qi::_val; 
     using boost::spirit::qi::_1; 

     using boost::phoenix::at_c; 
     using boost::phoenix::push_back; 

     Parser = 
       *(
         aParser [push_back(at_c<0>(_val), _1)] 
        | 
         bParser [push_back(at_c<1>(_val), _1)] 
       ); 
     aParser = "a=" >> uint_ >> "\r\n"; 
     bParser = "b=" >> uint_ >> "\r\n"; 
    } 
     boost::spirit::qi::rule<Iterator, MyStruct()> Parser; 
     boost::spirit::qi::rule<Iterator, unsigned int()> aParser, bParser; 
}; 

int main() 
{ 
    using boost::spirit::qi::phrase_parse; 

    std::string input("a=0\r\nb=7531\r\na=2\r\na=3\r\nb=246\r\n"); 
    std::string::const_iterator begin = input.begin(); 
    std::string::const_iterator end = input.end(); 
    MyParser<std::string::const_iterator> parser; 

    MyStruct result; 
    bool succes = phrase_parse(begin, end, parser, "", result); 
    assert(succes); 

    std::cout << "===A===\n" <<result.m_aList << "===B===\n" << result.m_bList << std::endl; 
} 

실제로는 구문 분석 할 필요가있는 다른 유형의 필드가 더 있습니다. 이 접근법에 대한 나의 반대 의견은 다음 표현식에 있습니다. [push_back (at_c < 0> (_ val), _1)] 여기에는 할당과 MyStruct의 첫 번째 요소 사이에 '숨겨진 종속성'이 있습니다. 이로 인해 코드가 변경되기 쉽지 않습니다. 구조체가 변경되면 여전히 컴파일 될 수 있지만 더 이상 기대되는 것은 수행하지 않습니다.

나는 같은 건설 바라고 있어요 : [와 push_back (at_c < 0> 바인드 (& MYSTRUCT :: aList, ARG1) (_ 발), _1)]를 는 정말 이름으로 바인딩 그래서 this.를 참조하십시오.

이렇게 할 수 있나요? 아니면 완전히 다른 접근 방식을 취해야합니까?

답변

7

피닉스 당신은뿐만 아니라 데이터 멤버를 결합 할 수 있습니다, 그래서 당신은 쓸 수 있습니다 :

Parser = 
    *( aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
    | bParser [push_back(bind(&MyStruct::m_bList, _val), _1)] 
    ); 

또한,이 경우 더 이상 당신의 구조에 대한 FUSION_ADAPT 마법이 필요하지 않습니다.