将boost :: spirit符号表作为继承属性传递给语法

时间:2014-10-16 13:58:01

标签: c++ parsing boost grammar boost-spirit

我想创建解析键值对列表的语法,但只接受给定的键。如果输入列表包含未知密钥,则语法应该失败。 “好”键的键可以作为qi :: symbol table传递给语法。

问题:是否可以将密钥作为语法的继承属性传递?

我创建了代码原型,但不知道如何将语法中的解析器或规则或子语法转换为属性信息。

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

对于coilru上的相同代码link

1 个答案:

答案 0 :(得分: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