代码之家  ›  专栏  ›  技术社区  ›  rubenvb

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

  •  3
  • rubenvb  · 技术社区  · 6 年前

    我想解析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值的函数实现。

    我也有 rule s处理前两个功能:

    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)
    

    问题在于 高速铁路 功能。我一秒钟也做不到 BOOST_FUSION_ADAPT_STRUCT 因此,我考虑在相应的值序列上使用语义操作,其中语义操作将简单地构造 color 从序列中。像这样:

    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) ];
    

    我好像想手动做什么 增强融合适应结构 是的,但在语义操作中。这可能吗?我应该如何处理?我知道序列的属性应该是一个具有四个解析值的“融合向量”类元组实体。我想把它们提取出来塞进 color::hsl 生成规则的属性。

    1 回复  |  直到 6 年前
        1
  •  5
  •   sehe    6 年前

    这里有很多提示。

    1. 我不能再做一次增强融合适应结构

      当然可以,看吧 BOOST_FUSION_ADAPT_STRUCT_NAMED

    2. 在QI中,这一一般形式似乎适用:

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

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

      如果您将 fusion::apply _你可以避免使用人工融合序列。

    3. 但是,您可能希望了解语义操作的这个非常好的隐藏属性兼容模式: BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT .隐藏在那个变更日志中:

      语义操作现在支持属性兼容性。这是一个突破性的变化,但定义 提升精神行动允许同胞 必须定义新行为才能启动。 默认情况下,旧行为仍然存在 .

      你可以用更少的调整来获得你想要的行为。

    4. X3真的很有延展性。我们可以吃那个 factory 上面所描述的助手包括:

      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)
    

    全部上市

    科里鲁生活

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