Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/wave/util/cpp_macromap_utils.hpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 16.6 KB
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3
4    Token sequence analysis and transformation helper functions
5   
6    http://www.boost.org/
7
8    Copyright (c) 2001-2007 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
13#if !defined(CPP_MACROMAP_UTIL_HPP_HK041119)
14#define CPP_MACROMAP_UTIL_HPP_HK041119
15
16#include <boost/assert.hpp>
17
18#include <boost/wave/wave_config.hpp>
19#include <boost/wave/token_ids.hpp>
20
21// this must occur after all of the includes and before any code appears
22#ifdef BOOST_HAS_ABI_HEADERS
23#include BOOST_ABI_PREFIX
24#endif
25
26///////////////////////////////////////////////////////////////////////////////
27//
28// This file contains the definition of several token sequence analyse
29// and transformation utility functions needed during macro handling.
30//
31///////////////////////////////////////////////////////////////////////////////
32
33///////////////////////////////////////////////////////////////////////////////
34namespace boost {
35namespace wave {
36namespace util {
37
38///////////////////////////////////////////////////////////////////////////////
39namespace on_exit {
40
41    ///////////////////////////////////////////////////////////////////////////
42    //
43    //  On destruction pop the first element of the list given as the argument
44    //
45    ///////////////////////////////////////////////////////////////////////////
46    template <typename ContainerT>
47    class pop_front {
48    public:
49        pop_front(ContainerT &list_) : list(list_) {}
50        ~pop_front() { list.pop_front(); }
51   
52    private:
53        ContainerT &list;
54    };
55
56    ///////////////////////////////////////////////////////////////////////////
57    //
58    //  Append a given list to the list given as argument
59    //  On destruction pop the first element of the list given as argument
60    //
61    ///////////////////////////////////////////////////////////////////////////
62    template <typename ContainerT>
63    class splice_pop_front {
64    public:
65        splice_pop_front(ContainerT &list_, ContainerT &queue) 
66        :   list(list_) 
67        {
68            list.splice(list.end(), queue);
69        }
70        ~splice_pop_front() { list.pop_front(); }
71
72    private:
73        ContainerT &list;
74    };
75
76    ///////////////////////////////////////////////////////////////////////////
77    //
78    //  On destruction reset a referenced value to its initial state
79    //
80    ///////////////////////////////////////////////////////////////////////////
81    template <typename TypeT>
82    class reset {
83    public:
84        reset(TypeT &target_value_, TypeT new_value)
85        :   target_value(target_value_), old_value(target_value_)
86        {
87            target_value_ = new_value;
88        }
89        ~reset() { target_value = old_value; }
90
91    private:
92        TypeT &target_value;
93        TypeT old_value;
94    };
95
96    ///////////////////////////////////////////////////////////////////////////
97    //
98    //  On destruction assign the given iterator back
99    //
100    ///////////////////////////////////////////////////////////////////////////
101    template <typename IteratorT, typename UnputIteratorT>
102    class assign {
103    public:
104        assign(IteratorT &it_, UnputIteratorT const &uit_) 
105        :   it(it_), uit(uit_) {}
106        ~assign() { it = uit.base(); }
107
108    private:
109        IteratorT &it;
110        UnputIteratorT const &uit;
111    };
112
113    template <typename IteratorT>
114    class assign<IteratorT, IteratorT> {
115    public:
116        assign(IteratorT &it_, IteratorT const &uit_) 
117        :   it(it_), uit(uit_) {}
118        ~assign() { it = uit; }
119
120    private:
121        IteratorT &it;
122        IteratorT const &uit;
123    };
124
125///////////////////////////////////////////////////////////////////////////////
126}   // namespace on_exit
127
128///////////////////////////////////////////////////////////////////////////////
129namespace impl {
130
131///////////////////////////////////////////////////////////////////////////////
132//
133//  Test, whether a given identifier resolves to a predefined name
134//
135///////////////////////////////////////////////////////////////////////////////
136template <typename StringT>
137inline bool 
138is_special_macroname (StringT const &name)
139{
140    if (name.size() < 7)
141        return false;
142       
143    if ("defined" == name)
144        return true;
145       
146    if ('_' == name[0] && '_' == name[1]) {
147    StringT str = name.substr(2);
148   
149        if (str == "cplusplus"  || str == "STDC__" || 
150            str == "TIME__"     || str == "DATE__" ||
151            str == "LINE__"     || str == "FILE__" ||
152            str == "INCLUDE_LEVEL__")
153        {
154            return true;
155        }
156    }
157    return false;
158}
159
160///////////////////////////////////////////////////////////////////////////////
161//
162//  Test, whether a given identifier resolves to a operator name
163//
164///////////////////////////////////////////////////////////////////////////////
165//template <typename StringT>
166//inline bool
167//is_operator_macroname (StringT const &name)
168//{
169//    if (name.size() < 2 || name.size() > 6)
170//        return false;
171//       
172//    if (str == "and"    || str == "and_eq" ||
173//        str == "bitand" || str == "bitor" ||
174//        str == "compl"  ||
175//        str == "not"    || str == "not_eq" ||
176//        str == "or"     || str == "or_eq" ||
177//        str == "xor"    || str == "xor_eq")
178//    {
179//        return true;
180//    }
181//    return false;
182//}
183
184///////////////////////////////////////////////////////////////////////////////
185//
186//  Test, whether two tokens are to be considered equal (different sequences
187//  of whitespace are considered to be equal)
188//
189///////////////////////////////////////////////////////////////////////////////
190template <typename TokenT>
191inline bool 
192token_equals(TokenT const &left, TokenT const &right)
193{
194    using namespace boost::wave;
195   
196#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
197    if (T_PARAMETERBASE == token_id(left) || 
198        T_EXTPARAMETERBASE == token_id(left)) 
199#else
200    if (T_PARAMETERBASE == token_id(left))
201#endif
202    {
203    //  if the existing token is of type T_PARAMETERBASE, then the right token
204    //  must be of type T_IDENTIFIER or a keyword
205    token_id id = token_id(right);
206     
207        return (T_IDENTIFIER == id || 
208                IS_CATEGORY(id, KeywordTokenType) ||
209                IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
210                IS_CATEGORY(id, BoolLiteralTokenType)) && 
211            left.get_value() == right.get_value();
212    }
213
214    // if the left token has whitespace, the value is irrelevant
215    return token_id(left) == token_id(right) && (
216            IS_CATEGORY(left, WhiteSpaceTokenType) ||
217            left.get_value() == right.get_value()
218        );
219}
220
221///////////////////////////////////////////////////////////////////////////////
222//
223//  Tests, whether two macro definitions are equal
224//
225///////////////////////////////////////////////////////////////////////////////
226template <typename ContainerT>
227inline bool 
228definition_equals(ContainerT const &definition, 
229    ContainerT const &new_definition)
230{
231    typedef typename ContainerT::const_iterator const_iterator_type;
232   
233const_iterator_type first1 = definition.begin();
234const_iterator_type last1 = definition.end();
235const_iterator_type first2 = new_definition.begin();
236const_iterator_type last2 = new_definition.end();
237   
238    while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2)) 
239    {
240    // skip whitespace, if both sequences have a whitespace next
241    token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
242    token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
243
244        if (IS_CATEGORY(id1, WhiteSpaceTokenType) && 
245            IS_CATEGORY(id2, WhiteSpaceTokenType)) 
246        {
247        // all consecutive whitespace tokens count as one whitespace
248        // adjust first1 and first2 accordingly
249            skip_whitespace(first1, last1);
250            skip_whitespace(first2, last2);
251        }
252        else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) && 
253                 !IS_CATEGORY(id2, WhiteSpaceTokenType)) 
254        {
255            ++first1;
256            ++first2;
257        }
258        else {
259        // the sequences differ
260            break;
261        }
262    }
263    return (first1 == last1 && first2 == last2) ? true : false;
264}
265
266///////////////////////////////////////////////////////////////////////////////
267//
268//  Tests, whether two given sets of macro parameters are equal
269//
270///////////////////////////////////////////////////////////////////////////////
271template <typename ContainerT>
272inline bool 
273parameters_equal(ContainerT const &parameters, ContainerT const &new_parameters)
274{
275    if (parameters.size() != new_parameters.size())
276        return false;   // different parameter count
277
278    typedef typename ContainerT::const_iterator const_iterator_type;
279   
280const_iterator_type first1 = parameters.begin();
281const_iterator_type last1 = parameters.end();
282const_iterator_type first2 = new_parameters.begin();
283const_iterator_type last2 = new_parameters.end();
284
285    while (first1 != last1 && first2 != last2) {
286    // parameters are different, if the corresponding tokens are different
287        using namespace boost::wave;
288        if (token_id(*first1) != token_id(*first2) ||
289            (*first1).get_value() != (*first2).get_value())
290        {
291            break;
292        }
293        ++first1;
294        ++first2;
295    }
296    return (first1 == last1 && first2 == last2) ? true : false;
297}
298
299///////////////////////////////////////////////////////////////////////////////
300//
301//  Strip leading and trailing whitespace from the given token sequence
302//
303///////////////////////////////////////////////////////////////////////////////
304template <typename ContainerT>
305inline void
306trim_replacement_list (ContainerT &replacement_list)
307{
308    using namespace boost::wave;
309
310// strip leading whitespace
311    if (replacement_list.size() > 0) {
312    typename ContainerT::iterator end = replacement_list.end();
313    typename ContainerT::iterator it = replacement_list.begin();
314   
315        while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { 
316            if (T_PLACEHOLDER != token_id(*it)) {
317                typename ContainerT::iterator next = it;
318                ++next;
319                replacement_list.erase(it);
320                it = next;
321            }
322            else {
323                ++it;
324            }
325        }
326    }
327       
328// strip trailing whitespace
329    if (replacement_list.size() > 0) {
330    typename ContainerT::reverse_iterator rend = replacement_list.rend();
331    typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
332   
333        while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType)) 
334            ++rit;
335
336    typename ContainerT::iterator end = replacement_list.end();
337    typename ContainerT::iterator it = rit.base();
338   
339        while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { 
340            if (T_PLACEHOLDER != token_id(*it)) {
341                typename ContainerT::iterator next = it;
342                ++next;
343                replacement_list.erase(it);
344                it = next;
345            }
346            else {
347                ++it;
348            }
349        }
350    }
351}
352
353///////////////////////////////////////////////////////////////////////////////
354//
355//  Remove all placeholder tokens from the given token sequence
356//
357///////////////////////////////////////////////////////////////////////////////
358template <typename ContainerT>
359inline void
360remove_placeholders (ContainerT &replacement_list)
361{
362    using namespace boost::wave;
363
364// strip leading whitespace
365    if (replacement_list.size() > 0) {
366    typename ContainerT::iterator end = replacement_list.end();
367    typename ContainerT::iterator it = replacement_list.begin();
368   
369        while (it != end) {
370            if (T_PLACEHOLDER == token_id(*it)) {
371                typename ContainerT::iterator next = it;
372                ++next;
373                replacement_list.erase(it);
374                it = next;
375            }
376            else {
377                ++it;
378            }
379        }
380       
381    // remove all 'new' leading and trailing whitespace
382        trim_replacement_list(replacement_list);
383    }
384}
385
386///////////////////////////////////////////////////////////////////////////////
387//
388//  Remove all whitespace tokens on the left side of the given token sequence
389//
390///////////////////////////////////////////////////////////////////////////////
391template <typename ContainerT>
392inline void
393trim_sequence_left (ContainerT &argument)
394{
395    using namespace boost::wave;
396   
397// strip leading whitespace (should be only one token)
398    if (argument.size() > 0 &&
399        IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
400    {
401        argument.pop_front();
402    }
403}
404   
405///////////////////////////////////////////////////////////////////////////////
406//
407//  Remove all whitespace tokens on the right side of the given token sequence
408//
409///////////////////////////////////////////////////////////////////////////////
410template <typename ContainerT>
411inline void
412trim_sequence_right (ContainerT &argument)
413{
414    using namespace boost::wave;
415   
416// strip trailing whitespace (should be only one token)
417    if (argument.size() > 0 &&
418        IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
419    {
420        argument.pop_back();
421    }
422}
423
424///////////////////////////////////////////////////////////////////////////////
425//
426//  Remove all whitespace tokens on the left and right sides of the given token
427//  sequence
428//
429///////////////////////////////////////////////////////////////////////////////
430template <typename ContainerT>
431inline void
432trim_sequence (ContainerT &argument)
433{
434    trim_sequence_left(argument);
435    trim_sequence_right(argument);
436}
437
438///////////////////////////////////////////////////////////////////////////////
439//
440//  Tests, whether the given token sequence consists out of whitespace only
441//
442///////////////////////////////////////////////////////////////////////////////
443template <typename ContainerT>
444inline bool
445is_whitespace_only (ContainerT const &argument)
446{
447    using namespace cpplexer;
448   
449    typename ContainerT::const_iterator end = argument.end();
450    for (typename ContainerT::const_iterator it = argument.begin();
451          it != end; ++it)
452    {
453        if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
454            return false;
455    }
456    return true;
457}
458
459///////////////////////////////////////////////////////////////////////////////
460//
461//  Skip forward to a given token
462//
463///////////////////////////////////////////////////////////////////////////////
464template <typename IteratorT>
465inline bool 
466skip_to_token(IteratorT &it, IteratorT const &end, token_id id)
467{
468    using namespace boost::wave;
469    if (token_id(*it) == id) 
470        return true;
471    if (++it == end) 
472        return false;
473
474    while (IS_CATEGORY(*it, WhiteSpaceTokenType) || 
475            T_NEWLINE == token_id(*it)) 
476    {
477        if (++it == end)
478            return false;
479    }
480    return token_id(*it) == id;
481}
482
483///////////////////////////////////////////////////////////////////////////////
484//
485//  Get the full name of a given macro name (concatenate the string
486//  representations of the single tokens).
487//
488///////////////////////////////////////////////////////////////////////////////
489template <typename IteratorT>
490inline std::string
491get_full_name(IteratorT const &begin, IteratorT const &end)
492{
493    std::string full_name;
494    for (IteratorT err_it = begin; err_it != end; ++err_it) 
495        full_name += (*err_it).get_value().c_str();
496
497    return full_name;
498}
499
500///////////////////////////////////////////////////////////////////////////////
501//
502//  The following predicate is used in conjunction with the remove_copy_if
503//  algorithm to allow the detection of an eventually copied operator ##.
504//  No removal is performed in any case.
505//
506///////////////////////////////////////////////////////////////////////////////
507class find_concat_operator {
508public:
509    find_concat_operator(bool &found_) : found_concat(found_) {}
510   
511    template <typename TokenT>
512    bool operator()(TokenT const &tok)
513    {
514        using namespace boost::wave;
515        if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
516            found_concat = true;
517        return false;
518    }
519
520private:
521    bool &found_concat;
522};
523
524///////////////////////////////////////////////////////////////////////////////
525}   // namespace impl
526
527///////////////////////////////////////////////////////////////////////////////
528}   // namespace util
529}   // namespace wave
530}   // namespace boost
531
532// the suffix header occurs after all of the code
533#ifdef BOOST_HAS_ABI_HEADERS
534#include BOOST_ABI_SUFFIX
535#endif
536
537#endif // !defined(CPP_MACROMAP_UTIL_HPP_HK041119)
Note: See TracBrowser for help on using the repository browser.