Han*_*Han 2 c++ recursion boost boost-spirit boost-spirit-x3
(1)假设我们要解析一个简单的递归块{}.
{
Some text.
{
{
Some more text.
}
Some Text again.
{}
}
}
Run Code Online (Sandbox Code Playgroud)
这个递归解析器非常简单.
x3::rule<struct idBlock1> const ruleBlock1{"Block1"};
auto const ruleBlock1_def =
x3::lit('{') >>
*(
ruleBlock1 |
(x3::char_ - x3::lit('}'))
) >>
x3::lit('}');
BOOST_SPIRIT_DEFINE(ruleBlock1)
Run Code Online (Sandbox Code Playgroud)
(2)然后块变得更复杂.它也可能被包围[].
{
Some text.
[
{
Some more text.
}
Some Text again.
[]
]
}
Run Code Online (Sandbox Code Playgroud)
我们需要在某处存放我们拥有的开放式支架.由于x3没有本地,我们可能会使用attribute(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)
Run Code Online (Sandbox Code Playgroud)
(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)
Run Code Online (Sandbox Code Playgroud)
代码在Coliru上.
问题:这是我们为这类问题编写递归x3解析器的方法吗?凭借Qi的本地人和继承的属性,解决方案似乎更简单.谢谢.
你可以用x3::with<>.
但是,我只想写一下:
auto const block_def =
'{' >> *( block | (char_ - '}')) >> '}'
| '[' >> *( block | (char_ - ']')) >> ']';
Run Code Online (Sandbox Code Playgroud)
#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";
}
Run Code Online (Sandbox Code Playgroud)
打印:
Parsed: true
Run Code Online (Sandbox Code Playgroud)
如果你坚持概括:
auto dyna_block = [](auto open, auto close) {
return open >> *(block | (char_ - close)) >> close;
};
auto const block_def =
dyna_block('{', '}')
| dyna_block('[', ']');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
163 次 |
| 最近记录: |