| /*============================================================================= |
| Boost.Wave: A Standard compliant C++ preprocessor library |
| |
| Copyright (c) 2001 Daniel C. Nuffer |
| Copyright (c) 2001-2010 Hartmut Kaiser. |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| TODO: |
| It also may be necessary to add $ to identifiers, for asm. |
| handle errors better. |
| have some easier way to parse strings instead of files (done) |
| =============================================================================*/ |
| |
| #define BOOST_WAVE_SOURCE 1 |
| |
| // disable stupid compiler warnings |
| #include <boost/config/warning_disable.hpp> |
| |
| #include <ctime> |
| #include <cstdlib> |
| #include <cstdio> |
| #include <cstring> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| #include <boost/wave/wave_config.hpp> // configuration data |
| |
| #if defined(BOOST_HAS_UNISTD_H) |
| #include <unistd.h> |
| #else |
| #include <io.h> |
| #endif |
| |
| #include <boost/assert.hpp> |
| #include <boost/detail/workaround.hpp> |
| |
| #include <boost/wave/token_ids.hpp> |
| #include <boost/wave/cpplexer/re2clex/aq.hpp> |
| #include <boost/wave/cpplexer/re2clex/scanner.hpp> |
| #include <boost/wave/cpplexer/re2clex/cpp_re.hpp> |
| #include <boost/wave/cpplexer/cpplexer_exceptions.hpp> |
| |
| // this must occur after all of the includes and before any code appears |
| #ifdef BOOST_HAS_ABI_HEADERS |
| #include BOOST_ABI_PREFIX |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| #if defined(BOOST_MSVC) |
| #pragma warning (disable: 4101) // 'foo' : unreferenced local variable |
| #pragma warning (disable: 4102) // 'foo' : unreferenced label |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| #define BOOST_WAVE_BSIZE 196608 |
| |
| #define YYCTYPE uchar |
| #define YYCURSOR cursor |
| #define YYLIMIT limit |
| #define YYMARKER marker |
| #define YYFILL(n) \ |
| { \ |
| cursor = uchar_wrapper(fill(s, cursor), cursor.column); \ |
| limit = uchar_wrapper (s->lim); \ |
| } \ |
| /**/ |
| |
| #include <iostream> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| #define BOOST_WAVE_UPDATE_CURSOR() \ |
| { \ |
| s->line += count_backslash_newlines(s, cursor); \ |
| s->curr_column = cursor.column; \ |
| s->cur = cursor; \ |
| s->lim = limit; \ |
| s->ptr = marker; \ |
| } \ |
| /**/ |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| #define BOOST_WAVE_RET(i) \ |
| { \ |
| BOOST_WAVE_UPDATE_CURSOR() \ |
| if (s->cur > s->lim) \ |
| return T_EOF; /* may happen for empty files */ \ |
| return (i); \ |
| } \ |
| /**/ |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { |
| namespace wave { |
| namespace cpplexer { |
| namespace re2clex { |
| |
| #define RE2C_ASSERT BOOST_ASSERT |
| |
| int get_one_char(Scanner *s) |
| { |
| if (0 != s->act) { |
| RE2C_ASSERT(s->first != 0 && s->last != 0); |
| RE2C_ASSERT(s->first <= s->act && s->act <= s->last); |
| if (s->act < s->last) |
| return *(s->act)++; |
| } |
| return -1; |
| } |
| |
| std::ptrdiff_t rewind_stream (Scanner *s, int cnt) |
| { |
| if (0 != s->act) { |
| RE2C_ASSERT(s->first != 0 && s->last != 0); |
| s->act += cnt; |
| RE2C_ASSERT(s->first <= s->act && s->act <= s->last); |
| return s->act - s->first; |
| } |
| return 0; |
| } |
| |
| std::size_t get_first_eol_offset(Scanner* s) |
| { |
| if (!AQ_EMPTY(s->eol_offsets)) |
| { |
| return s->eol_offsets->queue[s->eol_offsets->head]; |
| } |
| else |
| { |
| return (unsigned int)-1; |
| } |
| } |
| |
| void adjust_eol_offsets(Scanner* s, std::size_t adjustment) |
| { |
| aq_queue q; |
| std::size_t i; |
| |
| if (!s->eol_offsets) |
| s->eol_offsets = aq_create(); |
| |
| q = s->eol_offsets; |
| |
| if (AQ_EMPTY(q)) |
| return; |
| |
| i = q->head; |
| while (i != q->tail) |
| { |
| if (adjustment > q->queue[i]) |
| q->queue[i] = 0; |
| else |
| q->queue[i] -= adjustment; |
| ++i; |
| if (i == q->max_size) |
| i = 0; |
| } |
| if (adjustment > q->queue[i]) |
| q->queue[i] = 0; |
| else |
| q->queue[i] -= adjustment; |
| } |
| |
| int count_backslash_newlines(Scanner *s, uchar *cursor) |
| { |
| std::size_t diff, offset; |
| int skipped = 0; |
| |
| /* figure out how many backslash-newlines skipped over unknowingly. */ |
| diff = cursor - s->bot; |
| offset = get_first_eol_offset(s); |
| while (offset <= diff && offset != (unsigned int)-1) |
| { |
| skipped++; |
| aq_pop(s->eol_offsets); |
| offset = get_first_eol_offset(s); |
| } |
| return skipped; |
| } |
| |
| bool is_backslash(uchar *p, uchar *end, int &len) |
| { |
| if (*p == '\\') { |
| len = 1; |
| return true; |
| } |
| else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { |
| len = 3; |
| return true; |
| } |
| return false; |
| } |
| |
| uchar *fill(Scanner *s, uchar *cursor) |
| { |
| using namespace std; // some systems have memcpy etc. in namespace std |
| if(!s->eof) |
| { |
| uchar* p; |
| std::ptrdiff_t cnt = s->tok - s->bot; |
| if(cnt) |
| { |
| if (NULL == s->lim) |
| s->lim = s->top; |
| memmove(s->bot, s->tok, s->lim - s->tok); |
| s->tok = s->cur = s->bot; |
| s->ptr -= cnt; |
| cursor -= cnt; |
| s->lim -= cnt; |
| adjust_eol_offsets(s, cnt); |
| } |
| |
| if((s->top - s->lim) < BOOST_WAVE_BSIZE) |
| { |
| uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BOOST_WAVE_BSIZE)*sizeof(uchar)); |
| if (buf == 0) |
| { |
| using namespace std; // some systems have printf in std |
| if (0 != s->error_proc) { |
| (*s->error_proc)(s, lexing_exception::unexpected_error, |
| "Out of memory!"); |
| } |
| else |
| printf("Out of memory!\n"); |
| |
| /* get the scanner to stop */ |
| *cursor = 0; |
| return cursor; |
| } |
| |
| memmove(buf, s->tok, s->lim - s->tok); |
| s->tok = s->cur = buf; |
| s->ptr = &buf[s->ptr - s->bot]; |
| cursor = &buf[cursor - s->bot]; |
| s->lim = &buf[s->lim - s->bot]; |
| s->top = &s->lim[BOOST_WAVE_BSIZE]; |
| free(s->bot); |
| s->bot = buf; |
| } |
| |
| if (s->act != 0) { |
| cnt = s->last - s->act; |
| if (cnt > BOOST_WAVE_BSIZE) |
| cnt = BOOST_WAVE_BSIZE; |
| memmove(s->lim, s->act, cnt); |
| s->act += cnt; |
| if (cnt != BOOST_WAVE_BSIZE) |
| { |
| s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; |
| } |
| } |
| |
| /* backslash-newline erasing time */ |
| |
| /* first scan for backslash-newline and erase them */ |
| for (p = s->lim; p < s->lim + cnt - 2; ++p) |
| { |
| int len = 0; |
| if (is_backslash(p, s->lim + cnt, len)) |
| { |
| if (*(p+len) == '\n') |
| { |
| int offset = len + 1; |
| memmove(p, p + offset, s->lim + cnt - p - offset); |
| cnt -= offset; |
| --p; |
| aq_enqueue(s->eol_offsets, p - s->bot + 1); |
| } |
| else if (*(p+len) == '\r') |
| { |
| if (*(p+len+1) == '\n') |
| { |
| int offset = len + 2; |
| memmove(p, p + offset, s->lim + cnt - p - offset); |
| cnt -= offset; |
| --p; |
| } |
| else |
| { |
| int offset = len + 1; |
| memmove(p, p + offset, s->lim + cnt - p - offset); |
| cnt -= offset; |
| --p; |
| } |
| aq_enqueue(s->eol_offsets, p - s->bot + 1); |
| } |
| } |
| } |
| |
| /* FIXME: the following code should be fixed to recognize correctly the |
| trigraph backslash token */ |
| |
| /* check to see if what we just read ends in a backslash */ |
| if (cnt >= 2) |
| { |
| uchar last = s->lim[cnt-1]; |
| uchar last2 = s->lim[cnt-2]; |
| /* check \ EOB */ |
| if (last == '\\') |
| { |
| int next = get_one_char(s); |
| /* check for \ \n or \ \r or \ \r \n straddling the border */ |
| if (next == '\n') |
| { |
| --cnt; /* chop the final \, we've already read the \n. */ |
| aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); |
| } |
| else if (next == '\r') |
| { |
| int next2 = get_one_char(s); |
| if (next2 == '\n') |
| { |
| --cnt; /* skip the backslash */ |
| } |
| else |
| { |
| /* rewind one, and skip one char */ |
| rewind_stream(s, -1); |
| --cnt; |
| } |
| aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); |
| } |
| else if (next != -1) /* -1 means end of file */ |
| { |
| /* next was something else, so rewind the stream */ |
| rewind_stream(s, -1); |
| } |
| } |
| /* check \ \r EOB */ |
| else if (last == '\r' && last2 == '\\') |
| { |
| int next = get_one_char(s); |
| if (next == '\n') |
| { |
| cnt -= 2; /* skip the \ \r */ |
| } |
| else |
| { |
| /* rewind one, and skip two chars */ |
| rewind_stream(s, -1); |
| cnt -= 2; |
| } |
| aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); |
| } |
| /* check \ \n EOB */ |
| else if (last == '\n' && last2 == '\\') |
| { |
| cnt -= 2; |
| aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); |
| } |
| } |
| |
| s->lim += cnt; |
| if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ |
| { |
| s->eof = s->lim; |
| *(s->eof)++ = '\0'; |
| } |
| } |
| return cursor; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Special wrapper class holding the current cursor position |
| struct uchar_wrapper |
| { |
| uchar_wrapper (uchar *base_cursor, unsigned int column = 1) |
| : base_cursor(base_cursor), column(column) |
| {} |
| |
| uchar_wrapper& operator++() |
| { |
| ++base_cursor; |
| ++column; |
| return *this; |
| } |
| |
| uchar_wrapper& operator--() |
| { |
| --base_cursor; |
| --column; |
| return *this; |
| } |
| |
| uchar operator* () const |
| { |
| return *base_cursor; |
| } |
| |
| operator uchar *() const |
| { |
| return base_cursor; |
| } |
| |
| friend std::ptrdiff_t |
| operator- (uchar_wrapper const& lhs, uchar_wrapper const& rhs) |
| { |
| return lhs.base_cursor - rhs.base_cursor; |
| } |
| |
| uchar *base_cursor; |
| unsigned int column; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| boost::wave::token_id scan(Scanner *s) |
| { |
| BOOST_ASSERT(0 != s->error_proc); // error handler must be given |
| |
| uchar_wrapper cursor (s->tok = s->cur, s->column = s->curr_column); |
| uchar_wrapper marker (s->ptr); |
| uchar_wrapper limit (s->lim); |
| |
| // include the correct Re2C token definition rules |
| #if BOOST_WAVE_USE_STRICT_LEXER != 0 |
| #include "strict_cpp_re.inc" |
| #else |
| #include "cpp_re.inc" |
| #endif |
| |
| } /* end of scan */ |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| } // namespace re2clex |
| } // namespace cpplexer |
| } // namespace wave |
| } // namespace boost |
| |
| #undef BOOST_WAVE_RET |
| #undef BOOST_WAVE_BSIZE |
| #undef YYCTYPE |
| #undef YYCURSOR |
| #undef YYLIMIT |
| #undef YYMARKER |
| #undef YYFILL |
| |
| // the suffix header occurs after all of the code |
| #ifdef BOOST_HAS_ABI_HEADERS |
| #include BOOST_ABI_SUFFIX |
| #endif |
| |