2014-10-16 44 views
2

我想創建解析鍵值對列表的語法,但只接受給定的鍵。如果輸入列表包含未知鍵,則語法應該失敗。 「好」鍵的鍵可以作爲qi :: symbol表傳遞給語法。將boost :: spirit符號表傳遞爲語法作爲繼承屬性

問題:是否可以將鍵作爲語法的繼承屬性傳遞?

我創建了代碼原型,但不知道如何將屬性信息轉換爲語法中的解析器或規則或子語法。

#include <iostream> 
#include <vector> 

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

using namespace std; 
using namespace boost; 

namespace qi = boost::spirit::qi; 

template <typename I> using string_range = iterator_range<I>; 

template <typename I> using pair_type = pair< 
    boost::optional<int>, 
    boost::optional<string_range<I>> 
>; 

template <typename I> using pairs_type = vector<pair_type<I>>; 

using symbol_table = qi::symbols<char, int>; 

template <typename Iterator> 
struct keys_and_values 
    : qi::grammar<Iterator, pairs_type<Iterator>(symbol_table const&)> 
{ 
    keys_and_values() 
    : keys_and_values::base_type(query) 
    { 
    using namespace qi; 
    query = pair (_r1) >> *((qi::lit(';') | '&') >> pair (_r1)); 
// How to convert the attribute into the parsing object??? 
    pair = -matches[_r1] >> -('=' >> -value); 
    value = raw[+qi::char_("a-zA-Z_0-9")]; 
    } 
    qi::rule<Iterator, pairs_type<Iterator>(symbol_table const&)> query; 
    qi::rule<Iterator, pair_type<Iterator>(symbol_table const&)> pair; 
    qi::rule<Iterator, string_range<Iterator>()> value; 
}; 

int main() 
{ 
    namespace qi = boost::spirit::qi; 
    string input { "key1=v1;key2=v2;key3=v3" }; 

    using string_iterator = string::const_iterator; 

    static const keys_and_values <string_iterator> p; 
    pairs_type <string_iterator> m; 

    symbol_table keys; 
    keys.add ("key1", 1) ("key2", 2) ("key3", 3) ; 

    string_iterator begin{boost::begin (input)}, end{boost::end(input)}; 

    if (qi::parse (begin, end, p(boost::phoenix::ref(keys)), m)) 
    cout << "parse ok\n"; 
} 

A link對coilru相同的代碼。

回答

3

當然。這與着名的Nabialek Trick密切相關。

和有利機制是​​:

pair = -matches[lazy(_r1)] >> -('=' >> -value); 

我還加的#define BOOST_SPIRIT_USE_PHOENIX_V3(你可能沒有明確要設置,這取決於編譯器/升壓版本)。

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3 
#include <iostream> 
#include <vector> 

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

using namespace std; 
using namespace boost; 

namespace qi = boost::spirit::qi; 

template <typename I> using string_range = iterator_range<I>; 

template <typename I> using pair_type = pair< 
    boost::optional<int>, 
    boost::optional<string_range<I>> 
>; 

template <typename I> using pairs_type = vector<pair_type<I>>; 

using symbol_table = qi::symbols<char, int>; 

template <typename Iterator> 
struct keys_and_values 
    : qi::grammar<Iterator, pairs_type<Iterator>(symbol_table const&)> 
{ 
    keys_and_values() 
    : keys_and_values::base_type(query) 
    { 
     using namespace qi; 
     query = pair (_r1) >> *((qi::lit(';') | '&') >> pair (_r1)); 
     // How to convert the attribute into the parsing object??? 
     pair = -matches[lazy(_r1)] >> -('=' >> -value); 
     value = raw[+qi::char_("a-zA-Z_0-9")]; 
    } 
    qi::rule<Iterator, pairs_type<Iterator>(symbol_table const&)> query; 
    qi::rule<Iterator, pair_type<Iterator>(symbol_table const&)> pair; 
    qi::rule<Iterator, string_range<Iterator>()> value; 
}; 

int main() 
{ 
    namespace qi = boost::spirit::qi; 
    string input { "key1=v1;key2=v2;key3=v3" }; 

    using string_iterator = string::const_iterator; 

    static const keys_and_values <string_iterator> p; 
    pairs_type <string_iterator> m; 

    symbol_table keys; 
    keys.add ("key1", 1) ("key2", 2) ("key3", 3) ; 

    string_iterator begin{boost::begin (input)}, end{boost::end(input)}; 

    if (qi::parse (begin, end, p(boost::phoenix::ref(keys)), m)) 
     cout << "parse ok\n"; 
} 

輸出:

parse ok 
+0

謝謝你以極大的答案!現在我有相關(但不同)的問題,請看看你是否有時間http://stackoverflow.com/questions/26414677 – 2014-10-16 22:06:30