What makes Spirit tick? Now on to some details... The parser class is the most
fundamental entity in the framework. A parser accepts a scanner comprised of
a first-last iterator pair and returns a match object as its result. The iterators
delimit the data currently being parsed. The match object evaluates to true
if the parse succeeds, in which case the input is advanced accordingly. Each
parser can represent a specific pattern or algorithm, or it can be a more complex
parser formed as a composition of other parsers.

This class is a protocol base class for all parsers. The parser class does
not really know how to parse anything but instead relies on the template parameter
DerivedT to do the actual parsing. This technique is known as the "Curiously
Recurring Template Pattern" in template meta-programming circles. This
inheritance strategy gives us the power of polymorphism without the virtual
function overhead. In essence this is a way to implement compile
time polymorphism.

parser_category_t

Each derived parser has a typedef parser_category_t that defines
its category. By default, if one is not specified, it will inherit from the
base parser class which typedefs its parser_category_t as plain_parser_category.
Some template classes are provided to distinguish different types of parsers.
The following categories are the most generic. More specific types may inherit
from these.

embed_t

Each parser has a typedef embed_t. This typedef specifies how a parser
is embedded in a composite. By default, if one is not specified, the parser
will be embedded by value. That is, a copy of the parser is placed as a member
variable of the composite. Most parsers are embedded by value. In certain situations
however, this is not desirable or possible. One particular example is the rule.
The rule, unlike other parsers is embedded by reference.

The match

The match holds the result of a parser. A match object evaluates to true when
a succesful match is found, otherwise false. The length of the match is the
number of characters (or tokens) that is successfully matched. This can be queried
through its length() member function. A negative value means that the
match is unsucessful.

Each parser may have an associated attribute. This attribute is also returned
back to the client on a successful parse through the match object. We can get
this attribute via the match's value() member function. Be warned though
that the match's attribute may be invalid, in which case, getting the attribute
will result in an exception. The member function has_valid_attribute()
can be queried to know if it is safe to get the match's attribute. The attribute
may be set anytime through the member function value(v)where v
is the new attribute value.

A match attribute is valid:

on a successful match

when its value is set through the value(val) member function

if it is assigned or copied from a compatible match object (e.g. match<double>
from match<int>) with a valid attribute. A match object A
is compatible with another match object B if the attribute type of
A can be assigned from the attribute type of B
(i.e. a = b; must compile).

The match attribute is undefined:

on an unsuccessful match

when an attempt to copy or assign from another match object with an incompatible
attribute type (e.g. match<std::string> from match<int>).

match_result

It has been mentioned repeatedly that the parser returns a match object as
its result. This is a simplification. Actually, for the sake of genericity,
parsers are really not hard-coded to return a match object. More accurately,
a parser returns an object that adheres to a conceptual interface, of which
the match is an example. Nevertheless, we shall call the result type of a parser
a match object regardless if it is actually a match class, a derivative or a
totally unrelated type.

Meta-functions

What are meta-functions? We all know how functions look like. In simplest
terms, a function accepts some arguments and returns a result. Here is the
function we all love so much:

int identity_func(int
arg){return arg;
}// return the argument arg

Meta-functions are essentially the same. These beasts also accept arguments
and return a result. However, while functions work at runtime on values,
meta-functions work at compile time on types (or constants, but we shall
deal only with types). The meta-function is a template class (or struct).
The template parameters are the arguments to the meta-function and a typedef
within the class is the meta-function's return type. Here is the corresponding
meta-function:

By convention, meta-functions return the result through the typedef type.
Take note that typename is only required within templates.

The actual match type used by the parser depends on two types: the parser's
attribute type and the scanner type. match_result is the meta-function
that returns the desired match type given an attribute type and a scanner type.

Usage:

typename match_result<ScannerT, T>::type

The meta-function basically answers the question "given a scanner type
ScannerT and an attribute type T, what is the desired match
type?" [typename
is only required within templates ].

The parse member function

Concrete sub-classes inheriting from parser must have a corresponding member
function parse(...) compatible with the conceptual Interface:

template <typename ScannerT>
RT
parse(ScannerT const& scan) const;

where RT is the desired return type of the parser.

The parser result

Concrete sub-classes inheriting from parser in most cases need to have a nested
meta-function result that returns the result type of the parser's
parse member function, given a scanner type. The meta-function has the form:

template <typename ScannerT>
struct result
{
typedef RT type;
};

where RT is the desired return type of the parser. This is usually,
but not always, dependent on the template parameter ScannerT. For example,
given an attribute type int, we can use the match_result metafunction: