/*============================================================================= | |
Copyright (c) 2002 Juan Carlos Arevalo-Baeza | |
Copyright (c) 2002-2006 Hartmut Kaiser | |
Copyright (c) 2003 Giovanni Bajo | |
http://spirit.sourceforge.net/ | |
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_SPIRIT_POSITION_ITERATOR_HPP | |
#define BOOST_SPIRIT_POSITION_ITERATOR_HPP | |
#include <string> | |
#include <boost/config.hpp> | |
#include <boost/concept_check.hpp> | |
#include <boost/spirit/home/classic/namespace.hpp> | |
#include <boost/spirit/home/classic/iterator/position_iterator_fwd.hpp> | |
namespace boost { namespace spirit { | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// file_position_without_column | |
// | |
// A structure to hold positional information. This includes the file, | |
// and the line number | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename String> | |
struct file_position_without_column_base { | |
String file; | |
int line; | |
file_position_without_column_base(String const& file_ = String(), | |
int line_ = 1): | |
file (file_), | |
line (line_) | |
{} | |
bool operator==(const file_position_without_column_base& fp) const | |
{ return line == fp.line && file == fp.file; } | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// file_position | |
// | |
// This structure holds complete file position, including file name, | |
// line and column number | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename String> | |
struct file_position_base : public file_position_without_column_base<String> { | |
int column; | |
file_position_base(String const& file_ = String(), | |
int line_ = 1, int column_ = 1): | |
file_position_without_column_base<String> (file_, line_), | |
column (column_) | |
{} | |
bool operator==(const file_position_base& fp) const | |
{ return column == fp.column && this->line == fp.line && this->file == fp.file; } | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// position_policy<> | |
// | |
// This template is the policy to handle the file position. It is specialized | |
// on the position type. Providing a custom file_position also requires | |
// providing a specialization of this class. | |
// | |
// Policy interface: | |
// | |
// Default constructor of the custom position class must be accessible. | |
// set_tab_chars(unsigned int chars) - Set the tabstop width | |
// next_char(PositionT& pos) - Notify that a new character has been | |
// processed | |
// tabulation(PositionT& pos) - Notify that a tab character has been | |
// processed | |
// next_line(PositionT& pos) - Notify that a new line delimiter has | |
// been reached. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename PositionT> class position_policy; | |
/////////////////////////////////////////////////////////////////////////////// | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
}} /* namespace BOOST_SPIRIT_CLASSIC_NS */ | |
// This must be included here for full compatibility with old MSVC | |
#include "boost/spirit/home/classic/iterator/impl/position_iterator.ipp" | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// position_iterator | |
// | |
// It wraps an iterator, and keeps track of the current position in the input, | |
// as it gets incremented. | |
// | |
// The wrapped iterator must be at least a Forward iterator. The position | |
// iterator itself will always be a non-mutable Forward iterator. | |
// | |
// In order to have begin/end iterators constructed, the end iterator must be | |
// empty constructed. Similar to what happens with stream iterators. The begin | |
// iterator must be constructed from both, the begin and end iterators of the | |
// wrapped iterator type. This is necessary to implement the lookahead of | |
// characters necessary to parse CRLF sequences. | |
// | |
// In order to extract the current positional data from the iterator, you may | |
// use the get_position member function. | |
// | |
// You can also use the set_position member function to reset the current | |
// position to something new. | |
// | |
// The structure that holds the current position can be customized through a | |
// template parameter, and the class position_policy must be specialized | |
// on the new type to define how to handle it. Currently, it's possible | |
// to choose between the file_position and file_position_without_column | |
// (which saves some overhead if managing current column is not required). | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
#if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \ | |
BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 | |
#error "Please use at least Boost V1.31.0 while compiling the position_iterator class!" | |
#else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Uses the newer iterator_adaptor version (should be released with | |
// Boost V1.31.0) | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template < | |
typename ForwardIteratorT, | |
typename PositionT, | |
typename SelfT | |
> | |
class position_iterator | |
: public iterator_::impl::position_iterator_base_generator< | |
SelfT, | |
ForwardIteratorT, | |
PositionT | |
>::type, | |
public position_policy<PositionT> | |
{ | |
private: | |
typedef position_policy<PositionT> position_policy_t; | |
typedef typename iterator_::impl::position_iterator_base_generator< | |
SelfT, | |
ForwardIteratorT, | |
PositionT | |
>::type base_t; | |
typedef typename iterator_::impl::position_iterator_base_generator< | |
SelfT, | |
ForwardIteratorT, | |
PositionT | |
>::main_iter_t main_iter_t; | |
public: | |
typedef PositionT position_t; | |
position_iterator() | |
: _isend(true) | |
{} | |
position_iterator( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end) | |
: base_t(begin), _end(end), _pos(PositionT()), _isend(begin == end) | |
{} | |
template <typename FileNameT> | |
position_iterator( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT fileName) | |
: base_t(begin), _end(end), _pos(PositionT(fileName)), | |
_isend(begin == end) | |
{} | |
template <typename FileNameT, typename LineT> | |
position_iterator( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT fileName, LineT line) | |
: base_t(begin), _end(end), _pos(PositionT(fileName, line)), | |
_isend(begin == end) | |
{} | |
template <typename FileNameT, typename LineT, typename ColumnT> | |
position_iterator( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT fileName, LineT line, ColumnT column) | |
: base_t(begin), _end(end), _pos(PositionT(fileName, line, column)), | |
_isend(begin == end) | |
{} | |
position_iterator( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
const PositionT& pos) | |
: base_t(begin), _end(end), _pos(pos), _isend(begin == end) | |
{} | |
position_iterator(const position_iterator& iter) | |
: base_t(iter.base()), position_policy_t(iter), | |
_end(iter._end), _pos(iter._pos), _isend(iter._isend) | |
{} | |
position_iterator& operator=(const position_iterator& iter) | |
{ | |
base_t::operator=(iter); | |
position_policy_t::operator=(iter); | |
_end = iter._end; | |
_pos = iter._pos; | |
_isend = iter._isend; | |
return *this; | |
} | |
void set_position(PositionT const& newpos) { _pos = newpos; } | |
PositionT& get_position() { return _pos; } | |
PositionT const& get_position() const { return _pos; } | |
void set_tabchars(unsigned int chars) | |
{ | |
// This function (which comes from the position_policy) has a | |
// different name on purpose, to avoid messing with using | |
// declarations or qualified calls to access the base template | |
// function, which might break some compilers. | |
this->position_policy_t::set_tab_chars(chars); | |
} | |
private: | |
friend class boost::iterator_core_access; | |
void increment() | |
{ | |
typename base_t::reference val = *(this->base()); | |
if (val == '\n') { | |
++this->base_reference(); | |
this->next_line(_pos); | |
static_cast<main_iter_t &>(*this).newline(); | |
} | |
else if ( val == '\r') { | |
++this->base_reference(); | |
if (this->base_reference() == _end || *(this->base()) != '\n') | |
{ | |
this->next_line(_pos); | |
static_cast<main_iter_t &>(*this).newline(); | |
} | |
} | |
else if (val == '\t') { | |
this->tabulation(_pos); | |
++this->base_reference(); | |
} | |
else { | |
this->next_char(_pos); | |
++this->base_reference(); | |
} | |
// The iterator is at the end only if it's the same | |
// of the | |
_isend = (this->base_reference() == _end); | |
} | |
template < | |
typename OtherDerivedT, typename OtherIteratorT, | |
typename V, typename C, typename R, typename D | |
> | |
bool equal(iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D> | |
const &x) const | |
{ | |
OtherDerivedT const &rhs = static_cast<OtherDerivedT const &>(x); | |
bool x_is_end = rhs._isend; | |
return (_isend == x_is_end) && (_isend || this->base() == rhs.base()); | |
} | |
protected: | |
void newline(void) | |
{} | |
ForwardIteratorT _end; | |
PositionT _pos; | |
bool _isend; | |
}; | |
#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// position_iterator2 | |
// | |
// Equivalent to position_iterator, but it is able to extract the current | |
// line into a string. This is very handy for error reports. | |
// | |
// Notice that the footprint of this class is higher than position_iterator, | |
// (how much depends on how bulky the underlying iterator is), so it should | |
// be used only if necessary. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template | |
< | |
typename ForwardIteratorT, | |
typename PositionT | |
> | |
class position_iterator2 | |
: public position_iterator | |
< | |
ForwardIteratorT, | |
PositionT, | |
position_iterator2<ForwardIteratorT, PositionT> | |
> | |
{ | |
typedef position_iterator | |
< | |
ForwardIteratorT, | |
PositionT, | |
position_iterator2<ForwardIteratorT, PositionT> // JDG 4-15-03 | |
> base_t; | |
public: | |
typedef typename base_t::value_type value_type; | |
typedef PositionT position_t; | |
position_iterator2() | |
{} | |
position_iterator2( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end): | |
base_t(begin, end), | |
_startline(begin) | |
{} | |
template <typename FileNameT> | |
position_iterator2( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT file): | |
base_t(begin, end, file), | |
_startline(begin) | |
{} | |
template <typename FileNameT, typename LineT> | |
position_iterator2( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT file, LineT line): | |
base_t(begin, end, file, line), | |
_startline(begin) | |
{} | |
template <typename FileNameT, typename LineT, typename ColumnT> | |
position_iterator2( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
FileNameT file, LineT line, ColumnT column): | |
base_t(begin, end, file, line, column), | |
_startline(begin) | |
{} | |
position_iterator2( | |
const ForwardIteratorT& begin, | |
const ForwardIteratorT& end, | |
const PositionT& pos): | |
base_t(begin, end, pos), | |
_startline(begin) | |
{} | |
position_iterator2(const position_iterator2& iter) | |
: base_t(iter), _startline(iter._startline) | |
{} | |
position_iterator2& operator=(const position_iterator2& iter) | |
{ | |
base_t::operator=(iter); | |
_startline = iter._startline; | |
return *this; | |
} | |
ForwardIteratorT get_currentline_begin(void) const | |
{ return _startline; } | |
ForwardIteratorT get_currentline_end(void) const | |
{ return get_endline(); } | |
std::basic_string<value_type> get_currentline(void) const | |
{ | |
return std::basic_string<value_type> | |
(get_currentline_begin(), get_currentline_end()); | |
} | |
protected: | |
ForwardIteratorT _startline; | |
friend class position_iterator<ForwardIteratorT, PositionT, | |
position_iterator2<ForwardIteratorT, PositionT> >; | |
ForwardIteratorT get_endline() const | |
{ | |
ForwardIteratorT endline = _startline; | |
while (endline != this->_end && *endline != '\r' && *endline != '\n') | |
{ | |
++endline; | |
} | |
return endline; | |
} | |
void newline(void) | |
{ _startline = this->base(); } | |
}; | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
}} // namespace BOOST_SPIRIT_CLASSIC_NS | |
#endif |