2014-10-16 1 views
2

Я хочу создать грамматику, которая анализирует список пар ключей, но принимает только заданные ключи. Если список ввода содержит неизвестные ключи, грамматика должна завершиться неудачей. Ключи «хороших» ключей могут быть переданы в грамматику в виде таблицы qi ::.Пропустить boost :: таблицу символов духа в грамматику как унаследованный атрибут

Вопрос: можно ли передавать ключи как унаследованные атрибуты грамматики?

Я создаю прототип кода, но не знаю, как преобразовать информацию об атрибуте в парсер или правило или подграмму внутри грамматики.

#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"; 
} 

link к тому же коду на coilru.

ответ

3

Несомненно. Это тесно связано с прославленным Nabialek Trick.

И разрешающий механизм qi::lazy:

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 –

Смежные вопросы