使用 Boost Spirit X3 解析多个 CSS 选择器

Parsing multiple CSS selectors with Boost Spirit X3

我正在尝试使用 Boost Spirit X3 解析多个 CSS 选择器。例如,如果我有以下适用于多个 ID(选择器)的 CSS 规则:

#ID1, #ID2, #ID3 { color:#000000; }

其中 #ID1, #ID2, #ID3 是选择器,color:#000000; 是声明块,相同的声明块适用于所有 3 个选择器。并假设 ruleselectordeclaration_block 的结构如下:

struct Rule {
   Selector selector;
   DeclationBlock declarationBlock;
}

struct Selector {
std::string target;
}

struct DeclarationBlock {
std::vector<Declaration> declarations;
}

而且我已经有了选择器和声明块的 Spirit 规则:

auto selector = x3::rule<struct SelectorId, css::Selector>{"selector"};
auto declaration_block = x3::rule<struct DeclarationBlockId, css::DeclarationBlock>{"declaration-block"};

单个选择器的解析规则很简单:

auto rule = x3::rule<struct RuleId, css::Rule>{"rule"} = selector >> declaration_block;
auto rules = x3::rule<struct RulesId, std::vector<css::Rule>>{"rules"} = *rule;

但是,我的问题是,如何为多个选择器解析同一个声明块?我正在尝试使用语义操作来基本上复制所有选择器的声明块,但我不知道这是否是最好的方法。

我不确定是否可以将声明块的解析器属性用于多个选择器。很可能不是。

我宁愿以反映实际代码的方式更改 AST(和解析器):

struct Rule {
   std::vector<Selector> selectors;  // why not?
   DeclationBlock declarationBlock;
}

auto const selectors = selector % ",";

如果您希望 selectordeclarationBlock 之间有一个 1:1 对应关系,那么,根据上面定义的 Rule,应该可以在另一个这样的解析器:

struct SingleRule
{
    Selector selector;
    DeclationBlock declarationBlock;
};

auto unwrap = [](auto & ctx)
{
    // iterate through all the selectors
    // and add them to the vector together with linked
    // declaration block
    for (auto const & s: _attr(ctx).selectors)
        _val(ctx).push_back(SingleRule{s, _attr(ctx).declarationBlock});
};

auto const unwrapped_rules
    = x3::rule<struct UnwrappedRulesId, std::vector<css::SingleRule>>
    = rule [unwrap];

虽然不确定这是个好主意。也许,从解析器中抛出最接近和最简单的 AST,然后再进行所有的简化和优化会更容易。

此外,已经有一个CSS-parser使用Boost.Spirit.X3编写。您可以尝试将其作为参考或灵感。