1 /////////////////////////////////////////////////////////////////////////////// 2 // lookahead_matcher.hpp 3 // 4 // Copyright 2008 Eric Niebler. Distributed under the Boost 5 // Software License, Version 1.0. (See accompanying file 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 #ifndef BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKAHEAD_MATCHER_HPP_EAN_10_04_2005 9 #define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKAHEAD_MATCHER_HPP_EAN_10_04_2005 10 11 // MS compatible compilers support #pragma once 12 #if defined(_MSC_VER) 13 # pragma once 14 #endif 15 16 #include <boost/assert.hpp> 17 #include <boost/mpl/bool.hpp> 18 #include <boost/xpressive/detail/detail_fwd.hpp> 19 #include <boost/xpressive/detail/core/quant_style.hpp> 20 #include <boost/xpressive/detail/core/state.hpp> 21 #include <boost/xpressive/detail/utility/save_restore.hpp> 22 #include <boost/xpressive/detail/utility/ignore_unused.hpp> 23 24 namespace boost { namespace xpressive { namespace detail 25 { 26 27 /////////////////////////////////////////////////////////////////////////////// 28 // lookahead_matcher 29 // Xpr can be either a static_xpression, or a shared_matchable 30 // 31 template<typename Xpr> 32 struct lookahead_matcher 33 : quant_style<quant_none, 0, Xpr::pure> 34 { lookahead_matcherboost::xpressive::detail::lookahead_matcher35 lookahead_matcher(Xpr const &xpr, bool no, bool pure = Xpr::pure) 36 : xpr_(xpr) 37 , not_(no) 38 , pure_(pure) 39 { 40 } 41 inverseboost::xpressive::detail::lookahead_matcher42 void inverse() 43 { 44 this->not_ = !this->not_; 45 } 46 47 template<typename BidiIter, typename Next> matchboost::xpressive::detail::lookahead_matcher48 bool match(match_state<BidiIter> &state, Next const &next) const 49 { 50 return Xpr::pure || this->pure_ 51 ? this->match_(state, next, mpl::true_()) 52 : this->match_(state, next, mpl::false_()); 53 } 54 55 template<typename BidiIter, typename Next> match_boost::xpressive::detail::lookahead_matcher56 bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const 57 { 58 BidiIter const tmp = state.cur_; 59 60 if(this->not_) 61 { 62 // negative look-ahead assertions do not trigger partial matches. 63 save_restore<bool> partial_match(state.found_partial_match_); 64 detail::ignore_unused(partial_match); 65 66 if(this->xpr_.match(state)) 67 { 68 state.cur_ = tmp; 69 return false; 70 } 71 else if(next.match(state)) 72 { 73 return true; 74 } 75 } 76 else 77 { 78 if(!this->xpr_.match(state)) 79 { 80 return false; 81 } 82 state.cur_ = tmp; 83 if(next.match(state)) 84 { 85 return true; 86 } 87 } 88 89 BOOST_ASSERT(state.cur_ == tmp); 90 return false; 91 } 92 93 template<typename BidiIter, typename Next> match_boost::xpressive::detail::lookahead_matcher94 bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const 95 { 96 BidiIter const tmp = state.cur_; 97 98 // matching xpr could produce side-effects, save state 99 memento<BidiIter> mem = save_sub_matches(state); 100 101 if(this->not_) 102 { 103 // negative look-ahead assertions do not trigger partial matches. 104 save_restore<bool> partial_match(state.found_partial_match_); 105 detail::ignore_unused(partial_match); 106 107 if(this->xpr_.match(state)) 108 { 109 restore_action_queue(mem, state); 110 restore_sub_matches(mem, state); 111 state.cur_ = tmp; 112 return false; 113 } 114 restore_action_queue(mem, state); 115 if(next.match(state)) 116 { 117 reclaim_sub_matches(mem, state, true); 118 return true; 119 } 120 reclaim_sub_matches(mem, state, false); 121 } 122 else 123 { 124 if(!this->xpr_.match(state)) 125 { 126 restore_action_queue(mem, state); 127 reclaim_sub_matches(mem, state, false); 128 return false; 129 } 130 state.cur_ = tmp; 131 restore_action_queue(mem, state); 132 if(next.match(state)) 133 { 134 reclaim_sub_matches(mem, state, true); 135 return true; 136 } 137 restore_sub_matches(mem, state); 138 } 139 140 BOOST_ASSERT(state.cur_ == tmp); 141 return false; 142 } 143 144 Xpr xpr_; 145 bool not_; 146 bool pure_; // false if matching xpr_ could modify the sub-matches 147 }; 148 149 }}} 150 151 #endif 152