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