1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
4 Sample: Re2C based IDL lexer
8 Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
9 Software License, Version 1.0. (See accompanying file
10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 =============================================================================*/
13 #if !defined(BOOST_IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED)
14 #define BOOST_IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED
19 #include <boost/config.hpp>
21 #if defined(BOOST_HAS_UNISTD_H)
27 #include <boost/assert.hpp>
28 #include <boost/detail/workaround.hpp>
30 // reuse the token ids and re2c helper functions from the default C++ lexer
31 #include <boost/wave/token_ids.hpp>
32 #include <boost/wave/cpplexer/re2clex/aq.hpp>
33 #include <boost/wave/cpplexer/re2clex/scanner.hpp>
34 #include <boost/wave/cpplexer/cpplexer_exceptions.hpp>
36 #define BOOST_WAVE_BSIZE 196608
38 #define RE2C_ASSERT BOOST_ASSERT
40 #if defined(_MSC_VER) && !defined(__COMO__)
41 #pragma warning (disable: 4101) // 'foo' : unreferenced local variable
42 #pragma warning (disable: 4102) // 'foo' : unreferenced label
46 #define YYCURSOR cursor
47 #define YYLIMIT s->lim
48 #define YYMARKER s->ptr
49 #define YYFILL(n) {cursor = fill(s, cursor);}
51 //#define BOOST_WAVE_RET(i) {s->cur = cursor; return (i);}
52 #define BOOST_WAVE_RET(i) \
54 s->line += count_backslash_newlines(s, cursor); \
62 ///////////////////////////////////////////////////////////////////////////////
68 template<typename Iterator>
70 get_one_char(boost::wave::cpplexer::re2clex::Scanner<Iterator> *s)
72 using namespace boost::wave::cpplexer::re2clex;
73 RE2C_ASSERT(s->first <= s->act && s->act <= s->last);
79 template<typename Iterator>
81 rewind_stream (boost::wave::cpplexer::re2clex::Scanner<Iterator> *s, int cnt)
84 RE2C_ASSERT(s->first <= s->act && s->act <= s->last);
85 return s->act - s->first;
88 template<typename Iterator>
90 get_first_eol_offset(boost::wave::cpplexer::re2clex::Scanner<Iterator>* s)
92 if (!AQ_EMPTY(s->eol_offsets))
94 return s->eol_offsets->queue[s->eol_offsets->head];
98 return (unsigned int)-1;
102 template<typename Iterator>
104 adjust_eol_offsets(boost::wave::cpplexer::re2clex::Scanner<Iterator>* s,
105 std::size_t adjustment)
107 boost::wave::cpplexer::re2clex::aq_queue q;
111 s->eol_offsets = boost::wave::cpplexer::re2clex::aq_create();
121 if (adjustment > q->queue[i])
124 q->queue[i] -= adjustment;
126 if (i == q->max_size)
129 if (adjustment > q->queue[i])
132 q->queue[i] -= adjustment;
135 template<typename Iterator>
137 count_backslash_newlines(boost::wave::cpplexer::re2clex::Scanner<Iterator> *s,
138 boost::wave::cpplexer::re2clex::uchar *cursor)
140 using namespace boost::wave::cpplexer::re2clex;
142 std::size_t diff, offset;
145 /* figure out how many backslash-newlines skipped over unknowingly. */
146 diff = cursor - s->bot;
147 offset = get_first_eol_offset(s);
148 while (offset <= diff && offset != (unsigned int)-1)
151 boost::wave::cpplexer::re2clex::aq_pop(s->eol_offsets);
152 offset = get_first_eol_offset(s);
159 boost::wave::cpplexer::re2clex::uchar *p,
160 boost::wave::cpplexer::re2clex::uchar *end, int &len);
162 template<typename Iterator>
163 boost::wave::cpplexer::re2clex::uchar *
164 fill(boost::wave::cpplexer::re2clex::Scanner<Iterator> *s,
165 boost::wave::cpplexer::re2clex::uchar *cursor)
167 using namespace std; // some systems have memcpy etc. in namespace std
168 using namespace boost::wave::cpplexer::re2clex;
173 std::ptrdiff_t cnt = s->tok - s->bot;
176 memcpy(s->bot, s->tok, s->lim - s->tok);
181 adjust_eol_offsets(s, cnt);
184 if((s->top - s->lim) < BOOST_WAVE_BSIZE)
186 uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BOOST_WAVE_BSIZE)*sizeof(uchar));
189 using namespace std; // some systems have printf in std
190 if (0 != s->error_proc) {
192 cpplexer::lexing_exception::unexpected_error,
196 printf("Out of memory!\n");
198 /* get the scanner to stop */
203 memcpy(buf, s->tok, s->lim - s->tok);
205 s->ptr = &buf[s->ptr - s->bot];
206 cursor = &buf[cursor - s->bot];
207 s->lim = &buf[s->lim - s->bot];
208 s->top = &s->lim[BOOST_WAVE_BSIZE];
213 cnt = std::distance(s->act, s->last);
214 if (cnt > BOOST_WAVE_BSIZE)
215 cnt = BOOST_WAVE_BSIZE;
216 uchar * dst = s->lim;
217 for (std::ptrdiff_t idx = 0; idx < cnt; ++idx)
221 if (cnt != BOOST_WAVE_BSIZE) {
222 s->eof = &s->lim[cnt];
226 /* backslash-newline erasing time */
228 /* first scan for backslash-newline and erase them */
229 for (p = s->lim; p < s->lim + cnt - 2; ++p)
232 if (is_backslash(p, s->lim + cnt, len))
234 if (*(p+len) == '\n')
236 int offset = len + 1;
237 memmove(p, p + offset, s->lim + cnt - p - offset);
240 aq_enqueue(s->eol_offsets, p - s->bot + 1);
242 else if (*(p+len) == '\r')
244 if (*(p+len+1) == '\n')
246 int offset = len + 2;
247 memmove(p, p + offset, s->lim + cnt - p - offset);
253 int offset = len + 1;
254 memmove(p, p + offset, s->lim + cnt - p - offset);
258 aq_enqueue(s->eol_offsets, p - s->bot + 1);
263 /* FIXME: the following code should be fixed to recognize correctly the
264 trigraph backslash token */
266 /* check to see if what we just read ends in a backslash */
269 uchar last = s->lim[cnt-1];
270 uchar last2 = s->lim[cnt-2];
274 int next = get_one_char(s);
275 /* check for \ \n or \ \r or \ \r \n straddling the border */
278 --cnt; /* chop the final \, we've already read the \n. */
279 boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets,
280 cnt + (s->lim - s->bot));
282 else if (next == '\r')
284 int next2 = get_one_char(s);
287 --cnt; /* skip the backslash */
291 /* rewind one, and skip one char */
292 rewind_stream(s, -1);
295 boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets,
296 cnt + (s->lim - s->bot));
298 else if (next != -1) /* -1 means end of file */
300 /* next was something else, so rewind the stream */
301 rewind_stream(s, -1);
305 else if (last == '\r' && last2 == '\\')
307 int next = get_one_char(s);
310 cnt -= 2; /* skip the \ \r */
314 /* rewind one, and skip two chars */
315 rewind_stream(s, -1);
318 boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets,
319 cnt + (s->lim - s->bot));
322 else if (last == '\n' && last2 == '\\')
325 boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets,
326 cnt + (s->lim - s->bot));
331 if (s->eof) /* eof needs adjusting if we erased backslash-newlines */
340 ///////////////////////////////////////////////////////////////////////////////
341 // The scanner function to call whenever a new token is requested
342 template<typename Iterator>
343 BOOST_WAVE_DECL boost::wave::token_id scan(
344 boost::wave::cpplexer::re2clex::Scanner<Iterator> *s)
347 using namespace boost::wave::cpplexer::re2clex;
349 uchar *cursor = s->tok = s->cur;
356 ///////////////////////////////////////////////////////////////////////////////
357 } // namespace re2clex
358 } // namespace idllexer
364 #endif // !defined(BOOST_IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED)