C++ Boost.x3:属性在备选方案之间累积
我有一个解析器用于解析标识符,比如C++ Boost.x3:属性在备选方案之间累积,c++,parsing,boost-spirit,boost-spirit-x3,C++,Parsing,Boost Spirit,Boost Spirit X3,我有一个解析器用于解析标识符,比如foo,bar,baz,还有一个解析器用于解析嵌套标识符,比如foo::bar,foo::bar.baz,foo::bar.baz 它们都解析到相同的ast结构中,如下所示: struct identifier : x3::position_tagged{ std::vector <std::string> namespaces; std::vector <std::string> classes; std::st
foo,bar,baz
,还有一个解析器用于解析嵌套标识符,比如foo::bar,foo::bar.baz,foo::bar.baz
它们都解析到相同的ast结构中,如下所示:
struct identifier : x3::position_tagged{
std::vector <std::string> namespaces;
std::vector <std::string> classes;
std::string identifier;
};
#define VEC_ATR x3::attr(std::vector<std::string>({})) //ugly hack
auto const identifier_def =
VEC_ATR
>> VEC_ATR
>> id_string;
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
];
对于嵌套的\u标识符
,如下所示:
struct identifier : x3::position_tagged{
std::vector <std::string> namespaces;
std::vector <std::string> classes;
std::string identifier;
};
#define VEC_ATR x3::attr(std::vector<std::string>({})) //ugly hack
auto const identifier_def =
VEC_ATR
>> VEC_ATR
>> id_string;
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
];
我知道我为宏感到羞耻。
标识符解析器工作正常,但是
嵌套的_标识符
有一种奇怪的行为
如果我尝试解析像foo::bar::baz
这样的东西,那么从解析器中掉出来的ast对象拥有所有的名称空间,在本例中foo
和bar
两次位于名称空间
向量中。
我有一个这种奇怪行为的小例子
.
有人能解释一下为什么会发生这种情况,以及我如何避免这种情况吗?产生这种行为的原因是,当外部属性的一个分支出现故障时,替代解析器不会自动回滚对外部属性所做的更改 在您的情况下,会发生以下情况:
- 最初属性是
李>[{},{},“]
- 尝试第一个备选分支李>
匹配两次并将id\u string>>::“
和foo
添加到第一个向量->bar
李>[{foo,bar},{},”]
匹配失败->序列失败->替代分支失败(保持属性不变)李>id\u string>>“
- 尝试第二个备选分支李>
匹配两次并将id\u string>>::“
和foo
添加到第一个向量->bar
李>[{foo,bar,foo,bar},{},”]
成功(attr(vector({}))
始终成功),并用空字符串替换空的第二个向量->attr
李>[{foo,bar,foo,bar},{”“},“]
匹配并将id\u字符串
添加到属性->baz
李>[{foo,bar,foo,bar},{'},baz]
- 第二个备选分支成功
x3::rule
放入自己的。是一个简化的示例,它将显示为方法
另一种可能是执行hold
指令,下面是我的尝试()
#包括
#包括
#包括
名称空间提升{名称空间精神{名称空间x3
{
模板
结构hold_指令:一元语法分析器
{
typedef一元语法分析器基本类型;
静态布尔常数为通过一元数=真;
静态bool const handles\u container=Subject::handles\u container;
hold_指令(主体常量和主体)
:基本类型(主题){}
模板
布尔解析(迭代器&第一,迭代器常量&最后
,上下文常量和上下文,RContext和RContext,属性和属性)常量
{
属性复制(attr);
if(this->subject.parse(first、last、context、rcontext、copy))
{
特征::移动到(复制,属性);
返回true;
}
返回false;
}
};
结构保持根
{
模板
hold_指令
操作员[](主体常量和主体)常量
{
返回{as_解析器(subject)};
}
};
auto const hold=hold_gen{};
}}}
请注意,从Boost1.70开始,@sehe提出的解决方案不再有效(请参阅)
现在唯一的解决办法是重构语法,这样就不需要回滚了。区分类和名称空间有什么用处?例如,C++中,类是命名空间。你说得对,我希望AST拥有尽可能多的信息。这就是为什么我将后跟一个点的id解析为类向量。也许classes不是最好的名字,但我找不到另一个Quick,我以前从未像使用过这个。它是如何工作的?非常感谢你的帮助,我没想到会有这样的行为。我想这与解释的地方有关:)哦,很抱歉,我是这么做的fast@Exagon这是一个简化的例子,显示了作为的方法。@sehe和jv_ui如果没有你们两个会被搞砸的,谢谢你们一直以来对我的精神帮助