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-2005 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 ///////////////////////////////////////////////////////////////////////////////
19 namespace boost {
20 namespace wave {
21 namespace util {
22 
23 namespace impl {
24 
25 // T_IDENTIFIER
26     template <typename StringT>
27     inline bool
would_form_universal_char(StringT const & value)28     would_form_universal_char (StringT const &value)
29     {
30         if ('u' != value[0] && 'U' != value[0])
31             return false;
32         if ('u' == value[0] && value.size() < 5)
33             return false;
34         if ('U' == value[0] && value.size() < 9)
35             return false;
36 
37     typename StringT::size_type pos =
38         value.find_first_not_of("0123456789abcdefABCDEF", 1);
39 
40         if (StringT::npos == pos ||
41             ('u' == value[0] && pos > 5) ||
42             ('U' == value[0] && pos > 9))
43         {
44             return true;        // would form an universal char
45         }
46         return false;
47     }
48     template <typename StringT>
49     inline bool
handle_identifier(boost::wave::token_id prev,boost::wave::token_id before,StringT const & value)50     handle_identifier(boost::wave::token_id prev,
51         boost::wave::token_id before, StringT const &value)
52     {
53         using namespace boost::wave;
54         switch (static_cast<unsigned int>(prev)) {
55         case T_IDENTIFIER:
56         case T_NONREPLACABLE_IDENTIFIER:
57         case T_COMPL_ALT:
58         case T_OR_ALT:
59         case T_AND_ALT:
60         case T_NOT_ALT:
61         case T_XOR_ALT:
62         case T_ANDASSIGN_ALT:
63         case T_ORASSIGN_ALT:
64         case T_XORASSIGN_ALT:
65         case T_NOTEQUAL_ALT:
66         case T_FIXEDPOINTLIT:
67             return true;
68 
69         case T_FLOATLIT:
70         case T_INTLIT:
71             return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E'));
72 
73          // avoid constructing universal characters (\u1234)
74         case TOKEN_FROM_ID('\\', UnknownTokenType):
75             return would_form_universal_char(value);
76         }
77         return false;
78     }
79 // T_INTLIT
80     inline bool
handle_intlit(boost::wave::token_id prev,boost::wave::token_id before)81     handle_intlit(boost::wave::token_id prev, boost::wave::token_id before)
82     {
83         using namespace boost::wave;
84         switch (static_cast<unsigned int>(prev)) {
85         case T_IDENTIFIER:
86         case T_NONREPLACABLE_IDENTIFIER:
87         case T_INTLIT:
88         case T_FLOATLIT:
89         case T_FIXEDPOINTLIT:
90             return true;
91         }
92         return false;
93     }
94 // T_FLOATLIT
95     inline bool
handle_floatlit(boost::wave::token_id prev,boost::wave::token_id before)96     handle_floatlit(boost::wave::token_id prev,
97         boost::wave::token_id before)
98     {
99         using namespace boost::wave;
100         switch (static_cast<unsigned int>(prev)) {
101         case T_IDENTIFIER:
102         case T_NONREPLACABLE_IDENTIFIER:
103         case T_INTLIT:
104         case T_FLOATLIT:
105         case T_FIXEDPOINTLIT:
106             return true;
107         }
108         return false;
109     }
110 // <% T_LEFTBRACE
111     inline bool
handle_alt_leftbrace(boost::wave::token_id prev,boost::wave::token_id before)112     handle_alt_leftbrace(boost::wave::token_id prev,
113         boost::wave::token_id before)
114     {
115         using namespace boost::wave;
116         switch (static_cast<unsigned int>(prev)) {
117         case T_LESS:        // <<%
118         case T_SHIFTLEFT:   // <<<%
119             return true;
120         }
121         return false;
122     }
123 // <: T_LEFTBRACKET
124     inline bool
handle_alt_leftbracket(boost::wave::token_id prev,boost::wave::token_id before)125     handle_alt_leftbracket(boost::wave::token_id prev,
126         boost::wave::token_id before)
127     {
128         using namespace boost::wave;
129         switch (static_cast<unsigned int>(prev)) {
130         case T_LESS:        // <<:
131         case T_SHIFTLEFT:   // <<<:
132             return true;
133         }
134         return false;
135     }
136 // T_FIXEDPOINTLIT
137     inline bool
handle_fixedpointlit(boost::wave::token_id prev,boost::wave::token_id before)138     handle_fixedpointlit(boost::wave::token_id prev,
139         boost::wave::token_id before)
140     {
141         using namespace boost::wave;
142         switch (static_cast<unsigned int>(prev)) {
143         case T_IDENTIFIER:
144         case T_NONREPLACABLE_IDENTIFIER:
145         case T_INTLIT:
146         case T_FLOATLIT:
147         case T_FIXEDPOINTLIT:
148             return true;
149         }
150         return false;
151     }
152 // T_DOT
153     inline bool
handle_dot(boost::wave::token_id prev,boost::wave::token_id before)154     handle_dot(boost::wave::token_id prev, boost::wave::token_id before)
155     {
156         using namespace boost::wave;
157         switch (static_cast<unsigned int>(prev)) {
158         case T_DOT:
159             if (T_DOT == before)
160                 return true;    // ...
161             break;
162         }
163         return false;
164     }
165 // T_QUESTION_MARK
166     inline bool
handle_questionmark(boost::wave::token_id prev,boost::wave::token_id before)167     handle_questionmark(boost::wave::token_id prev,
168         boost::wave::token_id before)
169     {
170         using namespace boost::wave;
171         switch(static_cast<unsigned int>(prev)) {
172         case TOKEN_FROM_ID('\\', UnknownTokenType):     // \?
173         case T_QUESTION_MARK:   // ??
174             return true;
175         }
176         return false;
177     }
178 // T_NEWLINE
179     inline bool
handle_newline(boost::wave::token_id prev,boost::wave::token_id before)180     handle_newline(boost::wave::token_id prev,
181         boost::wave::token_id before)
182     {
183         using namespace boost::wave;
184         switch(static_cast<unsigned int>(prev)) {
185         case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n
186         case T_DIVIDE:
187             if (T_QUESTION_MARK == before)
188                 return true;    // ?/\n     // may be \\n
189             break;
190         }
191         return false;
192     }
193 
194 }   // namespace impl
195 
196 class insert_whitespace_detection
197 {
198 public:
insert_whitespace_detection()199     insert_whitespace_detection()
200     :   prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF)
201     {}
202 
203     template <typename StringT>
must_insert(boost::wave::token_id current,StringT const & value)204     bool must_insert(boost::wave::token_id current, StringT const &value)
205     {
206         using namespace boost::wave;
207         switch (current) {
208         case T_NONREPLACABLE_IDENTIFIER:
209         case T_IDENTIFIER:
210             return impl::handle_identifier(prev, beforeprev, value);
211         case T_INTLIT:
212             return impl::handle_intlit(prev, beforeprev);
213         case T_FLOATLIT:
214             return impl::handle_floatlit(prev, beforeprev);
215         case T_STRINGLIT:
216             if (TOKEN_FROM_ID('L', UnknownTokenType) == prev)       // 'L'
217                 return true;
218             break;
219         case T_LEFTBRACE_ALT:
220             return impl::handle_alt_leftbrace(prev, beforeprev);
221         case T_LEFTBRACKET_ALT:
222             return impl::handle_alt_leftbracket(prev, beforeprev);
223         case T_FIXEDPOINTLIT:
224             return impl::handle_fixedpointlit(prev, beforeprev);
225         case T_DOT:
226             return impl::handle_dot(prev, beforeprev);
227         case T_QUESTION_MARK:
228             return impl::handle_questionmark(prev, beforeprev);
229         case T_NEWLINE:
230             return impl::handle_newline(prev, beforeprev);
231 
232         case T_LEFTPAREN:
233         case T_RIGHTPAREN:
234         case T_LEFTBRACKET:
235         case T_RIGHTBRACKET:
236         case T_SEMICOLON:
237         case T_COMMA:
238         case T_COLON:
239             switch (static_cast<unsigned int>(prev)) {
240             case T_LEFTPAREN:
241             case T_RIGHTPAREN:
242             case T_LEFTBRACKET:
243             case T_RIGHTBRACKET:
244             case T_LEFTBRACE:
245             case T_RIGHTBRACE:
246                 return false;   // no insertion between parens/brackets/braces
247 
248             default:
249                 break;
250             }
251             break;
252 
253         case T_LEFTBRACE:
254         case T_RIGHTBRACE:
255             switch (static_cast<unsigned int>(prev)) {
256             case T_LEFTPAREN:
257             case T_RIGHTPAREN:
258             case T_LEFTBRACKET:
259             case T_RIGHTBRACKET:
260             case T_LEFTBRACE:
261             case T_RIGHTBRACE:
262             case T_SEMICOLON:
263             case T_COMMA:
264             case T_COLON:
265                 return false;   // no insertion between parens/brackets/braces
266 
267             case T_QUESTION_MARK:
268                 if (T_QUESTION_MARK == beforeprev)
269                     return true;
270                 break;
271 
272             default:
273                 break;
274             }
275             break;
276 
277         case T_MINUS:
278         case T_MINUSMINUS:
279         case T_LESS:
280         case T_EQUAL:
281         case T_ASSIGN:
282         case T_GREATER:
283         case T_DIVIDE:
284         case T_CHARLIT:
285         case T_NOT:
286         case T_NOTEQUAL:
287         case T_DIVIDEASSIGN:
288         case T_MINUSASSIGN:
289             if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
290                 return true;    // ??{op}
291             break;
292 
293         case T_COMPL_ALT:
294         case T_OR_ALT:
295         case T_AND_ALT:
296         case T_NOT_ALT:
297         case T_XOR_ALT:
298         case T_ANDASSIGN_ALT:
299         case T_ORASSIGN_ALT:
300         case T_XORASSIGN_ALT:
301         case T_NOTEQUAL_ALT:
302             if (T_IDENTIFIER == prev || T_NONREPLACABLE_IDENTIFIER == prev ||
303                 IS_CATEGORY(prev, KeywordTokenType))
304                 return true;
305             break;
306         }
307 
308     // else, handle operators separately
309         if (IS_CATEGORY(current, OperatorTokenType) &&
310             IS_CATEGORY(prev, OperatorTokenType))
311         {
312             return true;    // operators must be delimited always
313         }
314         return false;
315     }
shift_tokens(boost::wave::token_id next_id)316     void shift_tokens (boost::wave::token_id next_id)
317     {
318         beforeprev = prev;
319         prev = next_id;
320     }
321 
322 private:
323     boost::wave::token_id prev;        // the previous analyzed token
324     boost::wave::token_id beforeprev;  // the token before the previous
325 };
326 
327 ///////////////////////////////////////////////////////////////////////////////
328 }   //  namespace util
329 }   //  namespace wave
330 }   //  namespace boost
331 
332 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
333