| Home | Libraries | People | FAQ | More

##### Symbols Parser (`symbols`)

###### Description

The class `symbols` implements a symbol table: an associative container (or map) of key-value pairs where the keys are strings. The `symbols` class can work efficiently with 8, 16, 32 and even 64 bit characters.

Traditionally, symbol table management is maintained separately outside the grammar through semantic actions. Contrary to standard practice, the Spirit symbol table class `symbols` is-a parser, an instance of which may be used anywhere in the grammar specification. It is an example of a dynamic parser. A dynamic parser is characterized by its ability to modify its behavior at run time. Initially, an empty symbols object matches nothing. At any time, symbols may be added, thus, dynamically altering its behavior.

###### Header

    // forwards to <boost/spirit/home/qi/string/symbols.hpp>
    #include <boost/spirit/include/qi_symbols.hpp>

Also, see Include Structure.

###### Namespace

Name
`boost::spirit::qi::symbols`
`boost::spirit::qi::tst`
`boost::spirit::qi::tst_map`

###### Synopsis

    template <typename Char, typename T, typename Lookup>
    struct symbols;

###### Template parameters

Parameter | Description | Default
--- | --- | ---
`Char` | The character type of the symbol strings. | `char`
`T` | The data type associated with each symbol. | `unused_type`
`Lookup` | The symbol search implementation | `tst<Char, T>`

###### Model of

> `PrimitiveParser`

Notation

`Sym`

  A `symbols` type.

`Char`

  A character type.

`T`

  A data type.

`sym`, `sym2`

  `symbols` objects.

`sseq`

  An STL container of strings.

`dseq`

  An STL container of data with `value_type` `T`.

`s1`...`sN`

  A String.

`d1`...`dN`

  Objects of type `T`.

`f`

  A callable function or function object.

`f`, `l`

  `ForwardIterator` first/last pair.

###### Expression Semantics

Semantics of an expression is defined only where it differs from, or is not defined in `PrimitiveParser`.

Expression | Semantics
--- | ---
`Sym()` | Construct an empty symbols names `"symbols"`.
`Sym(name)` | Construct an empty symbols named `name`.
`Sym(sym2)` | Copy construct a symbols from `sym2` (Another `symbols` object).
`Sym(sseq)` | Construct symbols from `sseq` (an STL container of strings) named `"symbols"`.
`Sym(sseq, name)` | Construct symbols from `sseq` (an STL container of strings) named `name`.
`Sym(sseq, dseq)` | Construct symbols from `sseq` and `dseq` (An STL container of strings and an STL container of data with `value_type` `T`) which is named `"symbols"`.
`Sym(sseq, dseq, name)` | Construct symbols from `sseq` and `dseq` (An STL container of strings and an STL container of data with `value_type` `T`) which is named `name`.
`sym = sym2` | Assign `sym2` to `sym`.
`sym = s1, s2, ..., sN` | Assign one or more symbols (`s1`...`sN`) to `sym`.
`sym += s1, s2, ..., sN` | Add one or more symbols (`s1`...`sN`) to `sym`.
`sym.add(s1)(s2)...(sN)` | Add one or more symbols (`s1`...`sN`) to `sym`.
`sym.add(s1, d1)(s2, d2)...(sN, dN)` | Add one or more symbols (`s1`...`sN`) with associated data (`d1`...`dN`) to `sym`.
`sym -= s1, s2, ..., sN` | Remove one or more symbols (`s1`...`sN`) from `sym`.
`sym.remove(s1)(s2)...(sN)` | Remove one or more symbols (`s1`...`sN`) from `sym`.
`sym.clear()` | Erase all of the symbols in `sym`.
`sym.at(s)` | Return a reference to the object associated with symbol, `s`. If `sym` does not already contain such an object, `at` inserts the default object `T()`.
`sym.find(s)` | Return a pointer to the object associated with symbol, `s`. If `sym` does not already contain such an object, `find` returns a null pointer.
`sym.prefix_find(f, l)` | Return a pointer to the object associated with longest symbol that matches the beginning of the range `[f, l)`, and updates `f` to point to one past the end of that match. If no symbol matches, then return a null pointer, and `f` is unchanged.
`sym.for_each(f)` | For each symbol in `sym`, `s`, a `std::basic_string<Char>` with associated data, `d`, an object of type `T`, invoke `f(s, d)`
`sym.name()` | Retrieve the current name of the symbols object.
`sym.name(name)` | Set the current name of the symbols object to be `name`.

###### Attributes

The attribute of `symbol<Char, T>` is `T`.

###### Complexity

The default implementation uses a Ternary Search Tree (TST) with complexity:

> O(log n+k)

Where k is the length of the string to be searched in a TST with n strings.

TSTs are faster than hashing for many typical search problems especially when the search interface is iterator based. TSTs are many times faster than hash tables for unsuccessful searches since mismatches are discovered earlier after examining only a few characters. Hash tables always examine an entire key when searching.

An alternative implementation uses a hybrid hash-map front end (for the first character) plus a TST: `tst_map`. This gives us a complexity of

> O(1 + log n+k-1)

This is found to be significantly faster than plain TST, albeit with a bit more memory usage requirements (each slot in the hash-map is a TST node). If you require a lot of symbols to be searched, use the `tst_map` implementation. This can be done by using `tst_map` as the third template parameter to the symbols class:

    symbols<Char, T, tst_map<Char, T> > sym;

###### Example

| Note
The test harness for the example(s) below is presented in the Basics Examples section.

Some using declarations:

    using boost::spirit::qi::symbols;

Symbols with data:

    symbols<char, int> sym;

    sym.add
        ("Apple", 1)
        ("Banana", 2)
        ("Orange", 3)
    ;

    int i;
    test_parser_attr("Banana", sym, i);
    std::cout << i << std::endl;

When `symbols` is used for case-insensitive parsing (in a `no_case` directive), added symbol strings should be in lowercase. Symbol strings containing one or more uppercase characters will not match any input when symbols is used in a `no_case` directive.

    symbols<char, int> sym;

    sym.add
        ("apple", 1)    // symbol strings are added in lowercase...
        ("banana", 2)
        ("orange", 3)
    ;

    int i;
    // ...because sym is used for case-insensitive parsing
    test_parser_attr("Apple", no_case[ sym ], i);
    std::cout << i << std::endl;
    test_parser_attr("ORANGE", no_case[ sym ], i);
    std::cout << i << std::endl;