fix build
[m6w6/ext-psi] / src / types / cpp_exp.c
1 /*******************************************************************************
2 Copyright (c) 2017, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
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.
13
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 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include <assert.h>
33
34 #include "data.h"
35 #include "cpp.h"
36 #include "debug.h"
37
38 struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data)
39 {
40 struct psi_cpp_exp *exp = pecalloc(1, sizeof(*exp), 1);
41
42 switch ((exp->type = type)) {
43 case PSI_T_WARNING:
44 case PSI_T_ERROR:
45 case PSI_T_UNDEF:
46 case PSI_T_IFDEF:
47 case PSI_T_IFNDEF:
48 case PSI_T_IMPORT:
49 case PSI_T_INCLUDE:
50 case PSI_T_INCLUDE_NEXT:
51 exp->data.tok = data;
52 break;
53 case PSI_T_DEFINE:
54 exp->data.decl = data;
55 break;
56 case PSI_T_IF:
57 case PSI_T_ELIF:
58 exp->data.num = data;
59 break;
60 case PSI_T_ENDIF:
61 case PSI_T_ELSE:
62 case PSI_T_PRAGMA_ONCE:
63 break;
64 default:
65 assert(0);
66 break;
67 }
68
69 return exp;
70 }
71
72 void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr)
73 {
74 if (*exp_ptr) {
75 struct psi_cpp_exp *exp = *exp_ptr;
76
77 *exp_ptr = NULL;
78 switch (exp->type) {
79 case PSI_T_WARNING:
80 case PSI_T_ERROR:
81 case PSI_T_UNDEF:
82 case PSI_T_IFDEF:
83 case PSI_T_IFNDEF:
84 case PSI_T_IMPORT:
85 case PSI_T_INCLUDE:
86 case PSI_T_INCLUDE_NEXT:
87 psi_token_free(&exp->data.tok);
88 break;
89 case PSI_T_DEFINE:
90 psi_cpp_macro_decl_free(&exp->data.decl);
91 break;
92 case PSI_T_IF:
93 case PSI_T_ELIF:
94 psi_num_exp_free(&exp->data.num);
95 break;
96 case PSI_T_ENDIF:
97 case PSI_T_ELSE:
98 case PSI_T_PRAGMA_ONCE:
99 break;
100 default:
101 assert(0);
102 break;
103 }
104 psi_token_free(&exp->token);
105 free(exp);
106 }
107 }
108
109 void psi_cpp_exp_dump(struct psi_dump *dump, struct psi_cpp_exp *exp)
110 {
111 PSI_DUMP(dump, "#%s ", exp->token->text->val);
112 switch (exp->type) {
113 case PSI_T_WARNING:
114 case PSI_T_ERROR:
115 if (!exp->data.tok) {
116 break;
117 }
118 /* no break */
119 case PSI_T_UNDEF:
120 case PSI_T_IFDEF:
121 case PSI_T_IFNDEF:
122 PSI_DUMP(dump, "%s", exp->data.tok->text->val);
123 break;
124 case PSI_T_IMPORT:
125 case PSI_T_INCLUDE:
126 case PSI_T_INCLUDE_NEXT:
127 if (exp->data.tok->type == PSI_T_CPP_HEADER) {
128 PSI_DUMP(dump, "<%s>", exp->data.tok->text->val);
129 } else {
130 PSI_DUMP(dump, "\"%s\"", exp->data.tok->text->val);
131 }
132 break;
133 case PSI_T_DEFINE:
134 psi_cpp_macro_decl_dump(dump, exp->data.decl);
135 break;
136 case PSI_T_IF:
137 case PSI_T_ELIF:
138 psi_num_exp_dump(dump, exp->data.num);
139 break;
140 case PSI_T_ENDIF:
141 case PSI_T_ELSE:
142 case PSI_T_PRAGMA_ONCE:
143 break;
144 default:
145 assert(0);
146 break;
147 }
148 PSI_DUMP(dump, "\n");
149 }
150
151
152 static inline bool psi_cpp_level_skipped(struct psi_cpp *cpp)
153 {
154 return cpp->skip == cpp->level;
155 }
156
157 static inline void psi_cpp_level_skip(struct psi_cpp *cpp)
158 {
159 assert(!cpp->skip);
160 cpp->skip = cpp->level;
161 }
162
163 static inline void psi_cpp_level_unskip(struct psi_cpp *cpp)
164 {
165 if (psi_cpp_level_skipped(cpp)) {
166 cpp->skip = 0;
167 }
168 }
169
170 static inline bool psi_cpp_level_masked(struct psi_cpp *cpp)
171 {
172 return cpp->seen & (1 << cpp->level);
173 }
174
175 static inline void psi_cpp_level_mask(struct psi_cpp *cpp)
176 {
177 assert(!psi_cpp_level_masked(cpp));
178 cpp->seen |= (1 << cpp->level);
179 }
180
181 static inline void psi_cpp_level_unmask(struct psi_cpp *cpp)
182 {
183 cpp->seen &= ~(1 << cpp->level);
184 }
185
186 void psi_cpp_exp_exec(struct psi_cpp_exp *exp, struct psi_cpp *cpp, struct psi_data *D)
187 {
188 PSI_DEBUG_PRINT(D, "PSI: CPP EVAL < %s (level=%u, skip=%u)\n",
189 exp->token->text->val, cpp->level, cpp->skip);
190
191 #if PSI_CPP_DEBUG
192 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP exec -> ");
193 PSI_DEBUG_DUMP(cpp->parser, psi_cpp_exp_dump, exp);
194 #endif
195
196 switch (exp->type) {
197 case PSI_T_ERROR:
198 if (!cpp->skip) {
199 D->error(D, exp->token, PSI_ERROR, "%s",
200 exp->data.tok ? exp->data.tok->text->val : "");
201 }
202 break;
203 case PSI_T_WARNING:
204 if (!cpp->skip) {
205 D->error(D, exp->token, PSI_WARNING, "%s",
206 exp->data.tok ? exp->data.tok->text->val : "");
207 }
208 break;
209 case PSI_T_UNDEF:
210 if (!cpp->skip) {
211 psi_cpp_undef(cpp, exp->data.tok);
212 }
213 break;
214 case PSI_T_DEFINE:
215 if (!cpp->skip) {
216 psi_cpp_define(cpp, exp->data.decl);
217 /* FIXME: copy */
218 exp->data.decl = NULL;
219 }
220 break;
221 case PSI_T_IFDEF:
222 ++cpp->level;
223 if (!cpp->skip) {
224 if (psi_cpp_defined(cpp, exp->data.tok)) {
225 psi_cpp_level_mask(cpp);
226 } else {
227 psi_cpp_level_skip(cpp);
228 }
229 }
230 break;
231 case PSI_T_IFNDEF:
232 ++cpp->level;
233 if (!cpp->skip) {
234 if (psi_cpp_defined(cpp, exp->data.tok)) {
235 psi_cpp_level_skip(cpp);
236 } else {
237 psi_cpp_level_mask(cpp);
238 }
239 }
240 break;
241 case PSI_T_IF:
242 ++cpp->level;
243 if (!cpp->skip) {
244 if (psi_cpp_if(cpp, exp)) {
245 psi_cpp_level_mask(cpp);
246 } else {
247 psi_cpp_level_skip(cpp);
248 }
249 }
250 break;
251 case PSI_T_ENDIF:
252 if (!cpp->level) {
253 D->error(D, exp->token, PSI_WARNING, "Ingoring lone #endif");
254 } else {
255 psi_cpp_level_unskip(cpp);
256 psi_cpp_level_unmask(cpp);
257 --cpp->level;
258 }
259 break;
260 case PSI_T_ELSE:
261 /* FIXME: catch "else" after "else" */
262 if (!cpp->level) {
263 D->error(D, exp->token, PSI_WARNING, "Ingoring lone #else");
264 } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) {
265 /*
266 * if skip is set on this level and the level has
267 * not been masked yet, then unskip and mask this level
268 */
269 psi_cpp_level_unskip(cpp);
270 psi_cpp_level_mask(cpp);
271 } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
272 /*
273 * previous block masked this level
274 */
275 psi_cpp_level_skip(cpp);
276 } else {
277 assert(cpp->skip <= cpp->level);
278 }
279 break;
280 case PSI_T_ELIF:
281 if (!cpp->level) {
282 D->error(D, exp->token, PSI_WARNING, "Ingoring lone #elif");
283 } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) {
284 /*
285 * if skip is set on this level and the level has
286 * not been masked yet, then unskip and mask this
287 * level, if the condition evals truthy
288 */
289 if (psi_cpp_if(cpp, exp)) {
290 psi_cpp_level_unskip(cpp);
291 psi_cpp_level_mask(cpp);
292 }
293 } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
294 /*
295 * previous block masked this level
296 */
297 psi_cpp_level_skip(cpp);
298 } else {
299 assert(cpp->skip <= cpp->level);
300 }
301 break;
302 case PSI_T_INCLUDE:
303 if (!cpp->skip) {
304 if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE)) {
305 D->error(D, exp->token, PSI_WARNING, "Failed to include %s: %s",
306 exp->data.tok->text->val, strerror(errno));
307 }
308 }
309 break;
310 case PSI_T_INCLUDE_NEXT:
311 if (!cpp->skip) {
312 if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_NEXT)) {
313 D->error(D, exp->token, PSI_WARNING, "Failed to include next %s: %s",
314 exp->data.tok->text->val, strerror(errno));
315 }
316 }
317 break;
318 case PSI_T_IMPORT:
319 if (!cpp->skip) {
320 if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_ONCE)) {
321 D->error(D, exp->token, PSI_WARNING, "Failed to include once %s: %s",
322 exp->data.tok->text->val, strerror(errno));
323 }
324 }
325 break;
326 case PSI_T_PRAGMA_ONCE:
327 if (!cpp->skip) {
328 zend_hash_add_empty_element(&cpp->once, exp->token->file);
329 }
330 break;
331 default:
332 assert(0);
333 break;
334 }
335
336 PSI_DEBUG_PRINT(D, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n",
337 exp->token->text->val, cpp->level, cpp->skip);
338 }