8

就像许多其他问题一样,我正在尝试使用 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

很明显,我对 Spirit、Phoenix 或其他东西有误解。我的理解是,当方括号中的部分作为函数对象执行时,这qi::_1是 , 的第一个属性,应该表示解析的整数。qi::int_然后我假设函数对象将采用封闭integer属性qi::_val并尝试将解析的整数分配给它。我的猜测是,由于我的BOOST_FUSION_ADAPT_STRUCT调用,两者将是兼容的,从静态分析的角度来看,这肯定是这种情况,但数据并没有被保留。

我在某处或某处缺少参考(&)名称吗?

4

1 回答 1

15

如果 Integer 应该是规则公开的属性,则需要将其声明为:

qi::rule<Iterator, Integer()> integer; 

(注意括号)。Spirit 要求使用函数声明语法来描述规则的“接口”。它不仅在 Spirit 中使用,还被其他几个库使用(例如,参见 boost::function)。

这样做的主要原因是它是指定函数接口的一种简洁的方式。如果你想想规则是什么,你很快就会意识到它就像一个函数:它可能会返回一个值(解析后的结果,即综合属性)。此外,它可能需要一个或多个参数(继承的属性)。

第二个但次要的原因是 Spirit 需要能够区分规则的不同模板参数。模板参数可以按任何顺序指定(迭代器除外),因此它需要一些方法来确定什么是什么。函数声明语法与跳过程序或编码(其他两个可能的模板参数)有很大不同,可以在编译时识别它。

让我们看看您的不同尝试:

如果您如上所述更改规则定义,则可以使用此功能。

integer = qi::int_[qi::_val = qi::_1]; 

the_val指的是你的Integer,而 the_1指的是一个int。因此,您需要定义一个赋值运算符 fromint以使其工作:

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]; 
于 2011-01-06T22:15:57.780 回答