一样,许多这些其他问题,我试图解析语法简单到用Boost.Spirit.Qi结构树。
我会尝试提炼我想要做的最简单的案例。我有:
struct Integer {
int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))
稍后,在语法结构中,我有以下成员变量:
qi::rule<Iterator, Integer> integer;
我用
定义integer = qi::int_;
但是,当我尝试使用
实际解析整数时qi::phrase_parse(iter, end, g, space, myInteger);
成功解析后, myInteger.value
始终未初始化。
同样,我尝试了以下定义(显然那些不编译的定义是错误的):
integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't
显然,我误解了关于精神,凤凰或其他的东西。据我所知,qi::_1
是第一属性qi::int_
,这里,并且应表示所解析的整数,当在方括号内的部分作为功能对象被执行。我假设函数对象将采用封闭的integer
属性qi::_val
并尝试将解析的整数分配给它。我的猜测是,由于我的BOOST_FUSION_ADAPT_STRUCT
通话,两人将是兼容的,那肯定似乎是从静态角度分析的情况,但数据没有被保存下来。
是否存在我在某处或某处遗漏的参考(&amp;)名称?
答案 0 :(得分:13)
如果Integer应该是规则公开的属性,则需要将其声明为:
qi::rule<Iterator, Integer()> integer;
(注意括号)。 Spirit需要使用函数声明语法来描述规则的“接口”。它不仅用在Spirit中,还用于其他几个库(例如参见boost :: function)。
这样做的主要原因是它是一种指定函数接口的简洁方法。如果你考虑一个规则是什么,你很快就会意识到它就像一个函数:它可以返回一个值(解析后的结果,即合成属性)。此外,它可能需要一个或多个参数(继承的属性)。
第二个但很小的原因是Spirit需要能够区分规则的不同模板参数。模板参数可以按任何顺序指定(迭代器除外),因此需要一些方法来确定是什么。函数声明语法与skipper或编码(另外两个可能的模板参数)完全不同,以允许在编译时识别它。
让我们来看看你的不同尝试:
如果您更改上面列出的规则定义,则可以使用此功能。
integer = qi::int_[qi::_val = qi::_1];
_val
指的是Integer
,而_1
指的是int
。因此,您需要从int
定义赋值运算符以使其工作:
struct Integer {
int value;
Integer& operator=(int) {...}
};
在这种情况下,您无需将类型调整为Fusion序列。
但你可以更容易地写它:
integer = qi::int_ >> qi::eps;
100%等效(eps是用于将右侧转换为解析器序列的技巧,允许利用内置属性传播将适应的Fusion序列的元素映射到元素的属性的序列)。
此:
integer = qi::int_[qi::_r1 = qi::_1];
不起作用,因为_r1
指的是规则的第一个继承属性。但是,您的规则没有任何属性。
这将有效:
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1];
但不要求将您的类型调整为Fusion序列。
这样:
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1];