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:
11 h e l l o _ w o r l d
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.
ch is parametizable.
Example: ch_p(ref(c)) range(from, to),
either or both from and to are parametizable.
Example: range_p(ref(n1), ref(n2)) strlit(str),
str is parametizable.
Example: str_p(ref(s)) a.repeat(n);
n is parametizable.
Example: a.repeat(ref(x)) a.repeat(n1, n2);
either or both n1 and n2 are parametizable.
Example: a.repeat(3, ref(x))
[ loop from 3 to x ]
n is parametizable.
Example: a.repeat(ref(x), more)
[ loop x or more ]