We already have a hint of the dynamic nature of the Spirit framework. This
capability is fundamental to the underlying goals of Spirit. Dynamism as applied
to parsing is a very powerful concept. We shall take this concept further
through run-time parametric parsers. We are able to handle parsing tasks that
are impossible to do with any EBNF syntax alone. Consider the parsing of a
binary file of Pascal style length prefixed strings where the first byte determines
the length of the incoming string. Here's a sample input:
This trivial example cannot be practically defined in EBNF. Granted that
an EBNF syntax allows a more powerful repetition construct than the Kleene
star, we are limited to parsing fixed strings. The nature of EBNF forces the
repetition factor to be a constant. On the contrary, Spirit allows the repetition
factor to be variable at run time. We could write a grammar that accepts the
input string above. Consider this Spirit code fragment:
char c;
r = anychar[ref(c)] >> anychar.repeat(ref(c));
We have seen that we can extract the parsed result into a variable (see reference
wrappers). The expression:
anychar[ref(c)]
extracts the first character from the input and puts that in the variable
c. What's interesting is that in as much as we can use constants as
parameters to the parser::repeat member function, we can also use variables
wrapped inside reference wrappers. We
can see that in action in the expression:
anychar.repeat(ref(c))
This usage of the parser::repeat member function makes the loop parser defer
the evaluation of the repetition factor only until it is actually needed.
Continuing our example, since the value 11 is already extracted from the input,
parser::repeat is now expected to loop exactly 11 times.
The following table enumerates the parsers that can be run-time parameterized.
Parametric Parsers |
chlit(ch),
ch_p(ch)
|
ch is parametizable.
|
Example: ch_p(ref(c)) |
range(from, to),
range_p(from, to) |
either or both from and to
are parametizable.
|
Example: range_p(ref(n1), ref(n2)) |
strlit(str),
str_p(str) |
str is parametizable.
|
Example: str_p(ref(s)) |
a.repeat(n);
a(n); |
n is parametizable.
|
Example: a.repeat(ref(x)) |
a.repeat(n1, n2);
a(n, to); |
either or both n1 and n2
are parametizable.
|
Example: a.repeat(3, ref(x))
[ loop from 3 to x ] |
a.repeat(n, more);
a(n, more); |
n is parametizable.
|
Example: a.repeat(ref(x), more)
[ loop x or more ] |
|
|
|