// Copyright (c) 2001-2008 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_SET_MAR_13_2007_0145PM) #define BOOST_SPIRIT_LEX_TOKEN_SET_MAR_13_2007_0145PM #if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once // MS compatible compilers support #pragma once #endif #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace lex { /////////////////////////////////////////////////////////////////////////// // token_set /////////////////////////////////////////////////////////////////////////// template class token_set : public TokenSet, public proto::extends< typename make_terminal_holder< token_set*, token_set >::type, token_set > { protected: typedef typename TokenSet::char_type char_type; typedef typename TokenSet::string_type string_type; private: // avoid warnings about using 'this' in constructor token_set& this_() { return *this; } typedef token_set self_type; typedef TokenSet base_token_set; // initialize proto base class typedef terminal_holder terminal_holder_; typedef typename proto::terminal::type tag; typedef proto::extends base_type; tag make_tag() { tag xpr = {{ this }}; return xpr; } public: typedef typename TokenSet::id_type id_type; // Qi interface: metafunction calculating parser return type template struct attribute { // the return value of a token set contains the matched token id, // and the corresponding pair of iterators typedef typename Iterator::base_iterator_type iterator_type; typedef fusion::vector > type; }; private: // Qi interface: parse functionality template bool parse(Iterator& first, Iterator const& last, Context& context, Skipper const& skipper, Attribute& attr) const { qi::skip(first, last, skipper); // always do a pre-skip if (first != last) { typedef typename boost::detail::iterator_traits::value_type token_type; // If the following assertion fires you probably forgot to // associate this token set definition with a lexer instance. BOOST_ASSERT(~0 != token_state); token_type &t = *first; if (token_is_valid(t) && token_state == t.state()) { // any of the token definitions matched qi::detail::assign_to(t, attr); ++first; return true; } } return false; } friend struct terminal_director; static std::string what() { return "token_set"; } /////////////////////////////////////////////////////////////////////// // Lex interface: collect token definitions and put it into the // provided lexer def template void collect(LexerDef& lexdef, String const& state) { token_state = lexdef.add_state(state.c_str()); lexdef.add_token (state.c_str(), *this); } // allow to use the tokset.add("regex1", id1)("regex2", id2); // syntax struct adder { adder(token_set& def_) : def(def_) {} adder const& operator()(char_type c, id_type token_id = id_type()) const { if (0 == token_id) token_id = static_cast(c); def.add_token (def.initial_state().c_str(), lex::detail::escape(c), token_id); return *this; } adder const& operator()(string_type const& s, id_type token_id = id_type()) const { if (0 == token_id) token_id = next_id::get(); def.add_token (def.initial_state().c_str(), s, token_id); return *this; } template adder const& operator()(token_def& tokdef, id_type token_id = id_type()) const { // make sure we have a token id if (0 == token_id) { if (0 == tokdef.id()) { token_id = next_id::get(); tokdef.id(token_id); } else { token_id = tokdef.id(); } } else { // the following assertion makes sure, that the token_def // instance has not been assigned a different id earlier BOOST_ASSERT(0 == tokdef.id() || token_id == tokdef.id()); tokdef.id(token_id); } def.add_token (def.initial_state().c_str(), tokdef.definition(), token_id); return *this; } template adder const& operator()(token_set const& tokset) const { def.add_token (def.initial_state().c_str(), tokset); return *this; } token_set& def; }; friend struct adder; // allow to use lexer.self.add_pattern("pattern1", "regex1")(...); // syntax struct pattern_adder { pattern_adder(token_set& def_) : def(def_) {} pattern_adder const& operator()(string_type const& p, string_type const& s) const { def.add_pattern (def.state.c_str(), p, s); return *this; } token_set& def; }; friend struct pattern_adder; public: /////////////////////////////////////////////////////////////////// template void define(Expr const& xpr) { typedef typename result_of::as_component::type component; typedef typename component::director director; component c = spirit::as_component(lex::domain(), xpr); director::collect(c, *this, base_token_set::initial_state()); } token_set() : base_type(make_tag()), add(this_()), add_pattern(this_()), token_state(~0) {} // allow to assign a token definition expression template token_set& operator= (Expr const& xpr) { typedef spirit::traits::is_component is_component; // report invalid expression error as early as possible BOOST_MPL_ASSERT_MSG( is_component::value, xpr_is_not_convertible_to_a_token_definition, ()); this->clear(); define(xpr); return *this; } adder add; pattern_adder add_pattern; private: std::size_t token_state; }; // allow to assign a token definition expression template inline token_set& operator+= (token_set& tokset, Expr& xpr) { typedef spirit::traits::is_component is_component; // report invalid expression error as early as possible BOOST_MPL_ASSERT_MSG( is_component::value, xpr_is_not_convertible_to_a_token_definition, ()); tokset.define(xpr); return tokset; } template inline token_set& operator+= (token_set& tokset, Expr const& xpr) { typedef spirit::traits::is_component is_component; // report invalid expression error as early as possible BOOST_MPL_ASSERT_MSG( is_component::value, xpr_is_not_convertible_to_a_token_definition, ()); tokset.define(xpr); return tokset; } }}} #endif