| 1 | /*============================================================================= |
| 2 | Copyright (c) 2002 Juan Carlos Arevalo-Baeza |
| 3 | Copyright (c) 2002-2006 Hartmut Kaiser |
| 4 | Copyright (c) 2003 Giovanni Bajo |
| 5 | http://spirit.sourceforge.net/ |
| 6 | |
| 7 | Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 8 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 9 | =============================================================================*/ |
| 10 | #ifndef BOOST_SPIRIT_POSITION_ITERATOR_HPP |
| 11 | #define BOOST_SPIRIT_POSITION_ITERATOR_HPP |
| 12 | |
| 13 | #include <string> |
| 14 | #include <boost/config.hpp> |
| 15 | |
| 16 | #include <boost/spirit/home/classic/namespace.hpp> |
| 17 | #include <boost/spirit/home/classic/iterator/position_iterator_fwd.hpp> |
| 18 | |
| 19 | namespace boost { namespace spirit { |
| 20 | |
| 21 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
| 22 | |
| 23 | /////////////////////////////////////////////////////////////////////////////// |
| 24 | // |
| 25 | // file_position_without_column |
| 26 | // |
| 27 | // A structure to hold positional information. This includes the file, |
| 28 | // and the line number |
| 29 | // |
| 30 | /////////////////////////////////////////////////////////////////////////////// |
| 31 | template <typename String> |
| 32 | struct file_position_without_column_base { |
| 33 | String file; |
| 34 | int line; |
| 35 | |
| 36 | file_position_without_column_base(String const& file_ = String(), |
| 37 | int line_ = 1): |
| 38 | file (file_), |
| 39 | line (line_) |
| 40 | {} |
| 41 | |
| 42 | bool operator==(const file_position_without_column_base& fp) const |
| 43 | { return line == fp.line && file == fp.file; } |
| 44 | }; |
| 45 | |
| 46 | /////////////////////////////////////////////////////////////////////////////// |
| 47 | // |
| 48 | // file_position |
| 49 | // |
| 50 | // This structure holds complete file position, including file name, |
| 51 | // line and column number |
| 52 | // |
| 53 | /////////////////////////////////////////////////////////////////////////////// |
| 54 | template <typename String> |
| 55 | struct file_position_base : public file_position_without_column_base<String> { |
| 56 | int column; |
| 57 | |
| 58 | file_position_base(String const& file_ = String(), |
| 59 | int line_ = 1, int column_ = 1): |
| 60 | file_position_without_column_base<String> (file_, line_), |
| 61 | column (column_) |
| 62 | {} |
| 63 | |
| 64 | bool operator==(const file_position_base& fp) const |
| 65 | { return column == fp.column && this->line == fp.line && this->file == fp.file; } |
| 66 | }; |
| 67 | |
| 68 | /////////////////////////////////////////////////////////////////////////////// |
| 69 | // |
| 70 | // position_policy<> |
| 71 | // |
| 72 | // This template is the policy to handle the file position. It is specialized |
| 73 | // on the position type. Providing a custom file_position also requires |
| 74 | // providing a specialization of this class. |
| 75 | // |
| 76 | // Policy interface: |
| 77 | // |
| 78 | // Default constructor of the custom position class must be accessible. |
| 79 | // set_tab_chars(unsigned int chars) - Set the tabstop width |
| 80 | // next_char(PositionT& pos) - Notify that a new character has been |
| 81 | // processed |
| 82 | // tabulation(PositionT& pos) - Notify that a tab character has been |
| 83 | // processed |
| 84 | // next_line(PositionT& pos) - Notify that a new line delimiter has |
| 85 | // been reached. |
| 86 | // |
| 87 | /////////////////////////////////////////////////////////////////////////////// |
| 88 | template <typename PositionT> class position_policy; |
| 89 | |
| 90 | /////////////////////////////////////////////////////////////////////////////// |
| 91 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
| 92 | |
| 93 | }} /* namespace BOOST_SPIRIT_CLASSIC_NS */ |
| 94 | |
| 95 | |
| 96 | // This must be included here for full compatibility with old MSVC |
| 97 | #include <boost/spirit/home/classic/iterator/impl/position_iterator.ipp> |
| 98 | |
| 99 | /////////////////////////////////////////////////////////////////////////////// |
| 100 | namespace boost { namespace spirit { |
| 101 | |
| 102 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
| 103 | |
| 104 | /////////////////////////////////////////////////////////////////////////////// |
| 105 | // |
| 106 | // position_iterator |
| 107 | // |
| 108 | // It wraps an iterator, and keeps track of the current position in the input, |
| 109 | // as it gets incremented. |
| 110 | // |
| 111 | // The wrapped iterator must be at least a Forward iterator. The position |
| 112 | // iterator itself will always be a non-mutable Forward iterator. |
| 113 | // |
| 114 | // In order to have begin/end iterators constructed, the end iterator must be |
| 115 | // empty constructed. Similar to what happens with stream iterators. The begin |
| 116 | // iterator must be constructed from both, the begin and end iterators of the |
| 117 | // wrapped iterator type. This is necessary to implement the lookahead of |
| 118 | // characters necessary to parse CRLF sequences. |
| 119 | // |
| 120 | // In order to extract the current positional data from the iterator, you may |
| 121 | // use the get_position member function. |
| 122 | // |
| 123 | // You can also use the set_position member function to reset the current |
| 124 | // position to something new. |
| 125 | // |
| 126 | // The structure that holds the current position can be customized through a |
| 127 | // template parameter, and the class position_policy must be specialized |
| 128 | // on the new type to define how to handle it. Currently, it's possible |
| 129 | // to choose between the file_position and file_position_without_column |
| 130 | // (which saves some overhead if managing current column is not required). |
| 131 | // |
| 132 | /////////////////////////////////////////////////////////////////////////////// |
| 133 | |
| 134 | #if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \ |
| 135 | BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 |
| 136 | #error "Please use at least Boost V1.31.0 while compiling the position_iterator class!" |
| 137 | #else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 |
| 138 | |
| 139 | /////////////////////////////////////////////////////////////////////////////// |
| 140 | // |
| 141 | // Uses the newer iterator_adaptor version (should be released with |
| 142 | // Boost V1.31.0) |
| 143 | // |
| 144 | /////////////////////////////////////////////////////////////////////////////// |
| 145 | template < |
| 146 | typename ForwardIteratorT, |
| 147 | typename PositionT, |
| 148 | typename SelfT |
| 149 | > |
| 150 | class position_iterator |
| 151 | : public iterator_::impl::position_iterator_base_generator< |
| 152 | SelfT, |
| 153 | ForwardIteratorT, |
| 154 | PositionT |
| 155 | >::type, |
| 156 | public position_policy<PositionT> |
| 157 | { |
| 158 | private: |
| 159 | |
| 160 | typedef position_policy<PositionT> position_policy_t; |
| 161 | typedef typename iterator_::impl::position_iterator_base_generator< |
| 162 | SelfT, |
| 163 | ForwardIteratorT, |
| 164 | PositionT |
| 165 | >::type base_t; |
| 166 | typedef typename iterator_::impl::position_iterator_base_generator< |
| 167 | SelfT, |
| 168 | ForwardIteratorT, |
| 169 | PositionT |
| 170 | >::main_iter_t main_iter_t; |
| 171 | |
| 172 | public: |
| 173 | |
| 174 | typedef PositionT position_t; |
| 175 | |
| 176 | position_iterator() |
| 177 | : _isend(true) |
| 178 | {} |
| 179 | |
| 180 | position_iterator( |
| 181 | const ForwardIteratorT& begin, |
| 182 | const ForwardIteratorT& end) |
| 183 | : base_t(begin), _end(end), _pos(PositionT()), _isend(begin == end) |
| 184 | {} |
| 185 | |
| 186 | template <typename FileNameT> |
| 187 | position_iterator( |
| 188 | const ForwardIteratorT& begin, |
| 189 | const ForwardIteratorT& end, |
| 190 | FileNameT fileName) |
| 191 | : base_t(begin), _end(end), _pos(PositionT(fileName)), |
| 192 | _isend(begin == end) |
| 193 | {} |
| 194 | |
| 195 | template <typename FileNameT, typename LineT> |
| 196 | position_iterator( |
| 197 | const ForwardIteratorT& begin, |
| 198 | const ForwardIteratorT& end, |
| 199 | FileNameT fileName, LineT line) |
| 200 | : base_t(begin), _end(end), _pos(PositionT(fileName, line)), |
| 201 | _isend(begin == end) |
| 202 | {} |
| 203 | |
| 204 | template <typename FileNameT, typename LineT, typename ColumnT> |
| 205 | position_iterator( |
| 206 | const ForwardIteratorT& begin, |
| 207 | const ForwardIteratorT& end, |
| 208 | FileNameT fileName, LineT line, ColumnT column) |
| 209 | : base_t(begin), _end(end), _pos(PositionT(fileName, line, column)), |
| 210 | _isend(begin == end) |
| 211 | {} |
| 212 | |
| 213 | position_iterator( |
| 214 | const ForwardIteratorT& begin, |
| 215 | const ForwardIteratorT& end, |
| 216 | const PositionT& pos) |
| 217 | : base_t(begin), _end(end), _pos(pos), _isend(begin == end) |
| 218 | {} |
| 219 | |
| 220 | position_iterator(const position_iterator& iter) |
| 221 | : base_t(iter.base()), position_policy_t(iter), |
| 222 | _end(iter._end), _pos(iter._pos), _isend(iter._isend) |
| 223 | {} |
| 224 | |
| 225 | position_iterator& operator=(const position_iterator& iter) |
| 226 | { |
| 227 | base_t::operator=(iter); |
| 228 | position_policy_t::operator=(iter); |
| 229 | _end = iter._end; |
| 230 | _pos = iter._pos; |
| 231 | _isend = iter._isend; |
| 232 | return *this; |
| 233 | } |
| 234 | |
| 235 | void set_position(PositionT const& newpos) { _pos = newpos; } |
| 236 | PositionT& get_position() { return _pos; } |
| 237 | PositionT const& get_position() const { return _pos; } |
| 238 | |
| 239 | void set_tabchars(unsigned int chars) |
| 240 | { |
| 241 | // This function (which comes from the position_policy) has a |
| 242 | // different name on purpose, to avoid messing with using |
| 243 | // declarations or qualified calls to access the base template |
| 244 | // function, which might break some compilers. |
| 245 | this->position_policy_t::set_tab_chars(chars); |
| 246 | } |
| 247 | |
| 248 | private: |
| 249 | friend class boost::iterator_core_access; |
| 250 | |
| 251 | void increment() |
| 252 | { |
| 253 | typename base_t::reference val = *(this->base()); |
| 254 | if (val == '\n') { |
| 255 | ++this->base_reference(); |
| 256 | this->next_line(_pos); |
| 257 | static_cast<main_iter_t &>(*this).newline(); |
| 258 | } |
| 259 | else if ( val == '\r') { |
| 260 | ++this->base_reference(); |
| 261 | if (this->base_reference() == _end || *(this->base()) != '\n') |
| 262 | { |
| 263 | this->next_line(_pos); |
| 264 | static_cast<main_iter_t &>(*this).newline(); |
| 265 | } |
| 266 | } |
| 267 | else if (val == '\t') { |
| 268 | this->tabulation(_pos); |
| 269 | ++this->base_reference(); |
| 270 | } |
| 271 | else { |
| 272 | this->next_char(_pos); |
| 273 | ++this->base_reference(); |
| 274 | } |
| 275 | |
| 276 | // The iterator is at the end only if it's the same |
| 277 | // of the |
| 278 | _isend = (this->base_reference() == _end); |
| 279 | } |
| 280 | |
| 281 | template < |
| 282 | typename OtherDerivedT, typename OtherIteratorT, |
| 283 | typename V, typename C, typename R, typename D |
| 284 | > |
| 285 | bool equal(iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D> |
| 286 | const &x) const |
| 287 | { |
| 288 | OtherDerivedT const &rhs = static_cast<OtherDerivedT const &>(x); |
| 289 | bool x_is_end = rhs._isend; |
| 290 | |
| 291 | return (_isend == x_is_end) && (_isend || this->base() == rhs.base()); |
| 292 | } |
| 293 | |
| 294 | protected: |
| 295 | |
| 296 | void newline() |
| 297 | {} |
| 298 | |
| 299 | ForwardIteratorT _end; |
| 300 | PositionT _pos; |
| 301 | bool _isend; |
| 302 | }; |
| 303 | |
| 304 | #endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 |
| 305 | |
| 306 | /////////////////////////////////////////////////////////////////////////////// |
| 307 | // |
| 308 | // position_iterator2 |
| 309 | // |
| 310 | // Equivalent to position_iterator, but it is able to extract the current |
| 311 | // line into a string. This is very handy for error reports. |
| 312 | // |
| 313 | // Notice that the footprint of this class is higher than position_iterator, |
| 314 | // (how much depends on how bulky the underlying iterator is), so it should |
| 315 | // be used only if necessary. |
| 316 | // |
| 317 | /////////////////////////////////////////////////////////////////////////////// |
| 318 | |
| 319 | template |
| 320 | < |
| 321 | typename ForwardIteratorT, |
| 322 | typename PositionT |
| 323 | > |
| 324 | class position_iterator2 |
| 325 | : public position_iterator |
| 326 | < |
| 327 | ForwardIteratorT, |
| 328 | PositionT, |
| 329 | position_iterator2<ForwardIteratorT, PositionT> |
| 330 | > |
| 331 | { |
| 332 | typedef position_iterator |
| 333 | < |
| 334 | ForwardIteratorT, |
| 335 | PositionT, |
| 336 | position_iterator2<ForwardIteratorT, PositionT> // JDG 4-15-03 |
| 337 | > base_t; |
| 338 | |
| 339 | public: |
| 340 | typedef typename base_t::value_type value_type; |
| 341 | typedef PositionT position_t; |
| 342 | |
| 343 | position_iterator2() |
| 344 | {} |
| 345 | |
| 346 | position_iterator2( |
| 347 | const ForwardIteratorT& begin, |
| 348 | const ForwardIteratorT& end): |
| 349 | base_t(begin, end), |
| 350 | _startline(begin) |
| 351 | {} |
| 352 | |
| 353 | template <typename FileNameT> |
| 354 | position_iterator2( |
| 355 | const ForwardIteratorT& begin, |
| 356 | const ForwardIteratorT& end, |
| 357 | FileNameT file): |
| 358 | base_t(begin, end, file), |
| 359 | _startline(begin) |
| 360 | {} |
| 361 | |
| 362 | template <typename FileNameT, typename LineT> |
| 363 | position_iterator2( |
| 364 | const ForwardIteratorT& begin, |
| 365 | const ForwardIteratorT& end, |
| 366 | FileNameT file, LineT line): |
| 367 | base_t(begin, end, file, line), |
| 368 | _startline(begin) |
| 369 | {} |
| 370 | |
| 371 | template <typename FileNameT, typename LineT, typename ColumnT> |
| 372 | position_iterator2( |
| 373 | const ForwardIteratorT& begin, |
| 374 | const ForwardIteratorT& end, |
| 375 | FileNameT file, LineT line, ColumnT column): |
| 376 | base_t(begin, end, file, line, column), |
| 377 | _startline(begin) |
| 378 | {} |
| 379 | |
| 380 | position_iterator2( |
| 381 | const ForwardIteratorT& begin, |
| 382 | const ForwardIteratorT& end, |
| 383 | const PositionT& pos): |
| 384 | base_t(begin, end, pos), |
| 385 | _startline(begin) |
| 386 | {} |
| 387 | |
| 388 | position_iterator2(const position_iterator2& iter) |
| 389 | : base_t(iter), _startline(iter._startline) |
| 390 | {} |
| 391 | |
| 392 | position_iterator2& operator=(const position_iterator2& iter) |
| 393 | { |
| 394 | base_t::operator=(iter); |
| 395 | _startline = iter._startline; |
| 396 | return *this; |
| 397 | } |
| 398 | |
| 399 | ForwardIteratorT get_currentline_begin() const |
| 400 | { return _startline; } |
| 401 | |
| 402 | ForwardIteratorT get_currentline_end() const |
| 403 | { return get_endline(); } |
| 404 | |
| 405 | std::basic_string<value_type> get_currentline() const |
| 406 | { |
| 407 | return std::basic_string<value_type> |
| 408 | (get_currentline_begin(), get_currentline_end()); |
| 409 | } |
| 410 | |
| 411 | protected: |
| 412 | ForwardIteratorT _startline; |
| 413 | |
| 414 | friend class position_iterator<ForwardIteratorT, PositionT, |
| 415 | position_iterator2<ForwardIteratorT, PositionT> >; |
| 416 | |
| 417 | ForwardIteratorT get_endline() const |
| 418 | { |
| 419 | ForwardIteratorT endline = _startline; |
| 420 | while (endline != this->_end && *endline != '\r' && *endline != '\n') |
| 421 | { |
| 422 | ++endline; |
| 423 | } |
| 424 | return endline; |
| 425 | } |
| 426 | |
| 427 | void newline() |
| 428 | { _startline = this->base(); } |
| 429 | }; |
| 430 | |
| 431 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
| 432 | |
| 433 | }} // namespace BOOST_SPIRIT_CLASSIC_NS |
| 434 | |
| 435 | #endif |
| 436 | |