微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

boost Spirit 上下文相关语法规则的最佳实践

如何解决boost Spirit 上下文相关语法规则的最佳实践

只是一个说明问题的示例..(这是伪代码

经典方式:只需为每条路径制定规则。所以从“开始”开始并选择outer_rule1或outer_rule2,然后从那里进入inner_rule1和inner_rule2。您可以清楚地看到内部规则几乎相等。例如。关于一种语法,其中特殊分隔的行是由符号“:”给出的,一次由“;”给出

inner_rule1 = a >> b >> ":"
inner_rule2 = a >> b >> ";"

outer_rule1 = "X" >> inner_rule1
outer_rule2 = "Z" >> inner_rule2

start=outer_rule1 | outer_rule2

您可以通过将分隔符放在顶层来解决这个问题

inner_rule1 = a >> b
inner_rule2 = a >> b

outer_rule1 = "X" >> inner_rule1 >> ":"
outer_rule2 = "Z" >> inner_rule2 >> ";"

start=outer_rule1 | outer_rule2

但是如果内部规则更复杂,分隔符也可能在嵌套规则中使用,现在使用相同的规则但交换分隔符变得很棘手......

complex_inner1= w >> ";"
complex_inner2= r >> ":"

inner_rule1 = a >> +complex_inner1
inner_rule2 = a >> +complex_inner2

outer_rule1 = "X" >> inner_rule1
outer_rule2 = "Z" >> inner_rule2

start=outer_rule1 | outer_rule2

问题是如何制作这样的东西,在这种情况下,例如使用自定义操作,但我们知道自定义操作不是最佳选择,尤其是在使用回溯时。

complex_inner1= w >> separator
complex_inner2= r >> separator

inner_rule1 = a[separator=";"] >> +complex_inner1
inner_rule2 = a[separator=":"] >> +complex_inner2

outer_rule1 = "X" >> inner_rule1
outer_rule2 = "Z" >> inner_rule2

start=outer_rule1 | outer_rule2

解决方法

您忘记指定哪个版本的精神(Qi 或 X3)(again?)。

所以,这里是:

灵气:继承属性

您可以使用 Inherited AttributesLocals 将状态注入到规则中。

使用第一个演示:

Live On Compiler Explorer

#include <boost/spirit/include/qi.hpp>
#include <fmt/ranges.h>

namespace qi = boost::spirit::qi;

using Attr = std::vector<int>;

template <typename It>
struct Parser : qi::grammar<It,Attr()> {
    Parser() : Parser::base_type(start) {
        using namespace qi;
        inner  = int_ % lit(_r1);
        outer1 = 'X' >> inner(':');
        outer2 = 'Y' >> inner(';');
        start  = skip(space)[outer1 | outer2];
    }

  private:
    qi::rule<It,Attr()> start;
    qi::rule<It,Attr(),qi::space_type> outer1,outer2;
    qi::rule<It,Attr(char),qi::space_type> inner;
};

int main() {
    using It = std::string::const_iterator;
    Parser<It> p;

    for (std::string const& s : {
             ""," Y 7 ","X 7:-4:+99 ","Y 7 ; 42 ",})
    {
        It f = begin(s),l = end(s);

        Attr v;
        bool ok = parse(f,l,p,v);

        fmt::print("Parsed: {} {},remaining: '{}'\n",ok,v,std::string(f,l));
    }
}

印刷品

Parsed: false {},remaining: ''
Parsed: true {7},remaining: ' '
Parsed: true {7,-4,99},42},remaining: ' '

X3:函数组合

在 X3 中,Qi 的许多限制都消失了,因为它更容易编写规则。你会写几乎相同但不同的:

Live On Compiler Explorer

#include <boost/spirit/home/x3.hpp>
#include <fmt/ranges.h>

namespace x3 = boost::spirit::x3;

using Attr = std::vector<int>;

namespace Parser {
    using namespace x3;
    auto inner  = [](auto delim) { return int_ % delim; };
    auto outer1 = 'X' >> inner(':');
    auto outer2 = 'Y' >> inner(';');
    auto start  = skip(space)[outer1 | outer2];
} // namespace Parser

int main() {
    using It = std::string::const_iterator;

    for (std::string const& s : {
            "",Parser::start,l));
    }
}

打印相同。

公平地说,这掩盖了/发生/对给定样本不重要的复杂情况。但这就是非伪代码的好处:它有细节。如果你在路上遇到任何更微妙的问题,我希望你能回来提供具体的代码:)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。