Boost.Spirit.Qi:获取规则的属性并将其设置为封闭规则的struct属性的字段?

时间:2011-01-06 21:23:26

标签: c++ boost-spirit boost-spirit-qi boost-phoenix

一样,许多这些其他问题,我试图解析语法简单到用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;)名称?

1 个答案:

答案 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];