2012-07-30 2 views
3

키 - 값 문자열을 구조체로 파싱하려고합니다. 일부 키 - 값은 없거나 다른 순서 일 수 있습니다. 따라서 at_key<> 지시문을 사용하여 구조를 수정하고 구문을 분석하려면 boost::fusion을 사용하고 싶습니다.부스트 스피리트와 퓨전을 사용하여 연관 구조로 구문 분석하기

#include <iostream> 
#include <string> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/adapted.hpp> 
#include <boost/fusion/sequence.hpp> 

using namespace std; 
namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 
namespace phx = boost::phoenix; 

using boost::fusion::at_key; 

typedef string::const_iterator iter_type; 

struct Couple { 
    int a; 
    int b; 
    Couple() : a(0), b(0) {} 
}; 

namespace keys { 
    struct first; 
    struct second; 
} 

BOOST_FUSION_ADAPT_ASSOC_STRUCT(
    Couple, 
    (int, a, keys::first) 
    (int, b, keys::second) 
    ) 


struct G: qi::grammar< iter_type, Couple(), ascii::space_type > 
{ 
    G() : G::base_type(start_rule) { 
     using qi::_val; 
     using qi::_1; 
     using qi::_2; 

     start_rule = 
         ("first" >> qi::int_ 
           [ at_key<keys::first>(_val) = _1 ] 
         ) 
        ^
         ("second" >> qi::int_ 
           [ at_key<keys::second>(_val) = _1 ] 
         ); 
    } 

    qi::rule< iter_type, Couple(), ascii::space_type > start_rule; 
}; 

int main() { 
    Couple couple; 
    string example = "second 2 first 1"; 
    iter_type begin(example.begin()); 
    iter_type end(example.end()); 

    // test at_key -- compiles with no error 
    at_key<keys::second>(couple) = 5; 

    bool ok = qi::phrase_parse(begin, end, G(), ascii::space, couple); 
    if (ok) 
     cout << couple.a << " " << couple.b << endl; 
    else 
     cout << "Parse failed" << endl; 

    return 0; 
} 

문제는 코드가 컴파일되지 않는다는 것입니다 (부스트 1.50.0, g ++ 4.5.0이는 MinGW는) 분명히 at_key<> 규칙에 실패

In file included from D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:10:0, 
       from D:\projects\workspace\boost/boost/fusion/include/category_of.hpp:10, 
       from D:\projects\workspace\boost/boost/proto/fusion.hpp:20, 
       from D:\projects\workspace\boost/boost/proto/core.hpp:21, 
       from D:\projects\workspace\boost/boost/proto/proto.hpp:12, 
       from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16, 
       from ..\src\spirit02_test.cpp:11: 
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp: In instantiation of 'boost::fusion::detail::fusion_category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >': 
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:44:58: instantiated from 'boost::fusion::extension::category_of_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> > >' 
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:66:9: instantiated from 'boost::fusion::traits::category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >' 
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:73:9: instantiated from 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >' 
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: instantiated from 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >' 
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
..\src\spirit02_test.cpp:54:35: instantiated from here 
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp:15:38: error: no type named 'category' in 'const struct boost::phoenix::actor<boost::spirit::attribute<0> >' 
In file included from D:\projects\workspace\boost/boost/proto/args.hpp:21:0, 
       from D:\projects\workspace\boost/boost/proto/core.hpp:14, 
       from D:\projects\workspace\boost/boost/proto/proto.hpp:12, 
       from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16, 
       from ..\src\spirit02_test.cpp:11: 
D:\projects\workspace\boost/boost/mpl/if.hpp: In instantiation of 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >': 
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
..\src\spirit02_test.cpp:54:35: instantiated from here 
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >' 
D:\projects\workspace\boost/boost/mpl/if.hpp:70:41: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >' 
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0, 
       from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10, 
       from D:\projects\workspace\boost/boost/proto/fusion.hpp:22, 
       from D:\projects\workspace\boost/boost/proto/core.hpp:21, 
       from D:\projects\workspace\boost/boost/proto/proto.hpp:12, 
       from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16, 
       from ..\src\spirit02_test.cpp:11: 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>': 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
