Boost.Spirit(X3,Boost 1.64):如何正确实施此递归规则
Boost.spirit (x3, boost 1.64): how to implement this recursive rule correctly, is it possible?
这个问题很容易提出。我有一个递归规则,我不知道该规则的综合属性类型,但我也有一些有关内部工作的问题。
在我看来,返回类型是variant<tuple<return_type_of_a, SEQ>, tuple<return_type_of_b, SEQ>>
,其中SEQ
是递归规则,a
和b
是终端:
rule<class myrule, ??> SEQ = a >> SEQ | b >> SEQ;
由于规则是递归的,因此不接受以下内容,我无法完全弄清返回类型:
rule<class myrule, decltype (a>> SEQ | b >> SEQ)> seq = a >> seq | b >> seq;
- 我必须知道递归规则的返回类型吗?
- 看起来必须有某种类型的嵌套,这是自然的递归,但是如果不扁平,则不可能在编译时计算返回类型。那么,如何在编译时计算递归规则的类型呢?有什么样的扁平?
- 上面规则的合成应该是什么?
- 将规则重构为: 是否有帮助
rule<class myrule, ??> SEQ = (a | b) >> SEQ;
感谢您的帮助。
-
关于
seq = a >> seq | b >> seq;
首先:您的语法是严格的循环,永远不会解析:它将无限地反复该规则,直到不匹配为止。我将假设您想要类似的东西:
expr = var | "!" >> expr;
(请注意,并非所有分支都无条件地反复出现)。
-
如何正确实施此递归规则,是否可能?
是。教程样本可能应该显示此。
样品
假设我们有一个非常非常简单的语法,例如
expr = var | '!' >> expr;
我们创建一个AST来反映这一点:
namespace Ast {
using var = std::string;
struct negated;
using expr = boost::variant<var, boost::recursive_wrapper<negated> >;
struct negated {
expr e;
};
}
规则
由于expr
规则将是递归的,因此我们必须在其定义之前声明它:
static x3::rule<struct expr_, Ast::expr> expr {"expr"};
让我们想象它已经定义了,我们将写下sub表达式:
auto var = x3::rule<struct var_, Ast::var> {"var"}
= x3::lexeme [ x3::alpha >> *x3::alnum ];
auto neg = x3::rule<struct var_, Ast::negated> {"neg"}
= "!" >> expr;
剩下的就是递归规则本身:BOOST_SPIRIT_DEFINE
auto expr_def = var | neg;
BOOST_SPIRIT_DEFINE(expr)
仅此而已。
演示时间
让我们添加一些测试用例:
活在coliru
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/struct.hpp>
namespace Ast {
using var = std::string;
struct negated;
using expr = boost::variant<var, boost::recursive_wrapper<negated> >;
struct negated {
expr e;
};
static inline std::ostream& operator <<(std::ostream& os, Ast::negated const& n) {
return os << "NOT(" << n.e << ")";
}
}
BOOST_FUSION_ADAPT_STRUCT(Ast::negated, e)
namespace Parsers {
namespace x3 = boost::spirit::x3;
namespace detail {
static x3::rule<struct expr_, Ast::expr> expr {"expr"};
auto var = x3::rule<struct var_, Ast::var> {"var"}
= x3::lexeme [ x3::alpha >> *x3::alnum ];
auto neg = x3::rule<struct var_, Ast::negated> {"neg"}
= "!" >> expr;
auto expr_def = var | neg;
BOOST_SPIRIT_DEFINE(expr)
}
auto demo = x3::skip(x3::space) [ detail::expr ];
}
#include <iostream>
int main() {
for (std::string const input : { "foo", "! bar", "!!!qux" }) {
auto f = input.begin(), l = input.end();
Ast::expr e;
if (parse(f, l, Parsers::demo, e)) {
std::cout << "Parsed: " << e << "n";
} else {
std::cout << "Parse failedn";
}
if (f != l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'n";
}
}
打印
Parsed: foo
Parsed: NOT(bar)
Parsed: NOT(NOT(NOT(qux)))
和(可选)(#define BOOST_SPIRIT_X3_DEBUG
)
活在coliru
<expr>
<try>foo</try>
<var>
<try>foo</try>
<success></success>
<attributes>[f, o, o]</attributes>
</var>
<success></success>
<attributes>[f, o, o]</attributes>
</expr>
Parsed: foo
<expr>
<try>! bar</try>
<var>
<try>! bar</try>
<fail/>
</var>
<neg>
<try>! bar</try>
<expr>
<try> bar</try>
<var>
<try> bar</try>
<success></success>
<attributes>[b, a, r]</attributes>
</var>
<success></success>
<attributes>[b, a, r]</attributes>
</expr>
<success></success>
<attributes>[[b, a, r]]</attributes>
</neg>
<success></success>
<attributes>[[b, a, r]]</attributes>
</expr>
Parsed: NOT(bar)
<expr>
<try>!!!qux</try>
<var>
<try>!!!qux</try>
<fail/>
</var>
<neg>
<try>!!!qux</try>
<expr>
<try>!!qux</try>
<var>
<try>!!qux</try>
<fail/>
</var>
<neg>
<try>!!qux</try>
<expr>
<try>!qux</try>
<var>
<try>!qux</try>
<fail/>
</var>
<neg>
<try>!qux</try>
<expr>
<try>qux</try>
<var>
<try>qux</try>
<success></success>
<attributes>[q, u, x]</attributes>
</var>
<success></success>
<attributes>[q, u, x]</attributes>
</expr>
<success></success>
<attributes>[[q, u, x]]</attributes>
</neg>
<success></success>
<attributes>[[q, u, x]]</attributes>
</expr>
<success></success>
<attributes>[[[q, u, x]]]</attributes>
</neg>
<success></success>
<attributes>[[[q, u, x]]]</attributes>
</expr>
<success></success>
<attributes>[[[[q, u, x]]]]</attributes>
</neg>
<success></success>
<attributes>[[[[q, u, x]]]]</attributes>
</expr>
Parsed: NOT(NOT(NOT(qux)))
相关文章:
- 如何正确取消析构函数中的 Boost deadline_timer(在多线程环境中)?
- 为什么要 boost::p roperty_tree::write_json() 将整数值转换为字符串?这是不正确的
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 如何正确地将boost::asio::buffers_iterator转换为InputIterator
- 如何正确地将 boost::optional<std::chrono::d uration> 作为函数参数?
- Boost::Asio串行读/写打开:参数不正确
- 如何避免 boost 的野兽body_limit错误并正确处理大消息
- 有没有办法修复因未正确关闭 boost::archive::binary_oarchive 而损坏的文件?
- 如何通过std ::变体正确替换boost ::变体
- 如何使用 Boost.Asio 正确实现异步/等待语法
- 使用 CLion 在不同文件中分离 Boost 测试套件的正确方法
- Boost Read_graphml 无法正确读取 xml,它给出了所有顶点,但它们是空的
- 如何正确绑定成员函数与 boost::bind
- 2D 矢量未正确保存并加载 boost::序列化库
- 如何正确访问结构值并将其传递给函数 - boost::p ython
- 声明“const”“boost::range”的正确方法
- CMAKE带有Boost Library Windows 10库未正确找到
- 如何在多线程程序中使用 boost::asio 正确处理 fork()
- 当使用信号处理程序触发事件时,如何使boost.msm正确更改状态
- 如何解析胡子与Boost.Xpressive正确