/*=============================================================================

    Copyright (c) 2001-2003 Joel de Guzman

    http://spirit.sourceforge.net/



    Use, modification and distribution is subject to the Boost Software

    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at

    http://www.boost.org/LICENSE_1_0.txt)

=============================================================================*/

#ifndef BOOST_SPIRIT_SYMBOLS_HPP

#define BOOST_SPIRIT_SYMBOLS_HPP



///////////////////////////////////////////////////////////////////////////////

#include <string>



#include <boost/ref.hpp>



#include <boost/spirit/core/parser.hpp>

#include <boost/spirit/core/composite/directives.hpp>



#include <boost/spirit/symbols/symbols_fwd.hpp>





///////////////////////////////////////////////////////////////////////////////

namespace boost { namespace spirit {



///////////////////////////////////////////////////////////////////////////////

//

//  symbols class

//

//      This class implements a symbol table. The symbol table holds a

//      dictionary of symbols where each symbol is a sequence of CharTs.

//      The template class can work efficiently with 8, 16 and 32 bit

//      characters. Mutable data of type T is associated with each

//      symbol.

//

//      The class is a parser. The parse member function returns

//      additional information in the symbol_match class (see below).

//      The additional data is a pointer to some data associated with

//      the matching symbol.

//

//      The actual set implementation is supplied by the SetT template

//      parameter. By default, this uses the tst class (see tst.ipp).

//

//      Symbols are added into the symbol table statically using the

//      construct:

//

//          sym = a, b, c, d ...;

//

//      where sym is a symbol table and a..d are strings. Example:

//

//          sym = "pineapple", "orange", "banana", "apple";

//

//      Alternatively, symbols may be added dynamically through the

//      member functor 'add' (see symbol_inserter below). The member

//      functor 'add' may be attached to a parser as a semantic action

//      taking in a begin/end pair:

//

//          p[sym.add]

//

//      where p is a parser (and sym is a symbol table). On success,

//      the matching portion of the input is added to the symbol table.

//

//      'add' may also be used to directly initialize data. Examples:

//

//          sym.add("hello", 1)("crazy", 2)("world", 3);

//

///////////////////////////////////////////////////////////////////////////////

template <typename T, typename CharT, typename SetT>

class symbols

:   private SetT

,   public parser<symbols<T, CharT, SetT> >

{

public:



    typedef parser<symbols<T, CharT, SetT> > parser_base_t;

    typedef symbols<T, CharT, SetT> self_t;

    typedef self_t const& embed_t;

    typedef T symbol_data_t;

    typedef boost::reference_wrapper<T> symbol_ref_t;



    symbols();

    symbols(symbols const& other);

    ~symbols();



    symbols&

    operator=(symbols const& other);



    symbol_inserter<T, SetT> const&

    operator=(CharT const* str);



    template <typename ScannerT>

    struct result

    {

        typedef typename match_result<ScannerT, symbol_ref_t>::type type;

    };



    template <typename ScannerT>

    typename parser_result<self_t, ScannerT>::type

    parse_main(ScannerT const& scan) const

    {

        typedef typename ScannerT::iterator_t iterator_t;

        iterator_t first = scan.first;

        typename SetT::search_info result = SetT::find(scan);



        if (result.data)

            return scan.

                create_match(

                    result.length,

                    symbol_ref_t(*result.data),

                    first,

                    scan.first);

        else

            return scan.no_match();

    }



    template <typename ScannerT>

    typename parser_result<self_t, ScannerT>::type

    parse(ScannerT const& scan) const

    {

        typedef typename parser_result<self_t, ScannerT>::type result_t;

        return impl::implicit_lexeme_parse<result_t>

            (*this, scan, scan);

    }



    template < typename ScannerT >

    T* find(ScannerT const& scan) const

    { return SetT::find(scan).data; }



    symbol_inserter<T, SetT> const add;

};



///////////////////////////////////////////////////////////////////////////////

//

//  Symbol table utilities

//

//  add

//

//      adds a symbol 'sym' (string) to a symbol table 'table' plus an

//      optional data 'data' associated with the symbol. Returns a pointer to

//      the data associated with the symbol or NULL if add failed (e.g. when

//      the symbol is already added before).

//

//  find

//

//      finds a symbol 'sym' (string) from a symbol table 'table'. Returns a

//      pointer to the data associated with the symbol or NULL if not found

//

///////////////////////////////////////////////////////////////////////////////

template <typename T, typename CharT, typename SetT>

T*  add(symbols<T, CharT, SetT>& table, CharT const* sym, T const& data = T());



template <typename T, typename CharT, typename SetT>

T*  find(symbols<T, CharT, SetT> const& table, CharT const* sym);



///////////////////////////////////////////////////////////////////////////////

//

//  symbol_inserter class

//

//      The symbols class holds an instance of this class named 'add'.

//      This can be called directly just like a member function,

//      passing in a first/last iterator and optional data:

//

//          sym.add(first, last, data);

//

//      Or, passing in a C string and optional data:

//

//          sym.add(c_string, data);

//

//      where sym is a symbol table. The 'data' argument is optional.

//      This may also be used as a semantic action since it conforms

//      to the action interface (see action.hpp):

//

//          p[sym.add]

//

///////////////////////////////////////////////////////////////////////////////

template <typename T, typename SetT>

class symbol_inserter

{

public:



    symbol_inserter(SetT& set_)

    : set(set_) {}



    typedef symbol_inserter const & result_type;



    template <typename IteratorT>

    symbol_inserter const&

    operator()(IteratorT first, IteratorT const& last, T const& data = T()) const

    {

        set.add(first, last, data);

        return *this;

    }



    template <typename CharT>

    symbol_inserter const&

    operator()(CharT const* str, T const& data = T()) const

    {

        CharT const* last = str;

        while (*last)

            last++;

        set.add(str, last, data);

        return *this;

    }



    template <typename CharT>

    symbol_inserter const&

    operator,(CharT const* str) const

    {

        CharT const* last = str;

        while (*last)

            last++;

        set.add(str, last, T());

        return *this;

    }



private:



    SetT& set;

};



///////////////////////////////////////////////////////////////////////////////

}} // namespace boost::spirit



#include <boost/spirit/symbols/impl/symbols.ipp>

#endif

