Improve vacpp support.
[boost.git] / boost / libs / wave / src / cpplexer / re2clex / cpp_re.cpp
blob3cf33a857dd8de36887284ff1ebd6bb8c0f041bf
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
4 Copyright (c) 2001 Daniel C. Nuffer
5 Copyright (c) 2001-2007 Hartmut Kaiser.
6 Distributed under the Boost Software License, Version 1.0. (See accompanying
7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 TODO:
10 It also may be necessary to add $ to identifiers, for asm.
11 handle errors better.
12 have some easier way to parse strings instead of files (done)
13 =============================================================================*/
15 #define BOOST_WAVE_SOURCE 1
16 #include <ctime>
17 #include <cstdlib>
18 #include <cstdio>
19 #include <cstring>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
24 #include <boost/wave/wave_config.hpp> // configuration data
26 #if defined(BOOST_HAS_UNISTD_H)
27 #include <unistd.h>
28 #else
29 #include <io.h>
30 #endif
32 #include <boost/assert.hpp>
33 #include <boost/detail/workaround.hpp>
35 #include <boost/wave/token_ids.hpp>
36 #include <boost/wave/cpplexer/re2clex/aq.hpp>
37 #include <boost/wave/cpplexer/re2clex/scanner.hpp>
38 #include <boost/wave/cpplexer/re2clex/cpp_re.hpp>
40 // this must occur after all of the includes and before any code appears
41 #ifdef BOOST_HAS_ABI_HEADERS
42 #include BOOST_ABI_PREFIX
43 #endif
45 ///////////////////////////////////////////////////////////////////////////////
46 #if defined(BOOST_MSVC)
47 #pragma warning (disable: 4101) // 'foo' : unreferenced local variable
48 #pragma warning (disable: 4102) // 'foo' : unreferenced label
49 #endif
51 ///////////////////////////////////////////////////////////////////////////////
52 #define BOOST_WAVE_BSIZE 196608
54 #define YYCTYPE uchar
55 #define YYCURSOR cursor
56 #define YYLIMIT limit
57 #define YYMARKER marker
58 #define YYFILL(n) \
59 { \
60 cursor = uchar_wrapper(fill(s, cursor), cursor.column); \
61 limit = uchar_wrapper (s->lim); \
62 } \
63 /**/
65 #include <iostream>
67 ///////////////////////////////////////////////////////////////////////////////
68 #define BOOST_WAVE_UPDATE_CURSOR() \
69 { \
70 s->line += count_backslash_newlines(s, cursor); \
71 s->curr_column = cursor.column; \
72 s->cur = cursor; \
73 s->lim = limit; \
74 s->ptr = marker; \
75 } \
76 /**/
78 ///////////////////////////////////////////////////////////////////////////////
79 #define BOOST_WAVE_RET(i) \
80 { \
81 BOOST_WAVE_UPDATE_CURSOR() \
82 if (s->cur > s->lim) \
83 return T_EOF; /* may happen for empty files */ \
84 return (i); \
85 } \
86 /**/
88 ///////////////////////////////////////////////////////////////////////////////
89 namespace boost {
90 namespace wave {
91 namespace cpplexer {
92 namespace re2clex {
94 #define RE2C_ASSERT BOOST_ASSERT
96 int get_one_char(Scanner *s)
98 if (0 != s->act) {
99 RE2C_ASSERT(s->first != 0 && s->last != 0);
100 RE2C_ASSERT(s->first <= s->act && s->act <= s->last);
101 if (s->act < s->last)
102 return *(s->act)++;
104 return -1;
107 std::ptrdiff_t rewind_stream (Scanner *s, int cnt)
109 if (0 != s->act) {
110 RE2C_ASSERT(s->first != 0 && s->last != 0);
111 s->act += cnt;
112 RE2C_ASSERT(s->first <= s->act && s->act <= s->last);
113 return s->act - s->first;
115 return 0;
118 std::size_t get_first_eol_offset(Scanner* s)
120 if (!AQ_EMPTY(s->eol_offsets))
122 return s->eol_offsets->queue[s->eol_offsets->head];
124 else
126 return (unsigned int)-1;
130 void adjust_eol_offsets(Scanner* s, std::size_t adjustment)
132 aq_queue q;
133 std::size_t i;
135 if (!s->eol_offsets)
136 s->eol_offsets = aq_create();
138 q = s->eol_offsets;
140 if (AQ_EMPTY(q))
141 return;
143 i = q->head;
144 while (i != q->tail)
146 if (adjustment > q->queue[i])
147 q->queue[i] = 0;
148 else
149 q->queue[i] -= adjustment;
150 ++i;
151 if (i == q->max_size)
152 i = 0;
154 if (adjustment > q->queue[i])
155 q->queue[i] = 0;
156 else
157 q->queue[i] -= adjustment;
160 int count_backslash_newlines(Scanner *s, uchar *cursor)
162 std::size_t diff, offset;
163 int skipped = 0;
165 /* figure out how many backslash-newlines skipped over unknowingly. */
166 diff = cursor - s->bot;
167 offset = get_first_eol_offset(s);
168 while (offset <= diff && offset != (unsigned int)-1)
170 skipped++;
171 aq_pop(s->eol_offsets);
172 offset = get_first_eol_offset(s);
174 return skipped;
177 bool is_backslash(uchar *p, uchar *end, int &len)
179 if (*p == '\\') {
180 len = 1;
181 return true;
183 else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) {
184 len = 3;
185 return true;
187 return false;
190 uchar *fill(Scanner *s, uchar *cursor)
192 using namespace std; // some systems have memcpy etc. in namespace std
193 if(!s->eof)
195 uchar* p;
196 std::ptrdiff_t cnt = s->tok - s->bot;
197 if(cnt)
199 if (NULL == s->lim)
200 s->lim = s->top;
201 memmove(s->bot, s->tok, s->lim - s->tok);
202 s->tok = s->cur = s->bot;
203 s->ptr -= cnt;
204 cursor -= cnt;
205 s->lim -= cnt;
206 adjust_eol_offsets(s, cnt);
209 if((s->top - s->lim) < BOOST_WAVE_BSIZE)
211 uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BOOST_WAVE_BSIZE)*sizeof(uchar));
212 if (buf == 0)
214 using namespace std; // some systems have printf in std
215 if (0 != s->error_proc)
216 (*s->error_proc)(s, "Out of memory!");
217 else
218 printf("Out of memory!\n");
220 /* get the scanner to stop */
221 *cursor = 0;
222 return cursor;
225 memmove(buf, s->tok, s->lim - s->tok);
226 s->tok = s->cur = buf;
227 s->ptr = &buf[s->ptr - s->bot];
228 cursor = &buf[cursor - s->bot];
229 s->lim = &buf[s->lim - s->bot];
230 s->top = &s->lim[BOOST_WAVE_BSIZE];
231 free(s->bot);
232 s->bot = buf;
235 if (s->act != 0) {
236 cnt = s->last - s->act;
237 if (cnt > BOOST_WAVE_BSIZE)
238 cnt = BOOST_WAVE_BSIZE;
239 memmove(s->lim, s->act, cnt);
240 s->act += cnt;
241 if (cnt != BOOST_WAVE_BSIZE)
243 s->eof = &s->lim[cnt]; *(s->eof)++ = '\0';
247 /* backslash-newline erasing time */
249 /* first scan for backslash-newline and erase them */
250 for (p = s->lim; p < s->lim + cnt - 2; ++p)
252 int len = 0;
253 if (is_backslash(p, s->lim + cnt, len))
255 if (*(p+len) == '\n')
257 int offset = len + 1;
258 memmove(p, p + offset, s->lim + cnt - p - offset);
259 cnt -= offset;
260 --p;
261 aq_enqueue(s->eol_offsets, p - s->bot + 1);
263 else if (*(p+len) == '\r')
265 if (*(p+len+1) == '\n')
267 int offset = len + 2;
268 memmove(p, p + offset, s->lim + cnt - p - offset);
269 cnt -= offset;
270 --p;
272 else
274 int offset = len + 1;
275 memmove(p, p + offset, s->lim + cnt - p - offset);
276 cnt -= offset;
277 --p;
279 aq_enqueue(s->eol_offsets, p - s->bot + 1);
284 /* FIXME: the following code should be fixed to recognize correctly the
285 trigraph backslash token */
287 /* check to see if what we just read ends in a backslash */
288 if (cnt >= 2)
290 uchar last = s->lim[cnt-1];
291 uchar last2 = s->lim[cnt-2];
292 /* check \ EOB */
293 if (last == '\\')
295 int next = get_one_char(s);
296 /* check for \ \n or \ \r or \ \r \n straddling the border */
297 if (next == '\n')
299 --cnt; /* chop the final \, we've already read the \n. */
300 aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot));
302 else if (next == '\r')
304 int next2 = get_one_char(s);
305 if (next2 == '\n')
307 --cnt; /* skip the backslash */
309 else
311 /* rewind one, and skip one char */
312 rewind_stream(s, -1);
313 --cnt;
315 aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot));
317 else if (next != -1) /* -1 means end of file */
319 /* next was something else, so rewind the stream */
320 rewind_stream(s, -1);
323 /* check \ \r EOB */
324 else if (last == '\r' && last2 == '\\')
326 int next = get_one_char(s);
327 if (next == '\n')
329 cnt -= 2; /* skip the \ \r */
331 else
333 /* rewind one, and skip two chars */
334 rewind_stream(s, -1);
335 cnt -= 2;
337 aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot));
339 /* check \ \n EOB */
340 else if (last == '\n' && last2 == '\\')
342 cnt -= 2;
343 aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot));
347 s->lim += cnt;
348 if (s->eof) /* eof needs adjusting if we erased backslash-newlines */
350 s->eof = s->lim;
351 *(s->eof)++ = '\0';
354 return cursor;
357 ///////////////////////////////////////////////////////////////////////////////
358 // Special wrapper class holding the current cursor position
359 struct uchar_wrapper
361 uchar_wrapper (uchar *base_cursor, unsigned int column = 1)
362 : base_cursor(base_cursor), column(column)
365 uchar_wrapper& operator++()
367 ++base_cursor;
368 ++column;
369 return *this;
372 uchar_wrapper& operator--()
374 --base_cursor;
375 --column;
376 return *this;
379 uchar operator* () const
381 return *base_cursor;
384 operator uchar *() const
386 return base_cursor;
389 friend int operator- (uchar_wrapper const& lhs, uchar_wrapper const& rhs)
391 return lhs.base_cursor - rhs.base_cursor;
394 uchar *base_cursor;
395 unsigned int column;
398 ///////////////////////////////////////////////////////////////////////////////
399 boost::wave::token_id scan(Scanner *s)
401 BOOST_ASSERT(0 != s->error_proc); // error handler must be given
403 uchar_wrapper cursor (s->tok = s->cur, s->column = s->curr_column);
404 uchar_wrapper marker (s->ptr);
405 uchar_wrapper limit (s->lim);
407 // include the correct Re2C token definition rules
408 #if BOOST_WAVE_USE_STRICT_LEXER != 0
409 #include "strict_cpp_re.inc"
410 #else
411 #include "cpp_re.inc"
412 #endif
414 } /* end of scan */
416 ///////////////////////////////////////////////////////////////////////////////
417 } // namespace re2clex
418 } // namespace cpplexer
419 } // namespace wave
420 } // namespace boost
422 #undef BOOST_WAVE_RET
423 #undef BOOST_WAVE_BSIZE
424 #undef YYCTYPE
425 #undef YYCURSOR
426 #undef YYLIMIT
427 #undef YYMARKER
428 #undef YYFILL
430 // the suffix header occurs after all of the code
431 #ifdef BOOST_HAS_ABI_HEADERS
432 #include BOOST_ABI_SUFFIX
433 #endif