递归 x3 解析器,结果传递
Recursive x3 parser with results passing around
(1)假设我们要解析一个被{}
包围的简单递归块。
{
Some text.
{
{
Some more text.
}
Some Text again.
{}
}
}
这个递归解析器非常简单。
x3::rule<struct idBlock1> const ruleBlock1{"Block1"};
auto const ruleBlock1_def =
x3::lit('{') >>
*(
ruleBlock1 |
(x3::char_ - x3::lit('}'))
) >>
x3::lit('}');
BOOST_SPIRIT_DEFINE(ruleBlock1)
(2)然后块变得更加复杂。它也可以被[]
包围。
{
Some text.
[
{
Some more text.
}
Some Text again.
[]
]
}
我们需要一个地方来存储我们拥有的哪种开括号。由于 x3 没有局部变量,我们可以改用属性 (x3::_val
)。
x3::rule<struct idBlock2, char> const ruleBlock2{"Block2"};
auto const ruleBlock2_def = x3::rule<struct _, char>{} =
(
x3::lit('{')[([](auto& ctx){x3::_val(ctx)='}';})] |
x3::lit('[')[([](auto& ctx){x3::_val(ctx)=']';})]
) >>
*(
ruleBlock2 |
(
x3::char_ -
(
x3::eps[([](auto& ctx){x3::_pass(ctx)='}'==x3::_val(ctx);})] >> x3::lit('}') |
x3::eps[([](auto& ctx){x3::_pass(ctx)=']'==x3::_val(ctx);})] >> x3::lit(']')
)
)
) >>
(
x3::eps[([](auto& ctx){x3::_pass(ctx)='}'==x3::_val(ctx);})] >> x3::lit('}') |
x3::eps[([](auto& ctx){x3::_pass(ctx)=']'==x3::_val(ctx);})] >> x3::lit(']')
);
BOOST_SPIRIT_DEFINE(ruleBlock2)
(3)块内容(包围部分),我们称之为参数,可能比这个例子复杂得多。所以我们决定为它创建一个规则。在这种情况下,此属性解决方案不起作用。幸运的是,我们仍然x3::with
指令。我们可以将开括号(或期望的右括号)保存在堆栈引用中,并将其传递到下一个级别。
struct SBlockEndTag {};
x3::rule<struct idBlockEnd> const ruleBlockEnd{"BlockEnd"};
x3::rule<struct idArg> const ruleArg{"Arg"};
x3::rule<struct idBlock3> const ruleBlock3{"Block3"};
auto const ruleBlockEnd_def =
x3::eps[([](auto& ctx){
assert(!x3::get<SBlockEndTag>(ctx).get().empty());
x3::_pass(ctx)='}'==x3::get<SBlockEndTag>(ctx).get().top();
})] >>
x3::lit('}')
|
x3::eps[([](auto& ctx){
assert(!x3::get<SBlockEndTag>(ctx).get().empty());
x3::_pass(ctx)=']'==x3::get<SBlockEndTag>(ctx).get().top();
})] >>
x3::lit(']');
auto const ruleArg_def =
*(
ruleBlock3 |
(x3::char_ - ruleBlockEnd)
);
auto const ruleBlock3_def =
(
x3::lit('{')[([](auto& ctx){x3::get<SBlockEndTag>(ctx).get().push('}');})] |
x3::lit('[')[([](auto& ctx){x3::get<SBlockEndTag>(ctx).get().push(']');})]
) >>
ruleArg >>
ruleBlockEnd[([](auto& ctx){
assert(!x3::get<SBlockEndTag>(ctx).get().empty());
x3::get<SBlockEndTag>(ctx).get().pop();
})];
BOOST_SPIRIT_DEFINE(ruleBlockEnd, ruleArg, ruleBlock3)
代码在科利鲁。
问题:这就是我们为此类问题编写递归 x3 解析器的方式吗?有了灵气的局部和传承属性,解决方案似乎简单多了。谢谢。
您可以使用x3::with<>
.
但是,我只想写这个:
auto const block_def =
'{' >> *( block | (char_ - '}')) >> '}'
| '[' >> *( block | (char_ - ']')) >> ']';
演示
住在科里鲁
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace Parser {
using namespace boost::spirit::x3;
rule<struct idBlock1> const block {"Block"};
auto const block_def =
'{' >> *( block | (char_ - '}')) >> '}'
| '[' >> *( block | (char_ - ']')) >> ']';
BOOST_SPIRIT_DEFINE(block)
}
int main() {
std::string const input = R"({
Some text.
[
{
Some more text.
}
Some Text again.
[]
]
})";
std::cout << "Parsed: " << std::boolalpha << parse(input.begin(), input.end(), Parser::block) << "n";
}
指纹:
Parsed: true
但是 - 代码重复!
如果你坚持概括:
auto dyna_block = [](auto open, auto close) {
return open >> *(block | (char_ - close)) >> close;
};
auto const block_def =
dyna_block('{', '}')
| dyna_block('[', ']');
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- valgrind-hellgrind与泄漏检查的结果不同
- 用C++20 fmt限制结果的总大小
- 如何返回一个类的两个对象相加的结果
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 序列化,没有库的整数,得到奇怪的结果
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 在更改for循环的第三部分后,未使用for循环结果
- 使用++运算符会导致意外的结果
- 为什么在逗号分隔符上下文中将预增量的结果强制转换为void
- C++Brute Force攻击函数不会返回结果
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 算术运算的结果类似于:C浮点变量中的1/3
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- Spirit X3:自定义数字解析器在结果中产生意外的前导零
- 递归 x3 解析器,结果传递
- 如何使用 spirit x3 将解析的结果移动到结构中
- 在提升精神 x3 解析结果中包含前导零