gpt4 book ai didi

c++ - 升压.x3 : attribute accumulates between alternatives

转载 作者:太空狗 更新时间:2023-10-29 20:22:06 27 4
gpt4 key购买 nike

我有一个用于解析标识符的解析器,如 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 ,在本例中为 foobarnamespaces vector 中两次。我有一个关于这种奇怪行为的小例子 here .任何人都可以向我解释为什么会发生这种情况,以及如何避免这种情况?

最佳答案

出现该行为的原因是替代解析器在其中一个分支失败时不会自动回滚对外部属性所做的更改。

在您的情况下会发生这种情况:

  • Initially the attribute is [{},{},""].
  • The first alternative branch is tried.
  • id_string >> "::" matches twice and adds foo and bar 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 adds foo and bar 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 and baz 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 使用的 hereHere 是显示 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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com