1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3 
4     Detect the need to insert a whitespace token into the output stream
5 
6     http://www.boost.org/
7 
8     Copyright (c) 2001-2012 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 =============================================================================*/
12 #if !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
13 #define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED
14 
15 #include <boost/wave/wave_config.hpp>
16 #include <boost/wave/token_ids.hpp>
17 
18 // this must occur after all of the includes and before any code appears
19 #ifdef BOOST_HAS_ABI_HEADERS
20 #include BOOST_ABI_PREFIX
21 #endif
22 
23 ///////////////////////////////////////////////////////////////////////////////
24 namespace boost {
25 namespace wave {
26 namespace util {
27 
28 namespace impl {
29 
30 // T_IDENTIFIER
31     template <typename StringT>
32     inline bool
would_form_universal_char(StringT const & value)33     would_form_universal_char (StringT const &value)
34     {
35         if ('u' != value[0] && 'U' != value[0])
36             return false;
37         if ('u' == value[0] && value.size() < 5)
38             return false;
39         if ('U' == value[0] && value.size() < 9)
40             return false;
41 
42     typename StringT::size_type pos =
43         value.find_first_not_of("0123456789abcdefABCDEF", 1);
44 
45         if (StringT::npos == pos ||
46             ('u' == value[0] && pos > 5) ||
47             ('U' == value[0] && pos > 9))
48         {
49             return true;        // would form an universal char
50         }
51         return false;
52     }
53     template <typename StringT>
54     inline bool
handle_identifier(boost::wave::token_id prev,boost::wave::token_id before,StringT const & value)55     handle_identifier(boost::wave::token_id prev,
56         boost::wave::token_id before, StringT const &value)
57     {
58         using namespace boost::wave;
59         switch (prev) {
60         case T_IDENTIFIER:
61         case T_NONREPLACABLE_IDENTIFIER:
62         case T_COMPL_ALT:
63         case T_OR_ALT:
64         case T_AND_ALT:
65         case T_NOT_ALT:
66         case T_XOR_ALT:
67         case T_ANDASSIGN_ALT:
68         case T_ORASSIGN_ALT:
69         case T_XORASSIGN_ALT:
70         case T_NOTEQUAL_ALT:
71         case T_FIXEDPOINTLIT:
72             return true;
73 
74         case T_FLOATLIT:
75         case T_INTLIT:
76         case T_PP_NUMBER:
77             return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E'));
78 
79          // avoid constructing universal characters (\u1234)
80         case T_UNKNOWN_UNIVERSALCHAR:
81             return would_form_universal_char(value);
82 
83         default:
84             break;
85         }
86         return false;
87     }
88 // T_INTLIT
89     inline bool
handle_intlit(boost::wave::token_id prev,boost::wave::token_id)90     handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/)
91     {
92         using namespace boost::wave;
93         switch (prev) {
94         case T_IDENTIFIER:
95         case T_NONREPLACABLE_IDENTIFIER:
96         case T_INTLIT:
97         case T_FLOATLIT:
98         case T_FIXEDPOINTLIT:
99         case T_PP_NUMBER:
100             return true;
101 
102         default:
103             break;
104         }
105         return false;
106     }
107 // T_FLOATLIT
108     inline bool
handle_floatlit(boost::wave::token_id prev,boost::wave::token_id)109     handle_floatlit(boost::wave::token_id prev,
110         boost::wave::token_id /*before*/)
111     {
112         using namespace boost::wave;
113         switch (prev) {
114         case T_IDENTIFIER:
115         case T_NONREPLACABLE_IDENTIFIER:
116         case T_INTLIT:
117         case T_FLOATLIT:
118         case T_FIXEDPOINTLIT:
119         case T_PP_NUMBER:
120             return true;
121 
122         default:
123             break;
124         }
125         return false;
126     }
127 // <% T_LEFTBRACE
128     inline bool
handle_alt_leftbrace(boost::wave::token_id prev,boost::wave::token_id)129     handle_alt_leftbrace(boost::wave::token_id prev,
130         boost::wave::token_id /*before*/)
131     {
132         using namespace boost::wave;
133         switch (prev) {
134         case T_LESS:        // <<%
135         case T_SHIFTLEFT:   // <<<%
136             return true;
137 
138         default:
139             break;
140         }
141         return false;
142     }
143 // <: T_LEFTBRACKET
144     inline bool
handle_alt_leftbracket(boost::wave::token_id prev,boost::wave::token_id)145     handle_alt_leftbracket(boost::wave::token_id prev,
146         boost::wave::token_id /*before*/)
147     {
148         using namespace boost::wave;
149         switch (prev) {
150         case T_LESS:        // <<:
151         case T_SHIFTLEFT:   // <<<:
152             return true;
153 
154         default:
155             break;
156         }
157         return false;
158     }
159 // T_FIXEDPOINTLIT
160     inline bool
handle_fixedpointlit(boost::wave::token_id prev,boost::wave::token_id)161     handle_fixedpointlit(boost::wave::token_id prev,
162         boost::wave::token_id /*before*/)
163     {
164         using namespace boost::wave;
165         switch (prev) {
166         case T_IDENTIFIER:
167         case T_NONREPLACABLE_IDENTIFIER:
168         case T_INTLIT:
169         case T_FLOATLIT:
170         case T_FIXEDPOINTLIT:
171         case T_PP_NUMBER:
172             return true;
173 
174         default:
175             break;
176         }
177         return false;
178     }
179 // T_DOT
180     inline bool
handle_dot(boost::wave::token_id prev,boost::wave::token_id before)181     handle_dot(boost::wave::token_id prev, boost::wave::token_id before)
182     {
183         using namespace boost::wave;
184         switch (prev) {
185         case T_DOT:
186             if (T_DOT == before)
187                 return true;    // ...
188             break;
189 
190         default:
191             break;
192         }
193         return false;
194     }
195 // T_QUESTION_MARK
196     inline bool
handle_questionmark(boost::wave::token_id prev,boost::wave::token_id)197     handle_questionmark(boost::wave::token_id prev,
198         boost::wave::token_id /*before*/)
199     {
200         using namespace boost::wave;
201         switch(prev) {
202         case T_UNKNOWN_UNIVERSALCHAR:     // \?
203         case T_QUESTION_MARK:   // ??
204             return true;
205 
206         default:
207             break;
208         }
209         return false;
210     }
211 // T_NEWLINE
212     inline bool
handle_newline(boost::wave::token_id prev,boost::wave::token_id before)213     handle_newline(boost::wave::token_id prev,
214         boost::wave::token_id before)
215     {
216         using namespace boost::wave;
217         switch(prev) {
218         case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n
219         case T_DIVIDE:
220             if (T_QUESTION_MARK == before)
221                 return true;    // ?/\n     // may be \\n
222             break;
223 
224         default:
225             break;
226         }
227         return false;
228     }
229 
230     inline bool
handle_parens(boost::wave::token_id prev)231     handle_parens(boost::wave::token_id prev)
232     {
233         switch (prev) {
234         case T_LEFTPAREN:
235         case T_RIGHTPAREN:
236         case T_LEFTBRACKET:
237         case T_RIGHTBRACKET:
238         case T_LEFTBRACE:
239         case T_RIGHTBRACE:
240         case T_SEMICOLON:
241         case T_COMMA:
242         case T_COLON:
243             // no insertion between parens/brackets/braces and operators
244             return false;
245 
246         default:
247             break;
248         }
249         return true;
250     }
251 
252 }   // namespace impl
253 
254 class insert_whitespace_detection
255 {
256 public:
insert_whitespace_detection(bool insert_whitespace_=true)257     insert_whitespace_detection(bool insert_whitespace_ = true)
258     :   insert_whitespace(insert_whitespace_),
259         prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF)
260     {}
261 
262     template <typename StringT>
must_insert(boost::wave::token_id current,StringT const & value)263     bool must_insert(boost::wave::token_id current, StringT const &value)
264     {
265         if (!insert_whitespace)
266             return false;       // skip whitespace insertion alltogether
267 
268         using namespace boost::wave;
269         switch (current) {
270         case T_NONREPLACABLE_IDENTIFIER:
271         case T_IDENTIFIER:
272             return impl::handle_identifier(prev, beforeprev, value);
273         case T_PP_NUMBER:
274         case T_INTLIT:
275             return impl::handle_intlit(prev, beforeprev);
276         case T_FLOATLIT:
277             return impl::handle_floatlit(prev, beforeprev);
278         case T_STRINGLIT:
279             if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev)       // 'L'
280                 return true;
281             break;
282         case T_LEFTBRACE_ALT:
283             return impl::handle_alt_leftbrace(prev, beforeprev);
284         case T_LEFTBRACKET_ALT:
285             return impl::handle_alt_leftbracket(prev, beforeprev);
286         case T_FIXEDPOINTLIT:
287             return impl::handle_fixedpointlit(prev, beforeprev);
288         case T_DOT:
289             return impl::handle_dot(prev, beforeprev);
290         case T_QUESTION_MARK:
291             return impl::handle_questionmark(prev, beforeprev);
292         case T_NEWLINE:
293             return impl::handle_newline(prev, beforeprev);
294 
295         case T_LEFTPAREN:
296         case T_RIGHTPAREN:
297         case T_LEFTBRACKET:
298         case T_RIGHTBRACKET:
299         case T_SEMICOLON:
300         case T_COMMA:
301         case T_COLON:
302             switch (prev) {
303             case T_LEFTPAREN:
304             case T_RIGHTPAREN:
305             case T_LEFTBRACKET:
306             case T_RIGHTBRACKET:
307             case T_LEFTBRACE:
308             case T_RIGHTBRACE:
309                 return false;   // no insertion between parens/brackets/braces
310 
311             default:
312                 if (IS_CATEGORY(prev, OperatorTokenType))
313                     return false;
314                 break;
315             }
316             break;
317 
318         case T_LEFTBRACE:
319         case T_RIGHTBRACE:
320             switch (prev) {
321             case T_LEFTPAREN:
322             case T_RIGHTPAREN:
323             case T_LEFTBRACKET:
324             case T_RIGHTBRACKET:
325             case T_LEFTBRACE:
326             case T_RIGHTBRACE:
327             case T_SEMICOLON:
328             case T_COMMA:
329             case T_COLON:
330                 return false;   // no insertion between parens/brackets/braces
331 
332             case T_QUESTION_MARK:
333                 if (T_QUESTION_MARK == beforeprev)
334                     return true;
335                 if (IS_CATEGORY(prev, OperatorTokenType))
336                     return false;
337                 break;
338 
339             default:
340                 break;
341             }
342             break;
343 
344         case T_MINUS:
345         case T_MINUSMINUS:
346         case T_MINUSASSIGN:
347             if (T_MINUS == prev || T_MINUSMINUS == prev)
348                 return true;
349             if (!impl::handle_parens(prev))
350                 return false;
351             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
352                 return true;
353             break;
354 
355         case T_PLUS:
356         case T_PLUSPLUS:
357         case T_PLUSASSIGN:
358             if (T_PLUS == prev || T_PLUSPLUS == prev)
359                 return true;
360             if (!impl::handle_parens(prev))
361                 return false;
362             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
363                 return true;
364             break;
365 
366         case T_DIVIDE:
367         case T_DIVIDEASSIGN:
368             if (T_DIVIDE == prev)
369                 return true;
370             if (!impl::handle_parens(prev))
371                 return false;
372             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
373                 return true;
374             break;
375 
376         case T_EQUAL:
377         case T_ASSIGN:
378             switch (prev) {
379             case T_PLUSASSIGN:
380             case T_MINUSASSIGN:
381             case T_DIVIDEASSIGN:
382             case T_STARASSIGN:
383             case T_SHIFTRIGHTASSIGN:
384             case T_SHIFTLEFTASSIGN:
385             case T_EQUAL:
386             case T_NOTEQUAL:
387             case T_LESSEQUAL:
388             case T_GREATEREQUAL:
389             case T_LESS:
390             case T_GREATER:
391             case T_PLUS:
392             case T_MINUS:
393             case T_STAR:
394             case T_DIVIDE:
395             case T_ORASSIGN:
396             case T_ANDASSIGN:
397             case T_XORASSIGN:
398             case T_OR:
399             case T_AND:
400             case T_XOR:
401             case T_OROR:
402             case T_ANDAND:
403                 return true;
404 
405             case T_QUESTION_MARK:
406                 if (T_QUESTION_MARK == beforeprev)
407                     return true;
408                 break;
409 
410             default:
411                 if (!impl::handle_parens(prev))
412                     return false;
413                 break;
414             }
415             break;
416 
417         case T_GREATER:
418             if (T_MINUS == prev || T_GREATER == prev)
419                 return true;    // prevent -> or >>
420             if (!impl::handle_parens(prev))
421                 return false;
422             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
423                 return true;
424             break;
425 
426         case T_LESS:
427             if (T_LESS == prev)
428                 return true;    // prevent <<
429             // fall through
430         case T_CHARLIT:
431         case T_NOT:
432         case T_NOTEQUAL:
433             if (!impl::handle_parens(prev))
434                 return false;
435             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
436                 return true;
437             break;
438 
439         case T_AND:
440         case T_ANDAND:
441             if (!impl::handle_parens(prev))
442                 return false;
443             if (T_AND == prev || T_ANDAND == prev)
444                 return true;
445             break;
446 
447         case T_OR:
448             if (!impl::handle_parens(prev))
449                 return false;
450             if (T_OR == prev)
451                 return true;
452             break;
453 
454         case T_XOR:
455             if (!impl::handle_parens(prev))
456                 return false;
457             if (T_XOR == prev)
458                 return true;
459             break;
460 
461         case T_COMPL_ALT:
462         case T_OR_ALT:
463         case T_AND_ALT:
464         case T_NOT_ALT:
465         case T_XOR_ALT:
466         case T_ANDASSIGN_ALT:
467         case T_ORASSIGN_ALT:
468         case T_XORASSIGN_ALT:
469         case T_NOTEQUAL_ALT:
470             switch (prev) {
471             case T_LEFTPAREN:
472             case T_RIGHTPAREN:
473             case T_LEFTBRACKET:
474             case T_RIGHTBRACKET:
475             case T_LEFTBRACE:
476             case T_RIGHTBRACE:
477             case T_SEMICOLON:
478             case T_COMMA:
479             case T_COLON:
480                 // no insertion between parens/brackets/braces and operators
481                 return false;
482 
483             case T_IDENTIFIER:
484                 if (T_NONREPLACABLE_IDENTIFIER == prev ||
485                     IS_CATEGORY(prev, KeywordTokenType))
486                 {
487                     return true;
488                 }
489                 break;
490 
491             default:
492                 break;
493             }
494             break;
495 
496         case T_STAR:
497             if (T_STAR == prev)
498                 return false;     // '*****' do not need to be separated
499             if (T_GREATER== prev &&
500                 (T_MINUS == beforeprev || T_MINUSMINUS == beforeprev)
501                )
502             {
503                 return true;    // prevent ->*
504             }
505             break;
506 
507         case T_POUND:
508             if (T_POUND == prev)
509                 return true;
510             break;
511 
512         default:
513             break;
514         }
515 
516     // FIXME: else, handle operators separately (will catch to many cases)
517 //         if (IS_CATEGORY(current, OperatorTokenType) &&
518 //             IS_CATEGORY(prev, OperatorTokenType))
519 //         {
520 //             return true;    // operators must be delimited always
521 //         }
522         return false;
523     }
shift_tokens(boost::wave::token_id next_id)524     void shift_tokens (boost::wave::token_id next_id)
525     {
526         if (insert_whitespace) {
527             beforeprev = prev;
528             prev = next_id;
529         }
530     }
531 
532 private:
533     bool insert_whitespace;            // enable this component
534     boost::wave::token_id prev;        // the previous analyzed token
535     boost::wave::token_id beforeprev;  // the token before the previous
536 };
537 
538 ///////////////////////////////////////////////////////////////////////////////
539 }   //  namespace util
540 }   //  namespace wave
541 }   //  namespace boost
542 
543 // the suffix header occurs after all of the code
544 #ifdef BOOST_HAS_ABI_HEADERS
545 #include BOOST_ABI_SUFFIX
546 #endif
547 
548 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
549