| // Copyright (c) 2001-2010 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_LEXER_FUNCTOR_NOV_18_2007_1112PM) |
| #define BOOST_SPIRIT_LEX_LEXER_FUNCTOR_NOV_18_2007_1112PM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #include <boost/mpl/bool.hpp> |
| #include <boost/detail/iterator.hpp> |
| #include <boost/detail/workaround.hpp> |
| #include <boost/spirit/home/lex/lexer/pass_flags.hpp> |
| #include <boost/assert.hpp> |
| |
| #if 0 != __COMO_VERSION__ || !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) |
| #define BOOST_SPIRIT_STATIC_EOF 1 |
| #define BOOST_SPIRIT_EOF_PREFIX static |
| #else |
| #define BOOST_SPIRIT_EOF_PREFIX |
| #endif |
| |
| namespace boost { namespace spirit { namespace lex { namespace lexertl |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // functor is a template usable as the functor object for the |
| // multi_pass iterator allowing to wrap a lexertl based dfa into a |
| // iterator based interface. |
| // |
| // Token: the type of the tokens produced by this functor |
| // this needs to expose a constructor with the following |
| // prototype: |
| // |
| // Token(std::size_t id, std::size_t state, |
| // Iterator start, Iterator end) |
| // |
| // where 'id' is the token id, state is the lexer state, |
| // this token has been matched in, and 'first' and 'end' |
| // mark the start and the end of the token with respect |
| // to the underlying character stream. |
| // FunctorData: |
| // this is expected to encapsulate the shared part of the |
| // functor (see lex/lexer/lexertl/functor_data.hpp for an |
| // example and documentation). |
| // Iterator: the type of the underlying iterator |
| // SupportsActors: |
| // this is expected to be a mpl::bool_, if mpl::true_ the |
| // functor invokes functors which (optionally) have |
| // been attached to the token definitions. |
| // SupportState: |
| // this is expected to be a mpl::bool_, if mpl::true_ the |
| // functor supports different lexer states, |
| // otherwise no lexer state is supported. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Token |
| , template <typename, typename, typename, typename> class FunctorData |
| , typename Iterator = typename Token::iterator_type |
| , typename SupportsActors = mpl::false_ |
| , typename SupportsState = typename Token::has_state> |
| class functor |
| { |
| public: |
| typedef typename |
| boost::detail::iterator_traits<Iterator>::value_type |
| char_type; |
| |
| private: |
| // Needed by compilers not implementing the resolution to DR45. For |
| // reference, see |
| // http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45. |
| typedef typename Token::token_value_type token_value_type; |
| friend class FunctorData<Iterator, SupportsActors, SupportsState |
| , token_value_type>; |
| |
| // Helper template allowing to assign a value on exit |
| template <typename T> |
| struct assign_on_exit |
| { |
| assign_on_exit(T& dst, T const& src) |
| : dst_(dst), src_(src) {} |
| |
| ~assign_on_exit() |
| { |
| dst_ = src_; |
| } |
| |
| T& dst_; |
| T const& src_; |
| |
| private: |
| // silence MSVC warning C4512: assignment operator could not be generated |
| assign_on_exit& operator= (assign_on_exit const&); |
| }; |
| |
| public: |
| functor() |
| #if defined(__PGI) |
| : eof() |
| #endif |
| {} |
| |
| #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310) |
| // somehow VC7.1 needs this (meaningless) assignment operator |
| functor& operator=(functor const& rhs) |
| { |
| return *this; |
| } |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////// |
| // interface to the iterator_policies::split_functor_input policy |
| typedef Token result_type; |
| typedef functor unique; |
| typedef FunctorData<Iterator, SupportsActors, SupportsState |
| , token_value_type> shared; |
| |
| BOOST_SPIRIT_EOF_PREFIX result_type const eof; |
| |
| /////////////////////////////////////////////////////////////////////// |
| typedef Iterator iterator_type; |
| typedef typename shared::semantic_actions_type semantic_actions_type; |
| typedef typename shared::next_token_functor next_token_functor; |
| typedef typename shared::get_state_name_type get_state_name_type; |
| |
| // this is needed to wrap the semantic actions in a proper way |
| typedef typename shared::wrap_action_type wrap_action_type; |
| |
| /////////////////////////////////////////////////////////////////////// |
| template <typename MultiPass> |
| static result_type& get_next(MultiPass& mp, result_type& result) |
| { |
| shared& data = mp.shared()->ftor; |
| for(;;) |
| { |
| if (data.get_first() == data.get_last()) |
| #if defined(BOOST_SPIRIT_STATIC_EOF) |
| return result = eof; |
| #else |
| return result = mp.ftor.eof; |
| #endif |
| |
| data.reset_value(); |
| Iterator end = data.get_first(); |
| std::size_t unique_id = boost::lexer::npos; |
| std::size_t id = data.next(end, unique_id); |
| |
| if (boost::lexer::npos == id) { // no match |
| #if defined(BOOST_SPIRIT_LEXERTL_DEBUG) |
| std::string next; |
| Iterator it = data.get_first(); |
| for (std::size_t i = 0; i < 10 && it != data.get_last(); ++it, ++i) |
| next += *it; |
| |
| std::cerr << "Not matched, in state: " << data.get_state() |
| << ", lookahead: >" << next << "<" << std::endl; |
| #endif |
| return result = result_type(0); |
| } |
| else if (0 == id) { // EOF reached |
| #if defined(BOOST_SPIRIT_STATIC_EOF) |
| return result = eof; |
| #else |
| return result = mp.ftor.eof; |
| #endif |
| } |
| |
| #if defined(BOOST_SPIRIT_LEXERTL_DEBUG) |
| { |
| std::string next; |
| Iterator it = end; |
| for (std::size_t i = 0; i < 10 && it != data.get_last(); ++it, ++i) |
| next += *it; |
| |
| std::cerr << "Matched: " << id << ", in state: " |
| << data.get_state() << ", string: >" |
| << std::basic_string<char_type>(data.get_first(), end) << "<" |
| << ", lookahead: >" << next << "<" << std::endl; |
| } |
| #endif |
| // invoke_actions might change state, id, data.first_, and/or end |
| std::size_t state = data.get_state(); |
| |
| // account for a possibly pending lex::more(), i.e. moving |
| // data.first_ back to the start of the previously matched token. |
| bool adjusted = data.adjust_start(); |
| |
| // invoke attached semantic actions, if defined |
| BOOST_SCOPED_ENUM(pass_flags) pass = |
| data.invoke_actions(state, id, unique_id, end); |
| |
| if (data.has_value()) { |
| // return matched token using the token value as set before |
| // using data.set_value(), advancing 'data.first_' past the |
| // matched sequence |
| assign_on_exit<Iterator> on_exit(data.get_first(), end); |
| return result = result_type(id, state, data.get_value()); |
| } |
| else if (pass_flags::pass_normal == pass) { |
| // return matched token, advancing 'data.first_' past the |
| // matched sequence |
| assign_on_exit<Iterator> on_exit(data.get_first(), end); |
| return result = result_type(id, state, data.get_first(), end); |
| } |
| else if (pass_flags::pass_fail == pass) { |
| // if the data.first_ got adjusted above, revert this adjustment |
| if (adjusted) |
| data.revert_adjust_start(); |
| |
| // one of the semantic actions signaled no-match |
| return result = result_type(0); |
| } |
| |
| // if this token needs to be ignored, just repeat the matching, |
| // while starting right after the current match |
| data.get_first() = end; |
| } |
| } |
| |
| // set_state are propagated up to the iterator interface, allowing to |
| // manipulate the current lexer state through any of the exposed |
| // iterators. |
| template <typename MultiPass> |
| static std::size_t set_state(MultiPass& mp, std::size_t state) |
| { |
| std::size_t oldstate = mp.shared()->ftor.get_state(); |
| mp.shared()->ftor.set_state(state); |
| |
| #if defined(BOOST_SPIRIT_LEXERTL_DEBUG) |
| std::cerr << "Switching state from: " << oldstate |
| << " to: " << state |
| << std::endl; |
| #endif |
| return oldstate; |
| } |
| |
| template <typename MultiPass> |
| static std::size_t get_state(MultiPass& mp) |
| { |
| return mp.shared()->ftor.get_state(); |
| } |
| |
| template <typename MultiPass> |
| static std::size_t |
| map_state(MultiPass const& mp, char_type const* statename) |
| { |
| return mp.shared()->ftor.get_state_id(statename); |
| } |
| |
| // we don't need this, but it must be there |
| template <typename MultiPass> |
| static void destroy(MultiPass const&) {} |
| }; |
| |
| #if defined(BOOST_SPIRIT_STATIC_EOF) |
| /////////////////////////////////////////////////////////////////////////// |
| // eof token |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Token |
| , template <typename, typename, typename, typename> class FunctorData |
| , typename Iterator, typename SupportsActors, typename SupportsState> |
| typename functor<Token, FunctorData, Iterator, SupportsActors, SupportsState>::result_type const |
| functor<Token, FunctorData, Iterator, SupportsActors, SupportsState>::eof = |
| typename functor<Token, FunctorData, Iterator, SupportsActors |
| , SupportsState>::result_type(); |
| #endif |
| |
| }}}} |
| |
| #undef BOOST_SPIRIT_EOF_PREFIX |
| #undef BOOST_SPIRIT_STATIC_EOF |
| |
| #endif |