我想创建解析键值对列表的语法,但只接受给定的键。如果输入列表包含未知密钥,则语法应该失败。 “好”键的键可以作为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。
答案 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