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 file_position_without_column_baseboost::spirit::file_position_without_column_base36 file_position_without_column_base(String const& file_ = String(), 37 int line_ = 1): 38 file (file_), 39 line (line_) 40 {} 41 operator ==boost::spirit::file_position_without_column_base42 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 file_position_baseboost::spirit::file_position_base58 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 operator ==boost::spirit::file_position_base64 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 position_iterator2()343 position_iterator2() 344 {} 345 position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end)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> position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file)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> position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file,LineT line)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> position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file,LineT line,ColumnT column)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 position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,const PositionT & pos)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 position_iterator2(const position_iterator2 & iter)388 position_iterator2(const position_iterator2& iter) 389 : base_t(iter), _startline(iter._startline) 390 {} 391 operator =(const position_iterator2 & iter)392 position_iterator2& operator=(const position_iterator2& iter) 393 { 394 base_t::operator=(iter); 395 _startline = iter._startline; 396 return *this; 397 } 398 get_currentline_begin() const399 ForwardIteratorT get_currentline_begin() const 400 { return _startline; } 401 get_currentline_end() const402 ForwardIteratorT get_currentline_end() const 403 { return get_endline(); } 404 get_currentline() const405 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 get_endline() const417 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 newline()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