I am looking into Boost Spirit X3, but am struggling to fully grasp the difference between x3::_val and x3::_attr as used in semantic actions to extract attributes from the passed context. The official docs state
_val: A reference to the attribute of the innermost rule that directly or indirectly invokes the parser p
_attr: A reference to the attribute of the parser p
which doesn't really help me. I researched some and stumbled upon https://stackoverflow.com/a/61703199/3907364, which states
x3::_val(ctx) is like qi::_val
x3::_attr(ctx) is like qi::_0 (or qi::_1 for simple parsers)
but unfortunately, I was unsuccessful at figuring out what qi::_val and qi::_0/qi::_1 are - or more precisely what their difference is.
Finally, I also found https://stackoverflow.com/a/53971888/3907364, where it is stated that
What they [
x3::_valandx3::_attr] will be in a particular situation depends on make_attribute/transform_attribute traits. By default they will reference to the same value until you have nested rules with different attribute types
which seems to conform with experiments that I have conducted thus far - except I have not yet managed for _attr and _val to yield different values.
Even though I was unable to understand their difference yet, it seems rather relevant as all examples that I have seen, that use semantic actions to e.g. compute the result of a given calculation (see e.g. here) always seem to use _attr as a more global state, whereas _val seems to be the immediate state of the thing that has just been parsed. E.g.
[](auto& ctx) { _val(ctx) = _val(ctx) * _attr(ctx); }
Yet with all of this, I am still not quite able to point my finger to the exact difference in semantics between the two properties. Could someone perhaps try to rephrase Boost's docs and give an example of where the difference is actually important/visible?
Since this didn't help you, let's illustrate.
I like to call
_attrthe (accessor for) the synthesized attribute:On the other hand, there is the attribute bound to the rule when invoking a parser, the
_val(ctx). This depends on what context you use it in.Here's a demonstration program illustrating the differences:
Live On Coliru
Printing:
Note that the action is completely redundant here, just used to add output:
Live On Coliru
Still printing