ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 将已解析序列的每个元素传递给返回规则属性类型的函数

2019-08-27 23:06:09  阅读:212  来源: 互联网

标签:boost-spirit-x3 c css c17 boost-spirit


我想解析CSS颜色函数(为简单起见,所有参数都是0到255之间的数字)

rgb(r,g,b)
rgba(r,g,b,a)
hsl(h,s,l)
hsla(h,s,l,a)

struct color
{
    color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a) : red{r}, green{g}, blue{b}, alpha{a} {}
    static color hsl(std::uint8_t h, std::uint8_t s, std::uint8_t l, std::uint8_t a) { ... }
    std::uint8_t red;
    std::uint8_t green;
    std::uint8_t blue;
    std::uint8_t alpha;
}

我有一个工作的hsl函数实现,它将h,s和l转换为rgb值.

我也有处理前两个函数的规则:

constexpr auto uint8 = uint_parser<std::uint8_t>{};
const auto color_rgb = rule<struct rgb, color>{"rgb"}
                     = lit("rgb") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ')' >> attr(255);
const auto color_rgba = rule<struct rgba, color>{"rgba"}
                      = lit("rgba") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ')';

这是因为我使用过

BOOST_FUSION_ADAPT_STRUCT(color,
                          red, green, blue, alpha)

问题在于hsl函数.我不能做第二个BOOST_FUSION_ADAPT_STRUCT,所以我想到对各个值序列使用语义动作,其中语义动作将简单地从序列构造颜色.像这样的东西:

const auto color_hsl = rule<struct hsl, color, true>{"hsl"}
                   = (lit("hsl") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ')' >> attr(255))[color::hsl];

这不起作用,或者我不会问这个问题. Boost.Spirit.X3也没有任何意义上的东西

[ qi::_val = phx::construct<color>(...), qi::_1, qi::_2, qi::_3, qi::_4) ];

似乎我想手动执行BOOST_FUSION_ADAPT_STRUCT所执行的操作,但是在语义操作中.这是可能的,我应该如何处理?我知道序列的属性应该是具有四个解析值的“融合矢量”元组类实体.我想提取它们并将它们填充到color :: hsl中以生成规则的属性.

解决方法:

这里有许多提示.

>

I cannot do a second BOOST_FUSION_ADAPT_STRUCT

当然可以,见BOOST_FUSION_ADAPT_STRUCT_NAMED
>在齐这种一般形式似乎适用:

[ qi::_val = phxfunction(qi::_0) ]

你可以通过制作你自己的演员类型来进一步简化它,这样你就可以提供你的“工厂动作”:[factory(& Foo :: makeBar)].

如果你投入fusion ::apply¹的实现,你可以避免处理Fusion序列manuallt
>但是,您可能想要了解这个 – 非常隐蔽 – 语义操作的属性兼容模式:BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT.隐藏在该更改日志中:

Semantic actions now support attribute compatibility. This is a breaking change but #define BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT must be defined in order for the new behavior to kick in. By default, the old behavior is still in place.

你可以通过更少的调整来获得你想要的行为.
> X3真的具有可塑性.我们可以将上面描述的工厂助手尽可能地:

auto factory = [](auto f) {
    return [f](auto& ctx) {
        x3::_val(ctx) = my_apply(f, x3::_attr(ctx));
    };
};

我将抛出my_apply的快速草稿(对于前面描述的boost :: fusion :: apply):

namespace detail {
    template <class F, class Sequence, std::size_t... I>
        constexpr decltype(auto) apply_impl(F&& f, Sequence&& t, std::index_sequence<I...>)
        {
            return std::invoke(std::forward<F>(f), boost::fusion::at_c<I>(std::forward<Sequence>(t))...);
        }
}

template <class F, class Sequence>
    constexpr decltype(auto) my_apply(F&& f, Sequence&& t)
    {
        return detail::apply_impl(
                std::forward<F>(f), std::forward<Sequence>(t),
                std::make_index_sequence<typename boost::fusion::result_of::size<std::remove_reference_t<Sequence> >::type{}>{});
    }

现在我们可以拥有解析器:

namespace parser {
    using namespace x3;

    constexpr auto uint8  = uint_parser<std::uint8_t>{};

    auto factory = [](auto f) {
        return [f](auto& ctx) {
            x3::_val(ctx) = my_apply(f, x3::_attr(ctx));
        };
    };

    const auto color_rgb  = rule<struct rgb, ast::color>{"rgb"}
                          = lit("rgb") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> x3::attr(255u) >> ')';
    const auto color_rgba = rule<struct rgba, ast::color>{"rgba"}
                          = lit("rgba") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ')';
    const auto color_hsl  = rule<struct hsl, ast::color>{"hsl"}
                          = (lit("hsl") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> attr(255u) >> ')') [factory(ast::color::hsl)];

