source: NonGTP/Boost/boost/wave/util/cpp_macromap_utils.hpp @ 857

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