语义动作(使用_val和_attr)如何影响%=和x3 :: rule的force_attribute = true的规则定义?

时间:2018-12-29 12:18:55

标签: c++ parsing c++17 boost-spirit-x3

赋予语义参与者

template<typename ValueType>
class divide
{
public:
  divide(ValueType value) : divisor{value} {}

  template<typename ContextType>
  void operator()(ContextType& context) const
  {
    _val(context) /= divisor;
  }
private:
  const ValueType divisor;
};

似乎我遇到了一个事实,即语义动作的存在会抑制属性合成(或传播?),即

const auto norm = x3::rule<struct _, double>{"norm"}
                = x3::double_[normalize{100.}];

给我值0。

所以我尝试使用%=

来强制传播属性
const auto norm_rule = x3::rule<struct _, double>{"norm"}
                    %= x3::double_[normalize{100.}];

这给了我期望的解析值除以100。

然后我发现x3::rule有第三个模板参数bool force_attribute,并注意到了

const auto norm_rule = x3::rule<struct _, double, true>{"norm"}
                     = x3::double_[divide{100.}];

具有值的期望结果除以100。

进一步进行实验,我还发现我可以改为定义divide::operator()如下:

void operator()(ContextType& context)
{
  _attr(context) = _val(context) / divisor;
}

最后一个似乎强烈地将语义参与者与规则的顶层耦合/谴责,因为它作用于第一个规则的属性_attr而不是解析器的值_val它已附上。

我在推论中纠正了吗

  1. %=与将第三个x3::rule模板参数force_attribute设置为true相同吗?
  2. 这种类型的值处理语义动作应专门在_val上起作用,以便它们在附加的解析器上起作用,而不是在层次结构中遇到的第一个rule上起作用?

我了解这些问题似乎无关紧要,但是当我尝试处理已解析的数字(浮点数)并将其转换为uint8时,它们确实是相关的。要完全完整:我有工作代码(数字内容here和我正在构造/解析的实际内容here),但是它似乎不必要地复杂(由于上述原因,我似乎需要一个规则每个类型/值的转换,这似乎很愚蠢。

1 个答案:

答案 0 :(得分:1)

  

似乎我在想一个事实,即语义动作的存在会抑制属性合成(或传播?)

是这样,该行为是从Qi(qi::rule docsHow Do Rules Propagate Their Attributes?)复制而来的。

相关代码部分:call sitehandling

  

%=是否与将第三个x3::rule模板参数force_attribute设置为true相同?

是的,没有记录,请参见代码boost/spirit/home/x3/nonterminal/rule.hpp

  

进一步实验,我还发现我可以定义   divide::operator()如下:

void operator()(ContextType& context)
{
  _attr(context) = _val(context) / divisor;
}
     

这最后一个似乎将语义参与者强烈地耦合/谴责了一个   规则的顶层,因为它作用于第一条规则的属性_attr   而不是附加解析器的值_val

您几乎完全正确,但是交换了一下。应该是_val(context) = _attr(context) / divisor,详细信息如下。

  

这种类型的值处理语义动作应专门在_val上起作用,以便它们在附加的解析器上起作用,而不是在层次结构中遇到的第一个rule上起作用?

semantic actions documentation描述_val_attr是什么:

Function  Description                                         Example
--------  --------------------------------------------------  -----------------------
_val      A reference to the attribute of the innermost rule  _val(ctx) = "Gotya!"
          that directly or indirectly invokes the parser p    
_attr     A reference to the attribute of the parser p        _val(ctx) += _attr(ctx)

它们在特定情况下的状态取决于make_attribute / transform_attribute特质。默认情况下,它们将引用相同的值,直到您具有具有不同属性类型(relevant code)的嵌套规则为止。

P.S。我不能说任何原因。我看到许多Spirit用户只是在整个地方都使用%=,因为从直观上讲它应该是默认设置,并且您可以使用omit指令手动禁用传播。此外,当您在repeat指令(ticket 13313)之类的值上使用惰性值时,Qi会由于此机制而存在一些错误。