..\src\spirit02_test.cpp:54:35: instantiated from here 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>' 
..\src\spirit02_test.cpp: In constructor 'G::G()': 
..\src\spirit02_test.cpp:54:35: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)' 
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0, 
       from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10, 
       from D:\projects\workspace\boost/boost/proto/fusion.hpp:22, 
       from D:\projects\workspace\boost/boost/proto/core.hpp:21, 
       from D:\projects\workspace\boost/boost/proto/proto.hpp:12, 
       from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14, 
       from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16, 
       from ..\src\spirit02_test.cpp:11: 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: At global scope: 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>': 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>' 
..\src\spirit02_test.cpp:58:36: instantiated from here 
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>' 
..\src\spirit02_test.cpp: In constructor 'G::G()': 
..\src\spirit02_test.cpp:58:36: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)' 

나는 간단한 규칙을 사용하는 경우 (연관성없이) 모든 컴파일 잘 작동하지만이 솔루션은 다소 약해 :

// A non-associative solution 
    //start_rule %= (("first" >> qi::int_)^("second" >> qi::int_)); 

가 왜 의미 행동에 at_key을 사용할 수 없습니다? 비 연관 구조로 "연관"구문 분석을 수행하는 더 좋은 방법이 있습니까?

+0

지금까지 at_key 또는 BOOST_FUSION_ADAPT_ASSOC_STRUCT를 사용한 적이 없습니다. 하지만 : std :: map <>으로 구문 분석하는 것이 가능한가? 어쩌면 문법을 변경하여 boost :: optional으로 해석 할 수도 있지만 가능하지 않을 수도 있습니다. – duselbaer

+0

@duselbaer std :: map은 허용됩니다. 지역 변수를 사용하고 ref()로 액세스하는 것이 더 빠를 수도 있지만 여전히 추가 매핑이 필요하지 않았습니다. – Lyth

답변

7

at_key의 게으른 버전이 필요합니다. patch for this는 (아직) 성령으로 그것을하지 슬프게 결코 :

/*============================================================================= 
    Copyright (c) 2005-2008 Hartmut Kaiser 
    Copyright (c) 2005-2007 Joel de Guzman 
    Copyright (c) 2011  Michael Caisse 

    Distributed under the Boost Software License, Version 1.0. (See accompanying 
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
==============================================================================*/ 
#ifndef PHOENIX_SEQUENCE_AT_KEY_HPP 
#define PHOENIX_SEQUENCE_AT_KEY_HPP 

#include <boost/fusion/include/at_key.hpp> 
#include <boost/spirit/home/phoenix/core/actor.hpp> 
#include <boost/spirit/home/phoenix/core/compose.hpp> 
#include <boost/type_traits/remove_reference.hpp> 

namespace boost { namespace phoenix 
{ 
    template <typename Key> 
    struct at_key_eval 
    { 
     template <typename Env, typename Tuple> 
     struct result 
     { 
      typedef typename Tuple::template result<Env>::type tuple; 
      typedef typename 
       fusion::result_of::at_key< 
        typename remove_reference<tuple>::type, Key 
       >::type 
      type; 
     }; 

     template <typename RT, typename Env, typename Tuple> 
     static RT 
     eval(Env const& env, Tuple const& t) 
     { 
      return fusion::at_key<Key>(t.eval(env)); 
     } 
    }; 

    template <typename Key, typename Tuple> 
    inline actor<typename as_composite<at_key_eval<Key>, Tuple>::type> 
    at_key(Tuple const& tup) 
    { 
     return compose<at_key_eval<Key> >(tup); 
    } 

}} 

#endif 

당신이 그것을 추가하는 경우

, 당신은 boost::phoenix::at_key을 사용할 수 있습니다 : 예상대로

using boost::phoenix::at_key; 

것들 컴파일하고 작동합니다. 링크 된 패치는 물론이 새 헤더를 포함하도록 boost/spirit/home/phoenix/fusion.hpp을 수정합니다.

+0

자세한 답장을 보내 주셔서 감사합니다. – Lyth

+0

이번에는 Trac 문제 추적기에서 기능 요청을보고했습니다. https://svn.boost.org/trac/boost/ticket/7199 - 이번에는 잊지 않을 것이라고 확신합니다. 나는 phoenix가 일반적으로 '배터리 포함'(즉, 알고리즘 및 컨테이너 접근자를 수정할 필요가 없음)과 함께 제공되는 것을 좋아하므로 실제로 이와 같은 느낌을 감독과 같이 느낍니다. – sehe

+0

패치 용 Thx입니다. 또한 OP의 코드가 boost :: phoenix :: at_key를 사용하도록 변경해야한다고 언급해야합니다. 일단 당신이 그것을 밖으로 일하는 명백한! – John