1 /*******************************************************************************
2 Copyright (c) 2017, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
33 struct psi_cpp_exp
*psi_cpp_exp_init(token_t type
, void *data
)
35 struct psi_cpp_exp
*exp
= calloc(1, sizeof(*exp
));
37 switch ((exp
->type
= type
)) {
45 case PSI_T_INCLUDE_NEXT
:
49 exp
->data
.decl
= data
;
66 void psi_cpp_exp_free(struct psi_cpp_exp
**exp_ptr
)
69 struct psi_cpp_exp
*exp
= *exp_ptr
;
84 case PSI_T_INCLUDE_NEXT
:
89 psi_cpp_macro_decl_free(&exp
->data
.decl
);
93 psi_num_exp_free(&exp
->data
.num
);
109 void psi_cpp_exp_dump(int fd
, struct psi_cpp_exp
*exp
)
111 dprintf(fd
, "#%s ", exp
->token
->text
);
115 if (!exp
->data
.tok
) {
124 case PSI_T_INCLUDE_NEXT
:
125 dprintf(fd
, "%s", exp
->data
.tok
->text
);
128 psi_cpp_macro_decl_dump(fd
, exp
->data
.decl
);
132 psi_num_exp_dump(fd
, exp
->data
.num
);
145 static inline bool psi_cpp_level_skipped(struct psi_cpp
*cpp
)
147 return cpp
->skip
== cpp
->level
;
150 static inline void psi_cpp_level_skip(struct psi_cpp
*cpp
)
153 cpp
->skip
= cpp
->level
;
156 static inline void psi_cpp_level_unskip(struct psi_cpp
*cpp
)
158 if (psi_cpp_level_skipped(cpp
)) {
163 static inline bool psi_cpp_level_masked(struct psi_cpp
*cpp
)
165 return cpp
->seen
& (1 << cpp
->level
);
168 static inline void psi_cpp_level_mask(struct psi_cpp
*cpp
)
170 assert(!psi_cpp_level_masked(cpp
));
171 cpp
->seen
|= (1 << cpp
->level
);
174 static inline void psi_cpp_level_unmask(struct psi_cpp
*cpp
)
176 cpp
->seen
&= ~(1 << cpp
->level
);
179 void psi_cpp_exp_exec(struct psi_cpp_exp
*exp
, struct psi_cpp
*cpp
, struct psi_data
*D
)
181 PSI_DEBUG_PRINT(D
, "PSI: CPP EVAL < %s (level=%u, skip=%u)\n",
182 exp
->token
->text
, cpp
->level
, cpp
->skip
);
185 psi_cpp_exp_dump(2, exp
);
191 D
->error(D
, exp
->token
, PSI_ERROR
, "%s",
192 exp
->data
.tok
? exp
->data
.tok
->text
: "");
197 D
->error(D
, exp
->token
, PSI_WARNING
, "%s",
198 exp
->data
.tok
? exp
->data
.tok
->text
: "");
203 psi_cpp_undef(cpp
, exp
->data
.tok
);
208 psi_cpp_define(cpp
, exp
->data
.decl
);
210 exp
->data
.decl
= NULL
;
216 if (psi_cpp_defined(cpp
, exp
->data
.tok
)) {
217 psi_cpp_level_mask(cpp
);
219 psi_cpp_level_skip(cpp
);
226 if (psi_cpp_defined(cpp
, exp
->data
.tok
)) {
227 psi_cpp_level_skip(cpp
);
229 psi_cpp_level_mask(cpp
);
236 if (psi_cpp_if(cpp
, exp
)) {
237 psi_cpp_level_mask(cpp
);
239 psi_cpp_level_skip(cpp
);
245 D
->error(D
, exp
->token
, PSI_WARNING
, "Ingoring lone #endif");
247 psi_cpp_level_unskip(cpp
);
248 psi_cpp_level_unmask(cpp
);
253 /* FIXME: catch "else" after "else" */
255 D
->error(D
, exp
->token
, PSI_WARNING
, "Ingoring lone #else");
256 } else if (psi_cpp_level_skipped(cpp
) && !psi_cpp_level_masked(cpp
)) {
258 * if skip is set on this level and the level has
259 * not been masked yet, then unskip and mask this level
261 psi_cpp_level_unskip(cpp
);
262 psi_cpp_level_mask(cpp
);
263 } else if (!cpp
->skip
&& psi_cpp_level_masked(cpp
)) {
265 * previous block masked this level
267 psi_cpp_level_skip(cpp
);
269 assert(cpp
->skip
<= cpp
->level
);
274 D
->error(D
, exp
->token
, PSI_WARNING
, "Ingoring lone #elif");
275 } else if (psi_cpp_level_skipped(cpp
) && !psi_cpp_level_masked(cpp
)) {
277 * if skip is set on this level and the level has
278 * not been masked yet, then unskip and mask this
279 * level, if the condition evals truthy
281 if (psi_cpp_if(cpp
, exp
)) {
282 psi_cpp_level_unskip(cpp
);
283 psi_cpp_level_mask(cpp
);
285 } else if (!cpp
->skip
&& psi_cpp_level_masked(cpp
)) {
287 * previous block masked this level
289 psi_cpp_level_skip(cpp
);
291 assert(cpp
->skip
<= cpp
->level
);
296 if (!psi_cpp_include(cpp
, exp
->data
.tok
->text
, PSI_CPP_INCLUDE
)) {
297 D
->error(D
, exp
->token
, PSI_WARNING
, "Failed to include %s", exp
->data
.tok
->text
);
301 case PSI_T_INCLUDE_NEXT
:
303 if (!psi_cpp_include(cpp
, exp
->data
.tok
->text
, PSI_CPP_INCLUDE_NEXT
)) {
304 D
->error(D
, exp
->token
, PSI_WARNING
, "Failed to include %s", exp
->data
.tok
->text
);
313 PSI_DEBUG_PRINT(D
, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n",
314 exp
->token
->text
, cpp
->level
, cpp
->skip
);