• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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