将 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_ % ',';

完整演示

为调试输出添加一些代码:

Live On Coliru

//#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)