1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3 
4     http://www.boost.org/
5 
6     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
7     Software License, Version 1.0. (See accompanying file
8     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 
11 #if !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED)
12 #define CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED
13 
14 #include <stack>
15 #include <boost/wave/wave_config.hpp>
16 
17 // this must occur after all of the includes and before any code appears
18 #ifdef BOOST_HAS_ABI_HEADERS
19 #include BOOST_ABI_PREFIX
20 #endif
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 namespace boost {
24 namespace wave {
25 namespace util {
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 // the class if_blocks handles recursive conditional compilation contexts
29 class if_block
30 {
31 public:
if_block()32     if_block() :
33         status(true), some_part_status(true),
34         enclosing_status(true), is_in_else(false)
35     {
36     }
if_block(bool status_,bool enclosing_status_)37     if_block(bool status_, bool enclosing_status_) :
38         status(status_),
39         some_part_status(status_),
40         enclosing_status(enclosing_status_),
41         is_in_else(false)
42     {
43     }
44 
set_status(bool status_)45     void set_status(bool status_)
46     {
47         status = status_;
48         if (status_)
49             some_part_status = true;
50     }
get_status() const51     bool get_status() const { return status; }
get_some_part_status() const52     bool get_some_part_status() const { return some_part_status; }
get_enclosing_status() const53     bool get_enclosing_status() const { return enclosing_status; }
get_in_else() const54     bool get_in_else() const { return is_in_else; }
set_in_else()55     void set_in_else() { is_in_else = true; }
56 
57 private:
58    bool status;             // Current block is true
59    bool some_part_status;   // One of the preceding or current #if/#elif was true
60    bool enclosing_status;   // Enclosing #if block is true
61    bool is_in_else;         // Inside the #else part
62 };
63 
64 ///////////////////////////////////////////////////////////////////////////////
65 // stack of conditional compilation contexts
66 class if_block_stack
67 :   private std::stack<if_block>
68 {
69 public:
70     typedef std::stack<if_block>::size_type size_type;
71 
enter_if_block(bool new_status)72     void enter_if_block(bool new_status)
73     {
74     // If enclosing block is false, then this block is also false
75         bool enclosing_status = get_status();
76         this->push (value_type (new_status && enclosing_status, enclosing_status));
77     }
enter_elif_block(bool new_status)78     bool enter_elif_block(bool new_status)
79     {
80         if (!is_inside_ifpart())
81             return false;       // #elif without matching #if
82 
83         if (get_enclosing_status()) {
84             if (get_status()) {
85             // entered a (false) #elif block from a true block
86                 this->top().set_status(false);
87             }
88             else if (new_status && !this->top().get_some_part_status()) {
89             // Entered true #elif block and no previous block was true
90                 this->top().set_status(new_status);
91             }
92         }
93         return true;
94     }
enter_else_block()95     bool enter_else_block()
96     {
97         if (!is_inside_ifpart())
98             return false;       // #else without matching #if
99 
100         if (get_enclosing_status()) {
101             if (!this->top().get_some_part_status()) {
102             // Entered (true) #else block and no previous block was true
103                 this->top().set_status(true);
104             }
105             else if (get_status()) {
106             // Entered (false) #else block from true block
107                 this->top().set_status(false);
108             }
109 
110         // Set else flag
111             this->top().set_in_else();
112         }
113         return true;
114     }
exit_if_block()115     bool exit_if_block()
116     {
117         if (0 == this->size())
118             return false;   // #endif without matching #if
119 
120         this->pop();
121         return true;
122     }
123 
124 // return, whether the top (innermost) condition is true or false
get_status() const125     bool get_status() const
126     {
127         return 0 == this->size() || this->top().get_status();
128     }
get_some_part_status() const129     bool get_some_part_status() const
130     {
131         return 0 == this->size() || this->top().get_some_part_status();
132     }
get_enclosing_status() const133     bool get_enclosing_status() const
134     {
135         return 0 == this->size() || this->top().get_enclosing_status();
136     }
137 
get_if_block_depth() const138     size_type get_if_block_depth() const { return this->size(); }
139 
140 protected:
is_inside_ifpart() const141     bool is_inside_ifpart() const
142     {
143         return 0 != this->size() && !this->top().get_in_else();
144     }
is_inside_elsepart() const145     bool is_inside_elsepart() const
146     {
147         return 0 != this->size() && this->top().get_in_else();
148     }
149 };
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 }   // namespace util
153 }   // namespace wave
154 }   // namespace boost
155 
156 // the suffix header occurs after all of the code
157 #ifdef BOOST_HAS_ABI_HEADERS
158 #include BOOST_ABI_SUFFIX
159 #endif
160 
161 #endif // !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED)
162