在 Spirit X3 中使用布尔属性而不是可选属性
using a boolean attribute instead optional in spirit x3
在我想要实现的语法中,有一些枚举很重要的关键字(将具体关键字的枚举 id 存储在 ast 的节点内),甚至只存在相同的特定关键字 - 因此在布尔上下文中是可选的。我喜欢有一个自我表达的解析器表达式和ast节点,所以我提出了以下(可编译的)解决方案:
#include <iostream>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace x3 = boost::spirit::x3;
namespace ast {
enum class keyword_token {
UNSPECIFIED, FOO, BAR
};
struct buz {
bool foo;
int dummy;
};
}
BOOST_FUSION_ADAPT_STRUCT( ast::buz, foo, dummy )
namespace boost { namespace spirit { namespace x3 { namespace traits {
template <>
inline void
move_to(ast::keyword_token&& src, bool& dest) {
dest = static_cast<bool>(src);
}
} } } } // boost.spirit.x3.traits
namespace parser {
auto const FOO = x3::rule<struct _, ast::keyword_token> { "FOO" } =
x3::lexeme[ x3::no_case[ "foo" ] >> !(x3::alnum | '_') ]
>> x3::attr(ast::keyword_token::FOO);
auto const buz = x3::rule<struct _, ast::buz> { "buz" } =
-FOO >> x3::int_;
}
int main() {
for(std::string const str: {
"FOO 42",
"42"
}) {
auto iter = str.begin(), end = str.end();
ast::buz attr;
bool r = x3::phrase_parse(iter, end, parser::buz, x3::space, attr);
std::cout << "parse '" << str << "': ";
if (r && iter == end) {
std::cout << "succeeded:n";
std::cout << (attr.foo ? "FOO " : "") << attr.dummy << "n";
std::cout << "n";
} else {
std::cout << "*** failed ***n";
}
}
return 0;
}
在这里,ast的buz节点有一个布尔属性,解析器有一个"可选"语法。背后的想法是 bool 是默认可构造的,并且标准保证由 0 又名 false 初始化,这是预期的。此外,我有一个keyword::UNSPECIFIED
的后备解决方案(应该,因为我不是 100% 确定枚举类)等于 0 - imo 不应该永远不会被触发 - 在最坏的情况下,x3 的move_to(...)
特征也评估为 false。
运行此程序,解析阶段按预期对两个测试用例成功,但第二个测试用例的属性不是预期的;显然,"布尔值作为可选"方法无法按预期工作:
<buz>
<try>FOO 42</try>
<FOO>
<try>FOO 42</try>
<success> 42</success>
<attributes>1</attributes>
</FOO>
<success></success>
<attributes>[1, 42]</attributes>
</buz>
parse 'FOO 42': succeeded:
FOO 42
<buz>
<try>42</try>
<FOO>
<try>42</try>
<fail/>
</FOO>
<success></success>
<attributes>[1, 42]</attributes>
</buz>
parse '42': succeeded:
FOO 42
调试模式显示合成的属性[1, 42]
。那么,我的考虑是否合理,它可以工作,如果是,如何修复它以按预期工作? 可能还有另一个问题:如果没有定义BOOST_SPIRIT_X3_DEBUG
,我会收到警告:
warning: 'attr' may be used uninitialized in this function
...
warning: 'attr.ast::buz::dummy' may be used uninitialized in this function
在库特线。可能我不理解警告是否正确,因为 ast::buz 是默认的,我不想将值作为默认值(false,0)。
蛮力解决方案是编写类似以下内容的内容:
auto bool_attr = [](auto p) {
return x3::omit[ p ] >> x3::attr(true) | x3::attr(false);
};
并在规则中使用它,但我更喜欢"可选"语法而不是编写bool_attr(FOO) >> x3::int_
等。
来源也在科利鲁。
llonesmiz 明白了 POD 类对象初始化是否需要构造函数吗?我必须显式编写 ast 节点的构造函数:
struct buz {
bool foo;
int dummy;
buz() : foo{}, dummy{}
{ }
};
比属性符合预期:
parse 'FOO 42': succeeded:
FOO 42
parse '42': succeeded:
42
有了这个,上面提到的没有定义BOOST_SPIRIT_X3_DEBUG
的警告也消失了,警告对我来说更有意义......
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 一个关于在C++中重载布尔运算符的问题
- 提升精神:解析布尔表达式并简化为规范范式
- C++概念:如何使用'concept'检查模板化结构的属性?
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 通过指向指针数组的指针访问子类的属性
- MSVC是否支持C++11样式的属性而不是__declspec
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 线程之间的布尔停止信号
- 布尔比较运算符是如何在C++中工作的
- 变量定义到C++布尔值转换
- QML:修改在不同QML文件(而非main.QML)中定义的子对象的属性
- 类的C++属性似乎已重新初始化
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 隐式常量/非常量运算符布尔
- 在 Spirit X3 中使用布尔属性而不是可选属性
- 使用 QAbstractListModel 分配 QML 布尔属性失败
- 使用Boost ::几何多边形布尔/与线段属性的交叉点
- 从 Arduino 库中的方法获取私有布尔属性
- QML 引擎不隐式将布尔字符串 QVarient 转换为布尔属性