X3

时间:2019-01-24 10:04:27

标签: c++ c++14 boost-spirit boost-spirit-x3

我需要解析一个元素序列,其中第一个数字告诉您接下来必须解析多少个元素。

为简化我的需求:[3 10 20 30]的解析如下所示:

- Number of elements: 3
- Vector of elements: {10, 20, 30}

由于习惯了Qi及其“重复指令+凤凰”语法,我在X3上尝试了相同的方法,但编译失败。我正在网上寻找同样的问题,并且在堆栈溢出中找到下一个链接:Boost Spirit X3 cannot compile repeat directive with variable factor

对于X3中如此优雅地解决的问题,如何在X3中如此丑陋和笨拙,我感到震惊(个人观点,请没人冒犯)。当然,我知道由于c ++ 14取代了phoonix而导致的弃用的原因。

但是我不知道X3在这个主题上是否会有进一步的改进,因为该帖子来自2015年。我一直在寻找,但没有发现。有什么建议吗?

注意-不包含任何代码,因为该大小写/代码与发布的链接相同。

谢谢。

1 个答案:

答案 0 :(得分:3)

通常,这意味着该功能没有PR(或确实存在问题)。 repeat也有设计问题。例如,您可以使用它来解析{10 20 30},但不能解析{10, 20, 30}(需要一种list解析器)。

我不同意Qi具有出色的实现方式,因为您必须使用带有局部变量的规则或将引用传递给外部值。自然的方法似乎是repeat(len_parser)[item_parser],但是它具有一些附加的设计问题(或某些设计问题限制了复杂指令的灵活性)。

幸运的是,Spirit X3在编写自己的解析器组合器时要简单得多。

#include <boost/spirit/home/x3.hpp>

namespace x3e {

namespace x3 = boost::spirit::x3;

template <typename LenParser, typename Subject>
struct vlrepeat_directive : x3::unary_parser<Subject, vlrepeat_directive<LenParser, Subject>>
{
    using base_type = x3::unary_parser<Subject, vlrepeat_directive<LenParser, Subject>>;
    static bool const handles_container = true;

    vlrepeat_directive(LenParser const& lp_, Subject const& subject)
        : base_type(subject), lp(lp_) {}

    template<typename Iterator, typename Context, typename RContext, typename Attribute>
    bool parse(Iterator& first, Iterator const& last
      , Context const& context, RContext& rcontext, Attribute& attr) const
    {
        static_assert(x3::traits::has_attribute<LenParser, Context>::value, "must syntesize an attribute");

        Iterator iter = first;
        typename x3::traits::attribute_of<LenParser, Context>::type len;
        if (!lp.parse(iter, last, context, rcontext, len))
            return false;

        for (; len; --len) {
            if (!x3::detail::parse_into_container(
                    this->subject, iter, last, context, rcontext, attr))
                return false;
        }

        first = iter;
        return true;
    }

    LenParser lp;
};

template <typename LenParser>
struct vlrepeat_gen
{
    template <typename Subject>
    vlrepeat_directive<LenParser, typename x3::extension::as_parser<Subject>::value_type>
    operator[](Subject const& p) const
    {
        return { lp, x3::as_parser(p) };
    }

    LenParser lp;
};

template <typename Parser>
vlrepeat_gen<Parser> vlrepeat(Parser const& p)
{
    static_assert(x3::traits::is_parser<Parser>::value, "have to be a parser");
    return { p };
}

}

template <typename LenParser, typename Subject, typename Context>
struct boost::spirit::x3::traits::attribute_of<x3e::vlrepeat_directive<LenParser, Subject>, Context>
    : build_container<typename attribute_of<Subject, Context>::type> {};

并使用它:

#include <iostream>
#include <vector>

int main()
{
    namespace x3 = boost::spirit::x3;

    auto s = "5: 1 2 3 4 5", e = s + std::strlen(s);
    std::vector<int> v;
    if (phrase_parse(s, e, x3e::vlrepeat(x3::uint_ >> ':')[x3::int_], x3::space, v)) {
        std::cout << "Result:\n";
        for (auto x : v)
            std::cout << x << '\n';
    }
    else
        std::cout << "Failed!\n";
}

输出:

Result:
1
2
3
4
5

https://wandbox.org/permlink/K572K0BMEqA8lMJm

(它调用了detail::parse_into_container,这不是公共API)