如何解决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 Attributes 或 Locals 将状态注入到规则中。
使用第一个演示:
#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 的许多限制都消失了,因为它更容易编写规则。你会写几乎相同但不同的:
#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 举报,一经查实,本站将立刻删除。