blob: ab46b2675680adb5065fc949ea71bea29903fc0b [file] [log] [blame]
// Copyright (c) 2001-2009 Hartmut Kaiser
//
// Distributed under 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)
#if !defined(BOOST_SPIRIT_LEX_TOKEN_DEF_MAR_13_2007_0145PM)
#define BOOST_SPIRIT_LEX_TOKEN_DEF_MAR_13_2007_0145PM
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once // MS compatible compilers support #pragma once
#endif
#include <boost/spirit/home/lex/lexer/lexer_fwd.hpp>
#include <boost/spirit/home/lex/lexer/terminal_holder.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/spirit/home/qi/skip.hpp>
#include <boost/spirit/home/qi/detail/construct.hpp>
#include <boost/spirit/home/qi/detail/assign_to.hpp>
#include <boost/mpl/if.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/type_traits/is_same.hpp>
#include <string>
#include <cstdlib>
namespace boost { namespace spirit { namespace lex
{
///////////////////////////////////////////////////////////////////////////
// create a unique token id, note this is not thread safe
///////////////////////////////////////////////////////////////////////////
enum tokenids {
// this is the first token id automatically assigned by the library
// if needed
min_token_id = 0x10000
};
///////////////////////////////////////////////////////////////////////////
// The next_id template needs to be specialized for any non-default token
// id type used by a custom token type. It need to expose a function
// 'static Idtype get()' returning the next available token id each time
// it is called.
template <typename Idtype>
struct next_id;
///////////////////////////////////////////////////////////////////////////
// Default specialization for the next_id template returning the next
// available token id.
template <>
struct next_id<std::size_t>
{
static std::size_t get()
{
static std::size_t next_token_id = min_token_id;
return next_token_id++;
}
};
///////////////////////////////////////////////////////////////////////////
// This component represents a token definition
///////////////////////////////////////////////////////////////////////////
template<typename Attribute, typename Char, typename Idtype>
class token_def
: public proto::extends<
typename make_terminal_holder<
token_def<Attribute, Char, Idtype>*,
token_def<Attribute, Char, Idtype>
>::type,
token_def<Attribute, Char, Idtype>
>
{
private:
// initialize proto base class
typedef terminal_holder<token_def*, token_def> terminal_holder_;
typedef typename proto::terminal<terminal_holder_>::type tag;
typedef proto::extends<tag, token_def> base_type;
tag make_tag()
{
tag xpr = {{ this }};
return xpr;
}
public:
// Qi interface: metafunction calculating parser return type
template <typename Component, typename Context, typename Iterator>
struct attribute
{
// The return value of the token_def is either the specified
// attribute type, or the pair of iterators from the match of the
// corresponding token (if no attribute type has been specified),
// or unused_type (if omitted has been specified).
typedef typename Iterator::base_iterator_type iterator_type;
typedef typename
mpl::if_<
is_same<Attribute, unused_type>,
iterator_range<iterator_type>,
typename mpl::if_<
is_same<Attribute, omitted>,
unused_type,
Attribute
>::type
>::type
type;
};
private:
// Qi interface: parse functionality
template <typename Iterator, typename Context, typename Skipper,
typename Attribute1>
bool parse(Iterator& first, Iterator const& last,
Context& /*context*/, Skipper const& skipper, Attribute1& attr) const
{
qi::skip(first, last, skipper); // always do a pre-skip
if (first != last) {
typedef typename
boost::detail::iterator_traits<Iterator>::value_type
token_type;
// If the following assertion fires you probably forgot to
// associate this token definition with a lexer instance.
BOOST_ASSERT((std::size_t)(~0) != token_state);
token_type &t = *first;
if (token_id == t.id() && token_state == t.state()) {
qi::detail::assign_to(t, attr);
++first;
return true;
}
}
return false;
}
friend struct terminal_director;
std::string what() const
{
std::string result = "token_def(\"";
result += def;
result += "\")";
return result;
}
///////////////////////////////////////////////////////////////////////
// Lex interface: collect token definitions and put it into the
// provided lexer def
template <typename LexerDef, typename String>
void collect(LexerDef& lexdef, String const& state)
{
token_state = lexdef.add_state(state.c_str());
if (0 == token_id)
token_id = next_id<Idtype>::get();
lexdef.add_token (state.c_str(), def, token_id);
}
public:
typedef Char char_type;
typedef Idtype id_type;
typedef std::basic_string<char_type> string_type;
// Lex interface: constructing token definitions
token_def()
: base_type(make_tag()), token_id(0), token_state(~0)
{}
explicit token_def(char_type def_, Idtype id_ = Idtype())
: base_type(make_tag()), def(lex::detail::escape(def_)),
token_id(0 == id_ ? def_ : id_), token_state(~0)
{}
explicit token_def(string_type def_, Idtype id_ = Idtype())
: base_type(make_tag()), def(def_), token_id(id_), token_state(~0)
{}
template <typename String>
token_def& operator= (String const& definition)
{
def = definition;
token_id = 0;
return *this;
}
token_def& operator= (token_def const& rhs)
{
def = rhs.def;
token_id = rhs.token_id;
return *this;
}
// general accessors
Idtype id() const { return token_id; }
void id(Idtype id) { token_id = id; }
string_type const& definition() const { return def; }
std::size_t state() const { return token_state; }
private:
string_type def;
Idtype token_id;
std::size_t token_state;
};
}}}
#endif