2016-09-29 15 views
2

文字列に文字列をマッピングするキーと値のペアを解析したいと思います。私は右辺のため{ ... }のブロックをサポートしたいので、私は文字列の解析が失敗します。悪い精神x3文法

#include <boost/spirit/home/x3.hpp> 
#include <boost/fusion/include/std_pair.hpp> 

namespace grammar::map 
{ 
    using namespace boost::spirit::x3; 
    auto expression = rule<class expression, std::pair<std::string, std::string>>{"expression"}; 

    auto lhs = *(~char_('=')); 
    auto rest = *(~char_(';')); 
    auto block = '{' >> *expression >> '}'; 

    auto expression_def = lhs >> '=' >> (block | rest) >> ';'; 
    BOOST_SPIRIT_DEFINE(expression) 
} 

を開始する簡単な文法を思い付いた。しかし、それは私がstd::stringする表現の属性を変更しない限り、組み合わせでのコンパイルに失敗しました。

//! Transform a string into a key-value map of strings. 
template <class M, class R> 
    requires InputRange<R>() && _ContainerLike<M> 
      && Same<value_type_t<M>, std::pair<const std::string, std::string>>() 
      // && Assignable<std::pair<std::string, std::string>, value_type_t<M>>() 
M parse(R&& range) 
{ 
    auto begin = rng::begin(range); 
    auto end = rng::end(range); 
    auto map = M{}; 
    auto ret = x3::phrase_parse(begin, end, *grammar::map::expression, x3::space, map); 
    if (!ret) 
    throw std::runtime_error{"parse error"}; 
    return map; 
} 

私はエラーに

auto pair = std::pair<std::string, std::string>{}; 
auto ret = x3::phrase_parse(begin, end, grammar::map::expression, x3::space, map); 

次の式をしようと同じことが起こる

boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::detail::move_to_plain(Source&&, Dest&, mpl_::false_) [with Source = std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >; Dest = char; mpl_::false_ = mpl_::bool_<false>]’: 

私はカップルのため、そこに来ていますから位置

boost/spirit/home/x3/support/traits/move_to.hpp:62:18: error: cannot convert ‘std::remove_reference<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&>::type {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’ to ‘char’ in assignment 
      dest = std::move(src); 

を取得日のうちに見つけられないどのように適切にそれを行う。私はどんな助けもありがとう...:

boost-1.60 {-62}とgcc 6.1.1、6.2とより最近のトランクバージョンでテストしました。

+0

いや、私はstd_pair.hppが含まalread。私はそのポストでそれを明らかにする。 – Maikel

答えて

2

あなたの問題は、あなたがpair<string,string>の属性を持つようにexpressionが定義されていることですが、lhs >> '=' >> (block|rest) >> ';'の合成された属性は、基本的にsynt_attr=pair<string,variant<map_of_value_type_synt_attr,string>>あるsynt_attr=tuple<string,variant<vector<synt_attr>,string>>です。

  • 変更pair<string,string>なるように合成された属性:だからあなたはあなたが望む結果に応じて、少なくとも2つのオプションがあります。合成された属性と互換性のある属性を持つようにexpressionのあなたの定義を変更

    auto expression_def = lhs >> '=' >> (raw[block] | rest) >> ';'; 
    
  • :これはx3::rawディレクティブ(running on WandBox)を使用して非常に簡単です。これは再帰バリアントの使用を必要とし、訪問者(running on WandBox)を作成する必要があるため、解析されたマップ内のデータにアクセスする必要がある方法を複雑にします。

    //A value is either a `string` or a `map<string,Value>` 
    using Value = boost::make_recursive_variant<std::string,std::map<std::string,boost::recursive_variant_>>::type; 
    
    ... 
    
    struct printer : boost::static_visitor<void> 
    { 
        printer(int indent) :indent(indent) {} 
    
        void operator()(const std::string& val) const 
        { 
         std::cout << std::string(indent, ' ') << val << std::endl; 
        } 
    
        void operator()(const std::map<std::string,Value>& val) const 
        { 
         for (const auto& pair : val) 
         { 
          std::cout << std::string(indent, ' ') << pair.first << ':' << std::endl; 
          boost::apply_visitor(printer(indent + 4), pair.second); 
          std::cout << std::string(indent, ' ') << std::endl; 
         } 
        } 
    
    
        int indent; 
    }; 
    
    void print_map(const Value& val) 
    { 
        boost::apply_visitor(printer(0), val); 
    } 
    
+0

はい、問題でした。あなたの生のソリューションは本当に素晴らしいです! ;-) ありがとうございました。 – Maikel

関連する問題