将 Boost Spirit 递归匹配结果保存到 C++ 结构
Saving Boost Spirit recursive match results to a C++ struct
我成功解析了像 "A, (B, C), (D, E, (F, G)), H"
这样的字符串。
但是,我未能将匹配结果保存到 C++ 结构中。
我无法找出规则的正确属性类型。
以下是解析的最小测试用例。
TEST_CASE("recursive match", "[qi]")
{
namespace qi = boost::spirit::qi;
using qi::char_;
struct recursive_match
: qi::grammar<std::string::iterator, qi::ascii::space_type>
{
recursive_match() : recursive_match::base_type(div_)
{
subdiv_ = '(' >> div_ >> ')';
div_ = (char_("A-Z") | subdiv_) % ',';
}
qi::rule<std::string::iterator, qi::ascii::space_type> subdiv_;
qi::rule<std::string::iterator, qi::ascii::space_type> div_;
};
std::string s = "A, (B, C), (D, E, (F, G)), H";
auto begin = s.begin();
auto end = s.end();
recursive_match rule_;
bool r = qi::phrase_parse(begin, end, rule_, qi::ascii::space);
REQUIRE(r);
REQUIRE(begin == end);
}
任何对我有用的东西。
谢谢
我建议使用递归变体:
using node = boost::make_recursive_variant<
char,
std::vector<boost::recursive_variant_>
>::type;
using nodes = std::vector<node>;
现在,您可以更简单地声明规则:
qi::rule<It, Ast::node(), qi::ascii::space_type> node_;
qi::rule<It, Ast::nodes(), qi::ascii::space_type> list_;
定义是这样的
node_ = char_("A-Z") | '(' >> list_ >> ')';
list_ = node_ % ',';
完整演示
为调试输出添加一些代码:
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/io.hpp>
namespace qi = boost::spirit::qi;
namespace std {
// for debug output
template <typename T>
inline static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "(";
bool first = true;
for (auto& el : v) {
(first?os:os << ", ") << el;
first = false;
}
return os << ")";
}
}
namespace Ast {
using node = boost::make_recursive_variant<
char,
std::vector<boost::recursive_variant_>
>::type;
using nodes = std::vector<node>;
}
template <typename It = std::string::const_iterator>
struct recursive_match : qi::grammar<It, Ast::nodes(), qi::ascii::space_type> {
recursive_match() : recursive_match::base_type(list_) {
using namespace qi;
node_ = char_("A-Z") | '(' >> list_ >> ')';
list_ = node_ % ',';
BOOST_SPIRIT_DEBUG_NODES((node_)(list_))
}
private:
qi::rule<It, Ast::node(), qi::ascii::space_type> node_;
qi::rule<It, Ast::nodes(), qi::ascii::space_type> list_;
};
int main() {
using qi::char_;
std::string const s = "A, (B, C), (D, E, (F, G)), H";
auto begin = s.begin();
auto end = s.end();
recursive_match<> rule_;
Ast::nodes parsed;
bool ok = qi::phrase_parse(begin, end, rule_, qi::ascii::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parse failed\n";
if (begin != end)
std::cout << "Remaining unparsed input: '" << std::string(begin, end) << "'\n";
}
打印:
Parsed: (A, (B, C), (D, E, (F, G)), H)
我成功解析了像 "A, (B, C), (D, E, (F, G)), H"
这样的字符串。
但是,我未能将匹配结果保存到 C++ 结构中。
我无法找出规则的正确属性类型。
以下是解析的最小测试用例。
TEST_CASE("recursive match", "[qi]")
{
namespace qi = boost::spirit::qi;
using qi::char_;
struct recursive_match
: qi::grammar<std::string::iterator, qi::ascii::space_type>
{
recursive_match() : recursive_match::base_type(div_)
{
subdiv_ = '(' >> div_ >> ')';
div_ = (char_("A-Z") | subdiv_) % ',';
}
qi::rule<std::string::iterator, qi::ascii::space_type> subdiv_;
qi::rule<std::string::iterator, qi::ascii::space_type> div_;
};
std::string s = "A, (B, C), (D, E, (F, G)), H";
auto begin = s.begin();
auto end = s.end();
recursive_match rule_;
bool r = qi::phrase_parse(begin, end, rule_, qi::ascii::space);
REQUIRE(r);
REQUIRE(begin == end);
}
任何对我有用的东西。 谢谢
我建议使用递归变体:
using node = boost::make_recursive_variant<
char,
std::vector<boost::recursive_variant_>
>::type;
using nodes = std::vector<node>;
现在,您可以更简单地声明规则:
qi::rule<It, Ast::node(), qi::ascii::space_type> node_;
qi::rule<It, Ast::nodes(), qi::ascii::space_type> list_;
定义是这样的
node_ = char_("A-Z") | '(' >> list_ >> ')';
list_ = node_ % ',';
完整演示
为调试输出添加一些代码:
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/io.hpp>
namespace qi = boost::spirit::qi;
namespace std {
// for debug output
template <typename T>
inline static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "(";
bool first = true;
for (auto& el : v) {
(first?os:os << ", ") << el;
first = false;
}
return os << ")";
}
}
namespace Ast {
using node = boost::make_recursive_variant<
char,
std::vector<boost::recursive_variant_>
>::type;
using nodes = std::vector<node>;
}
template <typename It = std::string::const_iterator>
struct recursive_match : qi::grammar<It, Ast::nodes(), qi::ascii::space_type> {
recursive_match() : recursive_match::base_type(list_) {
using namespace qi;
node_ = char_("A-Z") | '(' >> list_ >> ')';
list_ = node_ % ',';
BOOST_SPIRIT_DEBUG_NODES((node_)(list_))
}
private:
qi::rule<It, Ast::node(), qi::ascii::space_type> node_;
qi::rule<It, Ast::nodes(), qi::ascii::space_type> list_;
};
int main() {
using qi::char_;
std::string const s = "A, (B, C), (D, E, (F, G)), H";
auto begin = s.begin();
auto end = s.end();
recursive_match<> rule_;
Ast::nodes parsed;
bool ok = qi::phrase_parse(begin, end, rule_, qi::ascii::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parse failed\n";
if (begin != end)
std::cout << "Remaining unparsed input: '" << std::string(begin, end) << "'\n";
}
打印:
Parsed: (A, (B, C), (D, E, (F, G)), H)