    const auto color = skip(space) [ color_rgba | color_rgb | color_hsl ];
} 

并测试它:

int main() {
    for (std::string const input : {
            "rgb(1,2,3)",
            "rgba(4,5,6,7)",
            "hsl(8,9,10)" }) 
    {
        std::cout << " ----- Parsng " << std::quoted(input) << " --------\n";
        auto begin = input.begin(), end = input.end();

        ast::color result;
        bool success = parse(begin, end, parser::color, result);

        if (success) {
            std::cout << "parsed: ";
            std::cout << result << "\n";
        } else {
            std::cout << "failed\n";
        }

        if (begin != end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(begin, end)) << std::endl;
        }
    }
}

打印:

Live On Coliru

 ----- Parsng "rgb(1,2,3)" --------
parsed: rgba(1,2,3,255)
 ----- Parsng "rgba(4,5,6,7)" --------
parsed: rgba(4,5,6,7)
 ----- Parsng "hsl(8,9,10)" --------
TODO: implement static ast::color ast::color::hsl(uint8_t, uint8_t, uint8_t, uint8_t)(8,9,10,255)
parsed: rgba(8,9,10,255)

完整清单

Live On Coliru

#include <iostream>
#include <iomanip>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/include/size.hpp>

namespace x3 = boost::spirit::x3;


namespace ast {
    using std::uint8_t;

    struct color {
        uint8_t red, green, blue, alpha;

        color(uint8_t r=0, uint8_t g=0, uint8_t b=0, uint8_t a=255) : red{r}, green{g}, blue{b}, alpha{a} {}

        static color hsl(uint8_t h, uint8_t s, uint8_t l, uint8_t a) { 
            std::cerr << "TODO: implement " << __PRETTY_FUNCTION__ << "(" << 1*h << "," << 1*s << "," << 1*l << "," << 1*a << ")\n";
            return {h,s,l,a}; }
    };

    static inline std::ostream& operator<<(std::ostream& os, color const& c) {
        return os << "rgba(" << 1*c.red << "," << 1*c.green << "," << 1*c.blue << "," << 1*c.alpha << ")";
    }
}

BOOST_FUSION_ADAPT_STRUCT(ast::color, red, green, blue, alpha);

namespace {
    namespace detail {
        template <class F, class Sequence, std::size_t... I>
            constexpr decltype(auto) apply_impl(F&& f, Sequence&& t, std::index_sequence<I...>)
            {
                return std::invoke(std::forward<F>(f), boost::fusion::at_c<I>(std::forward<Sequence>(t))...);
            }
    }

    template <class F, class Sequence>
        constexpr decltype(auto) my_apply(F&& f, Sequence&& t)
        {
            return detail::apply_impl(
                    std::forward<F>(f), std::forward<Sequence>(t),
                    std::make_index_sequence<typename boost::fusion::result_of::size<std::remove_reference_t<Sequence> >::type{}>{});
        }
}

namespace parser {
    using namespace x3;

    constexpr auto uint8  = uint_parser<std::uint8_t>{};

    auto factory = [](auto f) {
        return [f](auto& ctx) {
            x3::_val(ctx) = my_apply(f, x3::_attr(ctx));
        };
    };

    const auto color_rgb  = rule<struct rgb, ast::color>{"rgb"}
                          = lit("rgb") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> x3::attr(255u) >> ')';
    const auto color_rgba = rule<struct rgba, ast::color>{"rgba"}
                          = lit("rgba") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> ')';
    const auto color_hsl  = rule<struct hsl, ast::color>{"hsl"}
                          = (lit("hsl") >> '(' >> uint8 >> ',' >> uint8 >> ',' >> uint8 >> attr(255u) >> ')') [factory(ast::color::hsl)];

    const auto color = skip(space) [ color_rgba | color_rgb | color_hsl ];
} 

int main() {
    for (std::string const input : {
            "rgb(1,2,3)",
            "rgba(4,5,6,7)",
            "hsl(8,9,10)" }) 
    {
        std::cout << " ----- Parsng " << std::quoted(input) << " --------\n";
        auto begin = input.begin(), end = input.end();

        ast::color result;
        bool success = parse(begin, end, parser::color, result);

        if (success) {
            std::cout << "parsed: ";
            std::cout << result << "\n";
        } else {
            std::cout << "failed\n";
        }

        if (begin != end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(begin, end)) << std::endl;
        }
    }
}

¹似乎不存在.当然你可以复制到std :: tuple并使用std::apply(也是experimental)

标签:boost-spirit-x3,c,css,c17,boost-spirit
来源: https://codeday.me/bug/20190827/1745675.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有