- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个用于解析标识符的解析器,如 foo, bar, baz
和一个用于解析嵌套标识符的解析器,如 foo::bar, foo::bar.baz, foo::bar.baz.baham
它们都解析为相同的 ast 结构,如下所示:
struct identifier : x3::position_tagged{
std::vector <std::string> namespaces;
std::vector <std::string> classes;
std::string identifier;
};
identifier
的解析器如下所示:
#define VEC_ATR x3::attr(std::vector<std::string>({})) //ugly hack
auto const identifier_def =
VEC_ATR
>> VEC_ATR
>> id_string;
对于 nested_identifier
是这样的:
auto const nested_identifier_def =
x3::lexeme[
(+(id_string >> "::") >> +(id_string >> ".") > id_string)
| (+(id_string >> "::") >> VEC_ATR > id_string)
| (VEC_ATR >> +(id_string >> ".") > id_string)
| identifier
];
我知道我为宏感到羞耻。标识符解析器工作正常,但是 nested_identifier
有一个奇怪的行为如果我尝试解析类似 foo::bar::baz
的东西,则从解析器中掉出的 ast 对象具有所有 namespace ,在本例中为 foo
和 bar
在 namespaces
vector 中两次。我有一个关于这种奇怪行为的小例子 here .任何人都可以向我解释为什么会发生这种情况,以及如何避免这种情况?
最佳答案
出现该行为的原因是替代解析器在其中一个分支失败时不会自动回滚对外部属性所做的更改。
在您的情况下会发生这种情况:
- Initially the attribute is
[{},{},""]
.- The first alternative branch is tried.
id_string >> "::"
matches twice and addsfoo
andbar
to the first vector ->[{foo,bar},{},""]
.id_string >> "."
fails to match -> the sequence fails -> the alternative branch fails (leaving the attribute unchanged).- The second alternative branch is tried.
id_string >> "::"
matches twice and addsfoo
andbar
to the first vector ->[{foo,bar,foo,bar},{},""]
.attr(vector<string>({}))
succeeds (attr
always succeeds) and substitutes the empty second vector with a vector with an empty string ->[{foo,bar,foo,bar},{""},""]
.id_string
matches andbaz
is added to the attribute ->[{foo,bar,foo,bar},{""},baz]
.- The second alternative branch succeeds.
在 Spirit.Qi 中,这种情况下的解决方案非常简单,只需使用 hold directive 即可。不幸的是,该指令尚未在 Spirit.X3 中实现。一种可能的替代方法是将每个替代分支明确地或与 x3::rule
一起放在它自己的 as<ast::identifier>(alternative_branch)
中,如 sehe 使用的 here。 Here 是显示 as
方法的简化示例。
另一种可能性是实现 hold
指令,这是我的尝试(running on WandBox):
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct hold_directive : unary_parser<Subject, hold_directive<Subject>>
{
typedef unary_parser<Subject, hold_directive<Subject> > base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
hold_directive(Subject const& subject)
: base_type(subject) {}
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
Attribute copy(attr);
if (this->subject.parse(first, last, context, rcontext, copy))
{
traits::move_to(copy, attr);
return true;
}
return false;
}
};
struct hold_gen
{
template <typename Subject>
hold_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
return { as_parser(subject) };
}
};
auto const hold = hold_gen{};
}}}
关于c++ - 升压.x3 : attribute accumulates between alternatives,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39537675/
我只是在阅读有关 HQ9+ 编程语言的一些内容: https://esolangs.org/wiki/HQ9+ , https://en.wikipedia.org/wiki/HQ9+ , 和 htt
首先,我是 Mongo DB 的新手。一直在遵循一些指南和示例,例如 https://www.programcreek.com/java-api-examples/index.php?api=com.
当我写作时 long long sum = accumulate(a.begin(), a.end(), 0); 或者 long long sum = accumulate(a.begin(), a.
当我写作时 long long sum = accumulate(a.begin(), a.end(), 0); 或者 long long sum = accumulate(a.begin(), a.
我有一个关于 accumulate() 和运算符重载的问题。 我有一个类 Order 包含 private: Customer cust; std::vector vP; 和一个类 Purchase
我在 C++ 中使用 opencv 库,我正在尝试计算 vector difference 中包含的点的总和 Point 类具有 x 属性,即 float . float pointSumX(Poin
我试图将以下循环转换为 accumulate() 调用,但我失败了: total = 0 for h in heat_values: total += h total -= total
如果我像下面这样在 C++ 中使用 accumulate 函数 std::vector v2{1, 2, 3, 4, 5}; int sum = 0; std::cout values{ 1,
有没有办法按名称获取已注册的 Spark 累加器,而无需传递实际引用?期望的行为: val cnt1 = sc.longAccumulator("cnt1") val cnt2 = something
std::accumulate 的 C++ 引用没有提到 std::accumulate 可能抛出的任何异常,仍然它的定义不包含 noexcept。假设一个人使用不抛出的类型和操作,在声明为 noex
尝试“滥用”std::accumulate 算法(为什么它出现在“数字” header 中?;)) template std::string strjoin(Range&& range, Sepera
这让我很困惑,如果有人能帮助我,我将不胜感激。 (编辑:以为这是一个模板化问题,我误会了) 我想使用 gnu 的并行累积算法(存储在 #include 中)添加以下类的多个拷贝 类故意不做太多,我觉
错误似乎与 std::accumulate() 或迭代器有关,或者我是否访问了无效指针? int m = 0; std::vector v{4,-3,0,-5}; for(std::vector::i
此代码是从另一个用户问题复制而来的,我很好奇这里的 accumulate 是如何工作的。我从这段代码中得到了正确的结果,但想知道 lcm 在“累积”时采用什么参数。初始化为 A,范围之和为 b?请帮忙
如何统计满足 lower_bound(42), upper_bound(137) 的元素数量从这段代码?? accumulate(values.lower_bound(42), values.uppe
我在测试代码中使用 std::accumulate 得到了意想不到的结果。我正在尝试添加一个大的 double vector ,但由于某种原因,该值溢出了: #include #include #
我试着编写一个基本的编译时版本的std::accumulate()通过定义一个类模板,该模板将递归迭代给定范围并在每次迭代时添加元素。 在 Ubuntu 14.04 上使用 gcc 4.8.4 编译测
我刚刚写了一个小的辅助函数作为 std::accumulate 的包装: template inline auto accumulate(FwdIter begin, FwdIter end) ->
需要以下示例的更漂亮的解决方案,但需要使用 std::accumulate。 #include #include #include class Object { public: Obje
是否可以指示 Redis 累积一组操作,然后发出“publish all”命令来发布整组操作(按线性顺序)? 所以你会以某种方式设置一个标记(startpublish ?)并且缓存会累积从中接收到的所
我是一名优秀的程序员,十分优秀!