| // 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_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 <boost/spirit/home/lex/lexer/lexer_fwd.hpp> |
| #include <boost/spirit/home/lex/lexer/terminal_holder.hpp> |
| #include <boost/spirit/home/lex/lexer/token_def.hpp> |
| #include <boost/detail/iterator.hpp> |
| #include <boost/fusion/include/vector.hpp> |
| #include <boost/mpl/assert.hpp> |
| #include <boost/range/iterator_range.hpp> |
| #include <cstdlib> |
| |
| namespace boost { namespace spirit { namespace lex |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // token_set |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename TokenSet> |
| class token_set |
| : public TokenSet, |
| public proto::extends< |
| typename make_terminal_holder< |
| token_set<TokenSet>*, token_set<TokenSet> |
| >::type, |
| token_set<TokenSet> |
| > |
| { |
| 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<token_set*, token_set> terminal_holder_; |
| typedef typename proto::terminal<terminal_holder_>::type tag; |
| typedef proto::extends<tag, token_set> 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 <typename Component, typename Context, typename Iterator> |
| 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<id_type, iterator_range<iterator_type> > |
| type; |
| }; |
| |
| private: |
| // Qi interface: parse functionality |
| template <typename Iterator, typename Context, typename Skipper, |
| typename Attribute> |
| 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<Iterator>::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 <typename LexerDef, typename String> |
| 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<std::size_t>(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<id_type>::get(); |
| def.add_token (def.initial_state().c_str(), s, token_id); |
| return *this; |
| } |
| template <typename Attribute> |
| adder const& |
| operator()(token_def<Attribute, char_type, id_type>& 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<id_type>::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 <typename TokenSet_> |
| adder const& |
| operator()(token_set<TokenSet_> 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 <typename Expr> |
| void define(Expr const& xpr) |
| { |
| typedef typename |
| result_of::as_component<lex::domain, Expr>::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 <typename Expr> |
| token_set& operator= (Expr const& xpr) |
| { |
| typedef |
| spirit::traits::is_component<lex::domain, Expr> |
| 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 <typename TokenSet, typename Expr> |
| inline token_set<TokenSet>& |
| operator+= (token_set<TokenSet>& tokset, Expr& xpr) |
| { |
| typedef |
| spirit::traits::is_component<lex::domain, Expr> |
| 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 <typename TokenSet, typename Expr> |
| inline token_set<TokenSet>& |
| operator+= (token_set<TokenSet>& tokset, Expr const& xpr) |
| { |
| typedef |
| spirit::traits::is_component<lex::domain, Expr> |
| 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 |