Home | Libraries | People | FAQ | More |
While parsing input, it is often desirable to combine some constant elements
with variable parts. For instance, let us look at the example of parsing
or formatting a complex number, which is written as (real, imag)
,
where real
and imag
are the variables representing the
real and imaginary parts of our complex number. This can be achieved by writing:
'(' >> double_ >> ", " >> double_ >> ')'
Literals (such as '('
and ", "
) do not
expose any attribute (well actually, they do expose the special type unused_type
, but in this context unused_type
is interpreted as if the component
does not expose any attribute at all). It is very important to understand
that the literals don't consume any of the elements of a fusion sequence
passed to this component sequence. As said, they just don't expose any attribute
and don't produce (consume) any data. The following example shows this:
// the following parses "(1.0, 2.0)" into a pair of double std::string input("(1.0, 2.0)"); std::string::iterator strbegin = input.begin(); std::pair<double, double> p; x3::parse(strbegin, input.end(), '(' >> x3::double_ >> ", " >> x3::double_ >> ')', // parser grammar p); // attribute to fill while parsing
where the first element of the pair passed in as the data to generate is
still associated with the first double_
,
and the second element is associated with the second double_
parser.
This behavior should be familiar as it conforms to the way other input and
output formatting libraries such as scanf
,
printf
or boost::format
are handling their variable parts. In this context you can think about spirit_x3's
primitive components (such as the double_
above) as of being type safe placeholders for the attribute values.
Tip | |
---|---|
Similarly to the tip provided above, this example could be rewritten using Spirit's multi-attribute API function: double d1 = 0.0, d2 = 0.0; x3::parse(begin, end, '(' >> x3::double_ >> ", " >> x3::double_ >> ')', d1, d2);
which provides a clear and comfortable syntax, more similar to the placeholder
based syntax as exposed by |
Let's take a look at this from a more formal perspective:
a: A, b: Unused --> (a >> b): A
which reads as:
Given
a
andb
are parsers, andA
is the attribute type ofa
, andunused_type
is the attribute type ofb
, then the attribute type ofa >> b
(a << b
) will beA
as well. This rule applies regardless of the position the element exposing theunused_type
is at.
This rule is the key to the understanding of the attribute handling in sequences
as soon as literals are involved. It is as if elements with unused_type
attributes 'disappeared' during
attribute propagation. Notably, this is not only true for sequences but for
any compound components. For instance, for alternative components the corresponding
rule is:
a: A, b: Unused --> (a | b): A
again, allowing to simplify the overall attribute type of an expression.