Как семантические действия (с использованием _val и _attr) влияют на определение правил с помощью%= и x3::rule's force_attribute=true?

Данный семантический актер

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 к правде?
  2. Этот тип семантических действий по обработке значений должен работать исключительно на _val поэтому они работают на прикрепленном парсере вместо первого rule встречались в иерархии?

Я понимаю, что эти вопросы могут показаться несвязанными, но они действительно связаны, так как я пытаюсь обработать проанализированный номер (float) и преобразовать его в uint8 несколькими способами. Чтобы быть полностью законченным: у меня есть рабочий код (числовые данные здесь и фактические вещи, которые я создаю / анализирую здесь), но он кажется излишне сложным (из-за вышеизложенного кажется, что мне нужно правило для преобразования типа / значения, которое кажется глупо.

1 ответ

кажется, я поражаюсь тому факту, что наличие семантических действий препятствует синтезу атрибута (или распространению?)

Это так, поведение было скопировано из Ци (qi::rule документы, How Do Rules Propagate Their Attributes?).

Соответствующие части кода: вызов сайта, обработка.

%= так же, как установка третьего x3::rule параметр шаблона force_attribute к правде?

Да, это не задокументировано, см. Код 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 встречались в иерархии?

Документация по семантическим действиям описывает, что _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 черты. По умолчанию они будут ссылаться на одно и то же значение, пока у вас не будут вложенные правила с разными типами атрибутов ( соответствующий код).

PS Я не могу ничего сказать о причине, почему это так. Я вижу, что многие пользователи Spirit просто используют %= повсюду, потому что интуитивно это должно быть по умолчанию, и вы можете вручную отключить распространение с помощью omit директивы. Более того, у Qi есть некоторые ошибки из-за этого механизма, когда вы используете ленивые значения для чего-то вроде repeat директива ( билет 13313).

Другие вопросы по тегам