/////////////////////////////////////////////////////////////////////////////// // dynamic.hpp // // Copyright 2004 Eric Niebler. 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) #ifndef BOOST_XPRESSIVE_DETAIL_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 #define BOOST_XPRESSIVE_DETAIL_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include #include #include #include #include #include #include #include #include namespace boost { namespace xpressive { namespace detail { /////////////////////////////////////////////////////////////////////////////// // invalid_xpression // template struct invalid_xpression : matchable { invalid_xpression() : matchable() { } bool match(state_type &) const { BOOST_ASSERT(false); return false; } std::size_t get_width(state_type *) const { return 0; } static void noop(matchable const *) { } }; /////////////////////////////////////////////////////////////////////////////// // get_invalid_xpression // template inline shared_ptr const> const &get_invalid_xpression() { static invalid_xpression const invalid_xpr; static shared_ptr const> const invalid_ptr ( static_cast const *>(&invalid_xpr) , &invalid_xpression::noop ); return invalid_ptr; } /////////////////////////////////////////////////////////////////////////////// // dynamic_xpression // template struct dynamic_xpression : Matcher , matchable { typedef typename iterator_value::type char_type; shared_ptr const> next_; dynamic_xpression(Matcher const &matcher = Matcher()) : Matcher(matcher) , next_(get_invalid_xpression()) { } bool match(state_type &state) const { return this->Matcher::match(state, *this->next_); } std::size_t get_width(state_type *state) const { std::size_t this_width = this->Matcher::get_width(state); if(this_width == unknown_width()) return unknown_width(); std::size_t that_width = this->next_->get_width(state); if(that_width == unknown_width()) return unknown_width(); return this_width + that_width; } void link(xpression_linker &linker) const { linker.link(*static_cast(this), this->next_.get()); this->next_->link(linker); } void peek(xpression_peeker &peeker) const { this->peek_next_(peeker.peek(*static_cast(this)), peeker); } sequence quantify ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence seq , alternates_factory const &factory ) const { return this->quantify_(spec, hidden_mark_count, seq, quant_type(), factory, this); } bool is_quantifiable() const { return quant_type::value != (int)quant_none || this->next_ != get_invalid_xpression(); } private: void peek_next_(mpl::true_, xpression_peeker &peeker) const { this->next_->peek(peeker); } void peek_next_(mpl::false_, xpression_peeker &) const { // no-op } sequence quantify_ ( quant_spec const & , std::size_t & , sequence , mpl::int_ , alternates_factory const & , void const * ) const; sequence quantify_ ( quant_spec const & , std::size_t & , sequence , mpl::int_ , alternates_factory const & , void const * ) const; sequence quantify_ ( quant_spec const & , std::size_t & , sequence , mpl::int_ , alternates_factory const & , void const * ) const; sequence quantify_ ( quant_spec const & , std::size_t & , sequence , mpl::int_ , alternates_factory const & , mark_begin_matcher const * ) const; }; /////////////////////////////////////////////////////////////////////////////// // make_dynamic_xpression // template inline sequence make_dynamic_xpression(Matcher const &matcher) { typedef dynamic_xpression xpression_type; std::auto_ptr xpr(new xpression_type(matcher)); sequence seq; seq.second = &xpr->next_; seq.first = xpr; return seq; } /////////////////////////////////////////////////////////////////////////////// // alternates_factory // template struct alternates_factory { typedef std::vector const> > alternates_vector; virtual ~alternates_factory() {} virtual std::pair, alternates_vector *> operator ()() const = 0; }; template struct alternates_factory_impl : alternates_factory { typedef typename alternates_factory::alternates_vector alternates_vector; std::pair, alternates_vector *> operator ()() const { typedef alternate_matcher alternate_matcher; typedef dynamic_xpression alternate_xpression; shared_ptr alt_xpr(new alternate_xpression); sequence seq(alt_xpr, &alt_xpr->next_); return std::make_pair(seq, &alt_xpr->alternates_); } }; /////////////////////////////////////////////////////////////////////////////// // alternates_to_matchable // template inline sequence alternates_to_matchable ( std::list > const &alternates , alternates_factory const &factory ) { BOOST_ASSERT(0 != alternates.size()); // If there is only 1 alternate, just return it. if(1 == alternates.size()) { return alternates.front(); } typedef std::vector const> > alternates_vector; std::pair, alternates_vector *> result = factory(); // through the wonders of reference counting, all alternates can share an end_alternate typedef dynamic_xpression alternate_end_xpression; shared_ptr end_alt_xpr(new alternate_end_xpression); // terminate each alternate with an alternate_end_matcher result.second->reserve(alternates.size()); typedef std::list > alternates_list; typename alternates_list::const_iterator begin = alternates.begin(), end = alternates.end(); for(; begin != end; ++begin) { if(!begin->is_empty()) { result.second->push_back(begin->first); *begin->second = end_alt_xpr; } else { result.second->push_back(end_alt_xpr); } } return result.first; } /////////////////////////////////////////////////////////////////////////////// // matcher_wrapper // template struct matcher_wrapper : Matcher { matcher_wrapper(Matcher const &matcher = Matcher()) : Matcher(matcher) { } template bool match(state_type &state) const { return this->Matcher::match(state, matcher_wrapper()); } template void link(xpression_linker &linker) const { linker.link(*static_cast(this), 0); } template void peek(xpression_peeker &peeker) const { peeker.peek(*static_cast(this)); } }; ////////////////////////////////////////////////////////////////////////// // dynamic_xpression::quantify_ // // unquantifiable template inline sequence dynamic_xpression::quantify_ ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence seq , mpl::int_ , alternates_factory const &factory , void const * ) const { BOOST_ASSERT(this->next_ != get_invalid_xpression()); return this->quantify_(spec, hidden_mark_count, seq, mpl::int_(), factory, this); } // fixed-width matchers template inline sequence dynamic_xpression::quantify_ ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence seq , mpl::int_ , alternates_factory const &factory , void const * ) const { if(this->next_ != get_invalid_xpression()) { return this->quantify_(spec, hidden_mark_count, seq, mpl::int_(), factory, this); } typedef matcher_wrapper xpr_type; if(spec.greedy_) { simple_repeat_matcher quant(*this, spec.min_, spec.max_); return make_dynamic_xpression(quant); } else { simple_repeat_matcher quant(*this, spec.min_, spec.max_); return make_dynamic_xpression(quant); } } // variable-width, no mark template inline sequence dynamic_xpression::quantify_ ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence seq , mpl::int_ , alternates_factory const &factory , void const * ) const { // create a hidden mark so this expression can be quantified int mark_nbr = -static_cast(++hidden_mark_count); mark_begin_matcher mark_begin(mark_nbr); mark_end_matcher mark_end(mark_nbr); sequence new_seq = make_dynamic_xpression(mark_begin); new_seq += seq; new_seq += make_dynamic_xpression(mark_end); return new_seq.first->quantify(spec, hidden_mark_count, new_seq, factory); } // variable-width with mark template inline sequence dynamic_xpression::quantify_ ( quant_spec const &spec , std::size_t & , sequence seq , mpl::int_ , alternates_factory const &factory , mark_begin_matcher const * ) const { BOOST_ASSERT(spec.max_); // we should never get here if max is 0 int mark_number = this->mark_number_; // only bother creating a quantifier if max is greater than one if(1 < spec.max_) { unsigned int min = spec.min_ ? spec.min_ : 1U; detail::sequence seq_quant; // TODO: statically bind the repeat_begin_matcher to the mark_begin for better perf seq_quant += make_dynamic_xpression(repeat_begin_matcher(mark_number)); // TODO: statically bind the mark_end to the quantifier_end for better perf if(spec.greedy_) { repeat_end_matcher end_quant(mark_number, min, spec.max_); seq += make_dynamic_xpression(end_quant); } else { repeat_end_matcher end_quant(mark_number, min, spec.max_); seq += make_dynamic_xpression(end_quant); } seq_quant += seq; seq = seq_quant; } // if min is 0, the quant must be made alternate with an empty matcher. if(0 == spec.min_) { epsilon_mark_matcher mark(mark_number); std::list > alts; alts.push_back(make_dynamic_xpression(mark)); alts.push_back(seq); if(spec.greedy_) alts.reverse(); seq = alternates_to_matchable(alts, factory); } return seq; } }}} // namespace boost::xpressive::detail #endif