在精神气中解析嵌套层次结构 - 语法不正确
Parsing a nested hierarchy in spirit qi - can't get the grammar right
我对 spirit::qi 有点头疼,需要一些帮助。我正在尝试解析以下形式的短语:
( wheels=4 & chassis=metal & engine=( cylinders=8 & volume=6209 ) )
...进入嵌套结构:
class dict : public std::map<std::string, boost::variant<dict, std::string>>
... 其中 car_dict["wheels"] returns “4”,以及 car_dict["engine"] returns 另一个字典, 其中 engine_dict["cylinders"] returns "8".
这是我的语法,我希望在这方面有丰富经验的人能指出我哪里出错了。
struct qi_car_grammar : qi::grammar<std::string::const_iterator, dict()>
{
qi::rule<std::string::const_iterator, dict()> car_dict;
qi::rule<std::string::const_iterator, std::string()> car_key;
qi::rule<std::string::const_iterator, boost::variant<dict, std::string>()> car_variant_value;
qi_car_grammar()
: qi_car_grammar::base_type(car_dict)
{
// RULES
car_key %= *(qi::lit(' ')) >> *(~qi::lit('='));
car_variant_value %= car_dict | *(~qi::char_("&)"));
car_dict = qi::lit('(')
>> car_key >> qi::lit('=') >> car_variant_value
>> *(qi::lit('&') >> car_key >> qi::lit('=') >> car_variant_value)
>> qi::lit(')');
}
}
感谢任何帮助。在任何人提出建议之前,不,我对我要解析的结构没有太多控制权。
嗯。我刚刚做了一般清理通行证¹。
你们已经很接近了。
您可能只是错过了 boost/fusion/adapted/std_pair.hpp
header,这是将解析的元组自动转换为 std::pair<K,V>
所必需的。
这是工作示例(我花了大部分时间创建 dict
漂亮的打印机...):
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
class dict : public std::map<std::string, boost::variant<dict, std::string>>
{
};
template <typename It = std::string::const_iterator, typename Skipper = qi::space_type>
struct qi_car_grammar : qi::grammar<It, dict(), Skipper>
{
qi_car_grammar()
: qi_car_grammar::base_type(car_dict)
{
// RULES
car_key = *~qi::char_("=");
car_value = *~qi::char_("&)");
car_variant_value = car_dict | car_value;
car_dict = '(' >> (car_key >> '=' >> car_variant_value) % '&' >> ')';
}
private:
qi::rule<It, dict(), Skipper> car_dict;
qi::rule<It, std::string()> car_key, car_value;
qi::rule<It, boost::variant<dict, std::string>(), Skipper> car_variant_value;
};
// for debug
static inline std::ostream& operator<<(std::ostream& os, dict const& d) {
struct vis {
using result_type = void;
std::ostream& _os;
std::string indent;
void operator()(std::string const& s) const { _os << s; }
void operator()(dict const& d) const {
_os << "(\n";
for (auto& entry: d) {
_os << indent << " " << entry.first << " = ";
boost::apply_visitor(vis{_os, indent+" "}, entry.second);
_os << "\n";
}
_os << indent << ")\n";
}
} v { os, "" };
v(d);
return os;
}
int main()
{
std::string const input = "( wheels=4 & chassis=metal & engine=( cylinders=8 & volume=6209 ) )";
dict parsed;
qi_car_grammar<> g;
auto f = input.begin(), l = input.end();
bool ok = qi::phrase_parse(f, l, g, qi::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parsed failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
打印:
Parsed: (
chassis = metal
engine = (
cylinders = 8
volume = 6209
)
wheels = 4
)
¹(就像我在阅读代码示例时经常做的那样,它有助于我的理解)
我对 spirit::qi 有点头疼,需要一些帮助。我正在尝试解析以下形式的短语:
( wheels=4 & chassis=metal & engine=( cylinders=8 & volume=6209 ) )
...进入嵌套结构:
class dict : public std::map<std::string, boost::variant<dict, std::string>>
... 其中 car_dict["wheels"] returns “4”,以及 car_dict["engine"] returns 另一个字典, 其中 engine_dict["cylinders"] returns "8".
这是我的语法,我希望在这方面有丰富经验的人能指出我哪里出错了。
struct qi_car_grammar : qi::grammar<std::string::const_iterator, dict()>
{
qi::rule<std::string::const_iterator, dict()> car_dict;
qi::rule<std::string::const_iterator, std::string()> car_key;
qi::rule<std::string::const_iterator, boost::variant<dict, std::string>()> car_variant_value;
qi_car_grammar()
: qi_car_grammar::base_type(car_dict)
{
// RULES
car_key %= *(qi::lit(' ')) >> *(~qi::lit('='));
car_variant_value %= car_dict | *(~qi::char_("&)"));
car_dict = qi::lit('(')
>> car_key >> qi::lit('=') >> car_variant_value
>> *(qi::lit('&') >> car_key >> qi::lit('=') >> car_variant_value)
>> qi::lit(')');
}
}
感谢任何帮助。在任何人提出建议之前,不,我对我要解析的结构没有太多控制权。
嗯。我刚刚做了一般清理通行证¹。
你们已经很接近了。
您可能只是错过了 boost/fusion/adapted/std_pair.hpp
header,这是将解析的元组自动转换为 std::pair<K,V>
所必需的。
这是工作示例(我花了大部分时间创建 dict
漂亮的打印机...):
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
class dict : public std::map<std::string, boost::variant<dict, std::string>>
{
};
template <typename It = std::string::const_iterator, typename Skipper = qi::space_type>
struct qi_car_grammar : qi::grammar<It, dict(), Skipper>
{
qi_car_grammar()
: qi_car_grammar::base_type(car_dict)
{
// RULES
car_key = *~qi::char_("=");
car_value = *~qi::char_("&)");
car_variant_value = car_dict | car_value;
car_dict = '(' >> (car_key >> '=' >> car_variant_value) % '&' >> ')';
}
private:
qi::rule<It, dict(), Skipper> car_dict;
qi::rule<It, std::string()> car_key, car_value;
qi::rule<It, boost::variant<dict, std::string>(), Skipper> car_variant_value;
};
// for debug
static inline std::ostream& operator<<(std::ostream& os, dict const& d) {
struct vis {
using result_type = void;
std::ostream& _os;
std::string indent;
void operator()(std::string const& s) const { _os << s; }
void operator()(dict const& d) const {
_os << "(\n";
for (auto& entry: d) {
_os << indent << " " << entry.first << " = ";
boost::apply_visitor(vis{_os, indent+" "}, entry.second);
_os << "\n";
}
_os << indent << ")\n";
}
} v { os, "" };
v(d);
return os;
}
int main()
{
std::string const input = "( wheels=4 & chassis=metal & engine=( cylinders=8 & volume=6209 ) )";
dict parsed;
qi_car_grammar<> g;
auto f = input.begin(), l = input.end();
bool ok = qi::phrase_parse(f, l, g, qi::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parsed failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
打印:
Parsed: (
chassis = metal
engine = (
cylinders = 8
volume = 6209
)
wheels = 4
)
¹(就像我在阅读代码示例时经常做的那样,它有助于我的理解)