| Home | Libraries | People | FAQ | More

#### Generator Basics

###### Lazy Argument

Some generators (e.g. primitives and non-terminals) may take in additional attributes. Such generators take the form:

    g(a1, a2,..., aN)

where `g` is a generator. Each of the arguments (a1 ... aN) can either be an immediate value, or a function, `f`, with signature:

    T f(Unused, Context)

where `T`, the function's return value, is compatible with the argument type expected and `Context` is the generator's Context type (The first argument is `unused` to make the `Context` the second argument. This is done for uniformity with Semantic Actions).

###### Character Encoding Namespace

Some generators need to know which character set a `char` or `wchar_t` is operating on. For example, the `alnum` generator works differently with ISO8859.1 and ASCII encodings. Where necessary, Spirit encodes (tags) the generator with the character set.

We have a namespace for each character set Spirit will be supporting. That includes `ascii`, `iso8859_1`, `standard` and `standard_wide` (and in the future, `unicode`). In each of the character encoding namespaces, we place tagged versions of generators such as `alnum`, `space` etc.

Example:

    using boost::spirit::ascii::space; // use the ASCII space generator

Namespaces:

- boost::spirit::ascii
- boost::spirit::iso8859_1
- boost::spirit::standard
- boost::spirit::standard_wide

For ease of use, the components in this namespaces are also brought into the karma sub-namespaces with the same names:

- boost::spirit::karma::ascii
- boost::spirit::karma::iso8859_1
- boost::spirit::karma::standard
- boost::spirit::karma::standard_wide

###### Examples

All sections in the reference present some real world examples. The examples use a common test harness to keep the example code as minimal and direct to the point as possible. The test harness is presented below.

Some includes:

    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/support_utree.hpp>
    #include <boost/spirit/include/phoenix_core.hpp>
    #include <boost/spirit/include/phoenix_operator.hpp>
    #include <boost/fusion/include/std_pair.hpp>
    #include <iostream>
    #include <string>

The used output iterator:

    typedef std::back_insert_iterator<std::string> output_iterator_type;

Our test functions:

This one tests the generators without attributes.

    template <typename G>
    void test_generator(char const* expected, G const& g)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate(out, g) && s == expected)
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

These test the generators with one or more user supplied attributes.

    template <typename G, typename T>
    void test_generator_attr(char const* expected, G const& g, T const& attr)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate(out, g, attr) && s == expected)
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

    template <typename G, typename T1, typename T2>
    void test_generator_attr(char const* expected, G const& g, T1 const& attr1,
        T2 const& attr2)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate(out, g, attr1, attr2) && s == expected)
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

This tests the generators with one attribute and while using delimited output.

    template <typename G, typename Delimiter, typename T>
    void test_generator_attr_delim(char const* expected, G const& g, Delimiter const& d, T const& attr)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate_delimited(out, g, d, attr) && s == expected)
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

The examples of the binary generators use one or more of the following tests.

    template <typename G>
    void test_binary_generator(char const* expected, std::size_t size, G const& g)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate(out, g) && !std::memcmp(s.c_str(), expected, size))
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

    template <typename G, typename T>
    void test_binary_generator_attr(char const* expected, std::size_t size, G const& g, T const& attr)
    {
        std::string s;
        std::back_insert_iterator<std::string> out(s);
        if (boost::spirit::karma::generate(out, g, attr) && !std::memcmp(s.c_str(), expected, size))
            std::cout << "ok" << std::endl;
        else
            std::cout << "fail" << std::endl;
    }

###### Models

Predefined models include:

- any literal string, e.g. "Hello, World",
- a pointer/reference to a null-terminated array of characters
- a `std::basic_string<Char>`

The namespace `boost::spirit::traits` is open for users to provide their own specializations. The customization points implemented by Spirit.Karma usable to customize the behavior of generators are described in the section Customization of Attribute Handling.