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

jto*_*lds 7 c++ boost-spirit boost-phoenix boost-spirit-qi

就像其他许多问题一样,我正在尝试使用Boost.Spirit.Qi将简单语法解析为结构树.

我会尝试提炼我想要做的最简单的案例.我有:

struct Integer {
  int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))
Run Code Online (Sandbox Code Playgroud)

后来,在语法结构中,我有以下成员变量:

qi::rule<Iterator, Integer> integer;
Run Code Online (Sandbox Code Playgroud)

这是我定义的

integer = qi::int_;
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试实际解析整数时,使用

qi::phrase_parse(iter, end, g, space, myInteger);
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

显然,我误解了一些关于精神,凤凰或其他东西的东西.我的理解是,当方括号中的部分作为函数对象执行时,这里qi::_1的第一个属性qi::int_应该表示已解析的整数.我假设函数对象将采用封闭integer属性qi::_val并尝试将解析后的整数分配给它.我的猜测是因为我的BOOST_FUSION_ADAPT_STRUCT调用,两者兼容,从静态分析的角度来看,情况似乎确实如此,但数据并未得到保留.

是否有参考(&)指定我在某处或某处遗漏?

hka*_*ser 13

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

qi::rule<Iterator, Integer()> integer; 
Run Code Online (Sandbox Code Playgroud)

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

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

第二个但很小的原因是Spirit需要能够区分规则的不同模板参数.模板参数可以按任何顺序指定(迭代器除外),因此需要一些方法来确定是什么.函数声明语法与skipper或编码(另外两个可能的模板参数)完全不同,以允许在编译时识别它.

让我们来看看你的不同尝试:

如果您更改上面概述的规则定义,则可以使用此功能.

integer = qi::int_[qi::_val = qi::_1]; 
Run Code Online (Sandbox Code Playgroud)

_val指的是你Integer,而_1int.因此,您需要定义赋值运算符int以使其工作:

struct Integer {
    int value;
    Integer& operator=(int) {...}
};                    
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您无需将类型调整为Fusion序列.

但你可以更容易地写它:

integer = qi::int_ >> qi::eps;
Run Code Online (Sandbox Code Playgroud)

100%等效(eps是用于将右侧转换为解析器序列的技巧,允许利用内置属性传播将适应的Fusion序列的元素映射到序列元素的属性).

这个:

integer = qi::int_[qi::_r1 = qi::_1]; 
Run Code Online (Sandbox Code Playgroud)

将无法作为_r1规则的第一个继承属性的引用.但是,您的规则没有任何属性.

这将有效:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1];
Run Code Online (Sandbox Code Playgroud)

但不要求将您的类型调整为Fusion序列.

这样:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
Run Code Online (Sandbox Code Playgroud)

  • `git commit -a -m'Hartmut Kaiser是男人!'` (2认同)