bison
[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 #include "php_psi_stdinc.h"
27
28 #include <assert.h>
29
30 #include "data.h"
31 #include "cpp.h"
32
33 struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data)
34 {
35 struct psi_cpp_exp *exp = calloc(1, sizeof(*exp));
36
37 switch ((exp->type = type)) {
38 case PSI_T_WARNING:
39 case PSI_T_ERROR:
40 case PSI_T_UNDEF:
41 case PSI_T_IFDEF:
42 case PSI_T_IFNDEF:
43 case PSI_T_IMPORT:
44 case PSI_T_INCLUDE:
45 case PSI_T_INCLUDE_NEXT:
46 exp->data.tok = data;
47 break;
48 case PSI_T_DEFINE:
49 exp->data.decl = data;
50 break;
51 case PSI_T_IF:
52 case PSI_T_ELIF:
53 exp->data.num = data;
54 break;
55 case PSI_T_ENDIF:
56 case PSI_T_ELSE:
57 break;
58 default:
59 assert(0);
60 break;
61 }
62
63 return exp;
64 }
65
66 void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr)
67 {
68 if (*exp_ptr) {
69 struct psi_cpp_exp *exp = *exp_ptr;
70
71 *exp_ptr = NULL;
72 switch (exp->type) {
73 case PSI_T_WARNING:
74 case PSI_T_ERROR:
75 if (!exp->data.tok) {
76 break;
77 }
78 /* no break */
79 case PSI_T_UNDEF:
80 case PSI_T_IFDEF:
81 case PSI_T_IFNDEF:
82 case PSI_T_IMPORT:
83 case PSI_T_INCLUDE:
84 case PSI_T_INCLUDE_NEXT:
85 free(exp->data.tok);
86 exp->data.tok = NULL;
87 break;
88 case PSI_T_DEFINE:
89 psi_cpp_macro_decl_free(&exp->data.decl);
90 break;
91 case PSI_T_IF:
92 case PSI_T_ELIF:
93 psi_num_exp_free(&exp->data.num);
94 break;
95 case PSI_T_ENDIF:
96 case PSI_T_ELSE:
97 break;
98 default:
99 assert(0);
100 break;
101 }
102 if (exp->token) {
103 free(exp->token);
104 }
105 free(exp);
106 }
107 }
108
109 void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp)
110 {
111 dprintf(fd, "#%s ", exp->token->text);
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 case PSI_T_IMPORT:
123 case PSI_T_INCLUDE:
124 case PSI_T_INCLUDE_NEXT:
125 dprintf(fd, "%s", exp->data.tok->text);
126 break;
127 case PSI_T_DEFINE:
128 psi_cpp_macro_decl_dump(fd, exp->data.decl);
129 break;
130 case PSI_T_IF:
131 case PSI_T_ELIF:
132 psi_num_exp_dump(fd, exp->data.num);
133 break;
134 case PSI_T_ENDIF:
135 case PSI_T_ELSE:
136 break;
137 default:
138 assert(0);
139 break;
140 }
141 dprintf(fd, "\n");
142 }
143
144
145 static inline bool psi_cpp_level_skipped(struct psi_cpp *cpp)
146 {
147 return cpp->skip == cpp->level;
148 }
149
150 static inline void psi_cpp_level_skip(struct psi_cpp *cpp)
151 {
152 assert(!cpp->skip);
153 cpp->skip = cpp->level;
154 }
155
156 static inline void psi_cpp_level_unskip(struct psi_cpp *cpp)
157 {
158 if (psi_cpp_level_skipped(cpp)) {
159 cpp->skip = 0;
160 }
161 }
162
163 static inline bool psi_cpp_level_masked(struct psi_cpp *cpp)
164 {
165 return cpp->seen & (1 << cpp->level);
166 }
167
168 static inline void psi_cpp_level_mask(struct psi_cpp *cpp)
169 {
170 assert(!psi_cpp_level_masked(cpp));
171 cpp->seen |= (1 << cpp->level);
172 }
173
174 static inline void psi_cpp_level_unmask(struct psi_cpp *cpp)
175 {
176 cpp->seen &= ~(1 << cpp->level);
177 }
178
179 void psi_cpp_exp_exec(struct psi_cpp_exp *exp, struct psi_cpp *cpp, struct psi_data *D)
180 {
181 PSI_DEBUG_PRINT(D, "PSI: CPP EVAL < %s (level=%u, skip=%u)\n",
182 exp->token->text, cpp->level, cpp->skip);
183
184 #if PSI_CPP_DEBUG
185 psi_cpp_exp_dump(2, exp);
186 #endif
187
188 switch (exp->type) {
189 case PSI_T_ERROR:
190 if (!cpp->skip) {
191 D->error(D, exp->token, PSI_ERROR, "%s",
192 exp->data.tok ? exp->data.tok->text : "");
193 }
194 break;
195 case PSI_T_WARNING:
196 if (!cpp->skip) {
197 D->error(D, exp->token, PSI_WARNING, "%s",
198 exp->data.tok ? exp->data.tok->text : "");
199 }
200 break;
201 case PSI_T_UNDEF:
202 if (!cpp->skip) {
203 psi_cpp_undef(cpp, exp->data.tok);
204 }
205 break;
206 case PSI_T_DEFINE:
207 if (!cpp->skip) {
208 psi_cpp_define(cpp, exp->data.decl);
209 /* FIXME: copy */
210 exp->data.decl = NULL;
211 }
212 break;
213 case PSI_T_IFDEF:
214 ++cpp->level;
215 if (!cpp->skip) {
216 if (psi_cpp_defined(cpp, exp->data.tok)) {
217 psi_cpp_level_mask(cpp);
218 } else {
219 psi_cpp_level_skip(cpp);
220 }
221 }
222 break;
223 case PSI_T_IFNDEF:
224 ++cpp->level;
225 if (!cpp->skip) {
226 if (psi_cpp_defined(cpp, exp->data.tok)) {
227 psi_cpp_level_skip(cpp);
228 } else {
229 psi_cpp_level_mask(cpp);
230 }
231 }
232 break;
233 case PSI_T_IF:
234 ++cpp->level;
235 if (!cpp->skip) {
236 if (psi_cpp_if(cpp, exp)) {
237 psi_cpp_level_mask(cpp);
238 } else {
239 psi_cpp_level_skip(cpp);
240 }
241 }
242 break;
243 case PSI_T_ENDIF:
244 if (!cpp->level) {
245 D->error(D, exp->token, PSI_WARNING, "Ingoring lone #endif");
246 } else {
247 psi_cpp_level_unskip(cpp);
248 psi_cpp_level_unmask(cpp);
249 --cpp->level;
250 }
251 break;
252 case PSI_T_ELSE:
253 /* FIXME: catch "else" after "else" */
254 if (!cpp->level) {
255 D->error(D, exp->token, PSI_WARNING, "Ingoring lone #else");
256 } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) {
257 /*
258 * if skip is set on this level and the level has
259 * not been masked yet, then unskip and mask this level
260 */
261 psi_cpp_level_unskip(cpp);
262 psi_cpp_level_mask(cpp);
263 } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
264 /*
265 * previous block masked this level
266 */
267 psi_cpp_level_skip(cpp);
268 } else {
269 assert(cpp->skip <= cpp->level);
270 }
271 break;
272 case PSI_T_ELIF:
273 if (!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)) {
276 /*
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
280 */
281 if (psi_cpp_if(cpp, exp)) {
282 psi_cpp_level_unskip(cpp);
283 psi_cpp_level_mask(cpp);
284 }
285 } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
286 /*
287 * previous block masked this level
288 */
289 psi_cpp_level_skip(cpp);
290 } else {
291 assert(cpp->skip <= cpp->level);
292 }
293 break;
294 case PSI_T_INCLUDE:
295 if (!cpp->skip) {
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);
298 }
299 }
300 break;
301 case PSI_T_INCLUDE_NEXT:
302 if (!cpp->skip) {
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);
305 }
306 }
307 break;
308 default:
309 assert(0);
310 break;
311 }
312
313 PSI_DEBUG_PRINT(D, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n",
314 exp->token->text, cpp->level, cpp->skip);
315 }