51daaa9bb794a850e3ae215b152471a941255a62
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"
32 void psi_cpp_tokiter_dump(int fd
, struct psi_cpp
*cpp
)
34 size_t i
= cpp
->index
;
42 while (psi_plist_get(cpp
->tokens
, i
, &T
)) {
43 dprintf(fd
, "PSI: CPP tokens %5zu %c ", i
, cpp
->index
== i
? '*' : ' ');
44 psi_token_dump(fd
, T
);
45 if (i
>= cpp
->index
+ 10) {
46 dprintf(fd
, "PSI: CPP tokens .....\n");
54 void psi_cpp_tokiter_reset(struct psi_cpp
*cpp
)
57 fprintf(stderr
, "PSI: CPP reset (%zu tokens)\n", psi_plist_count(cpp
->tokens
));
58 # if PSI_CPP_DEBUG > 1
59 psi_cpp_tokiter_dump(2, cpp
);
66 bool psi_cpp_tokiter_seek(struct psi_cpp
*cpp
, size_t index
)
68 if (index
< psi_plist_count(cpp
->tokens
)) {
75 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp
*cpp
)
77 struct psi_token
*current
= NULL
;
78 bool found
= psi_plist_get(cpp
->tokens
, cpp
->index
, ¤t
);
85 size_t psi_cpp_tokiter_index(struct psi_cpp
*cpp
)
90 void psi_cpp_tokiter_next(struct psi_cpp
*cpp
)
92 #if 0 && PSI_CPP_DEBUG
93 fprintf(stderr
, "PSI: CPP next -> index=%zu -> index=%zu\n", cpp
->index
, cpp
->index
+1);
98 void psi_cpp_tokiter_prev(struct psi_cpp
*cpp
)
100 #if 0 && PSI_CPP_DEBUG
101 fprintf(stderr
, "PSI: CPP prev -> index=%zu -> index=%zu\n", cpp
->index
, cpp
->index
-1);
108 bool psi_cpp_tokiter_valid(struct psi_cpp
*cpp
)
110 #if 0 && PSI_CPP_DEBUG
111 fprintf(stderr
, "PSI: CPP valid -> index=%zu -> %d\n", cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
));
113 return cpp
->index
< psi_plist_count(cpp
->tokens
);
116 bool psi_cpp_tokiter_del_cur(struct psi_cpp
*cpp
, bool free_token
)
118 struct psi_token
*cur
= NULL
;
119 bool deleted
= psi_plist_del(cpp
->tokens
, cpp
->index
, &cur
);
123 fprintf(stderr
, "PSI: CPP del_cur -> index=%zu, del=%d, free=%d, count=%zu ",
124 cpp
->index
, (int) deleted
, (int) free_token
, psi_plist_count(cpp
->tokens
));
126 psi_token_dump(2, cur
);
128 fprintf(stderr
, "NULL\n");
131 if (cur
&& free_token
) {
134 count
= psi_plist_count(cpp
->tokens
);
135 if (deleted
&& cpp
->index
>= count
) {
137 cpp
->index
= count
- 1;
145 bool psi_cpp_tokiter_del_range(struct psi_cpp
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
147 struct psi_token
**ptr
;
151 ptr
= calloc(num_eles
, sizeof(*ptr
));
157 fprintf(stderr
, "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, count=%zu\n",
158 cpp
->index
, offset
, num_eles
, psi_plist_count(cpp
->tokens
));
161 deleted
= psi_plist_del_r(cpp
->tokens
, offset
, num_eles
, (void *) ptr
);
164 size_t count
= psi_plist_count(cpp
->tokens
);
166 if (cpp
->index
>= count
) {
168 cpp
->index
= count
- 1;
186 bool psi_cpp_tokiter_ins_cur(struct psi_cpp
*cpp
, struct psi_token
*tok
)
188 struct psi_plist
*tokens
= psi_plist_ins(cpp
->tokens
, cpp
->index
, &tok
);
191 fprintf(stderr
, "PSI: CPP ins_cur -> index=%zu ", cpp
->index
);
192 psi_token_dump(2, tok
);
198 cpp
->tokens
= tokens
;
202 bool psi_cpp_tokiter_ins_range(struct psi_cpp
*cpp
, size_t offset
,
203 size_t num_eles
, void **eles
)
205 struct psi_plist
*tokens
;
211 tokens
= psi_plist_ins_r(cpp
->tokens
, offset
, num_eles
, eles
);
214 fprintf(stderr
, "PSI: CPP ins_range -> index=%zu, offset=%zu, num_eles=%zu, count=%zu\n",
215 cpp
->index
, offset
, num_eles
, psi_plist_count(tokens
));
221 cpp
->tokens
= tokens
;
225 bool psi_cpp_tokiter_defined(struct psi_cpp
*cpp
)
227 if (psi_cpp_tokiter_valid(cpp
)) {
228 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
230 return psi_cpp_defined(cpp
, current
);
236 void psi_cpp_tokiter_expand_tokens(struct psi_cpp
*cpp
, struct psi_plist
*tokens
)
238 if (tokens
&& psi_plist_count(tokens
)) {
240 bool stringify
= false, paste
= false;
241 struct psi_token
*tok
, **exp_tokens
= calloc(psi_plist_count(tokens
), sizeof(*exp_tokens
));
243 while (psi_plist_get(tokens
, i
++, &tok
)) {
244 struct psi_token
*new_tok
;
246 if (tok
->type
== PSI_T_EOL
) {
249 if (tok
->type
== PSI_T_HASH
) {
253 if (tok
->type
== PSI_T_CPP_PASTE
) {
258 if (paste
&& n
> 0 && exp_tokens
[n
- 1] &&
259 (new_tok
= psi_token_cat(NULL
, 2, exp_tokens
[n
- 1], tok
))) {
260 free(exp_tokens
[n
- 1]);
261 exp_tokens
[n
- 1] = new_tok
;
263 struct psi_token
*cpy
= psi_token_copy(tok
);
266 cpy
->type
= PSI_T_QUOTED_STRING
;
268 exp_tokens
[n
++] = cpy
;
272 fprintf(stderr
, "PSI: CPP expand > ");
273 psi_token_dump(2, tok
);
279 psi_cpp_tokiter_ins_range(cpp
, psi_cpp_tokiter_index(cpp
), n
, (void *) exp_tokens
);
284 static void psi_cpp_tokiter_free_call_tokens(struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
288 for (i
= 0; i
< arg_count
; ++i
) {
289 if (arg_tokens_list
[i
]) {
291 struct psi_token
*tok
;
293 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
297 psi_plist_free(arg_tokens_list
[i
]);
300 free(arg_tokens_list
);
303 static struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
304 struct psi_cpp
*cpp
, size_t arg_count
)
306 size_t arg_index
= 0, lparens
= 1, rparens
= 0;
307 struct psi_plist
**arg_tokens
= calloc(arg_count
, sizeof(*arg_tokens
));
308 struct psi_plist
*free_tokens
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
309 struct psi_token
*tok
;
311 arg_tokens
[0] = psi_plist_init(NULL
);
313 /* free macro name token on success */
314 tok
= psi_cpp_tokiter_current(cpp
);
315 free_tokens
= psi_plist_add(free_tokens
, &tok
);
317 /* next token must be a LPAREN for a macro call */
318 psi_cpp_tokiter_next(cpp
);
319 tok
= psi_cpp_tokiter_current(cpp
);
320 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
324 /* free LPAREN on success */
325 free_tokens
= psi_plist_add(free_tokens
, &tok
);
327 while (lparens
> rparens
) {
328 psi_cpp_tokiter_next(cpp
);
329 if (!psi_cpp_tokiter_valid(cpp
)) {
332 tok
= psi_cpp_tokiter_current(cpp
);
337 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
340 if (++rparens
== lparens
) {
342 if (arg_index
+ 1 < arg_count
) {
345 free_tokens
= psi_plist_add(free_tokens
, &tok
);
347 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
351 if (1 == (lparens
- rparens
)) {
352 /* too many commas? */
353 if (++arg_index
>= arg_count
) {
356 free_tokens
= psi_plist_add(free_tokens
, &tok
);
358 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
360 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
364 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
368 psi_plist_free(free_tokens
);
372 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
376 static void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp
*cpp
,
377 struct psi_cpp_macro_decl
*macro
, struct psi_plist
**arg_tokens_list
)
380 struct psi_token
*tok
;
381 struct psi_plist
*tokens
= psi_plist_init(NULL
);
383 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
384 struct psi_plist
*arg_tokens
= NULL
;
386 if (tok
->type
== PSI_T_NAME
) {
388 struct psi_token
*arg_name
;
390 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
391 if (arg_name
->size
== tok
->size
) {
392 if (!memcmp(arg_name
->text
, tok
->text
, tok
->size
)) {
393 arg_tokens
= arg_tokens_list
[s
];
401 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
403 tokens
= psi_plist_add(tokens
, &tok
);
407 psi_cpp_tokiter_expand_tokens(cpp
, tokens
);
408 psi_plist_free(tokens
);
411 static bool psi_cpp_tokiter_expand_call(struct psi_cpp
*cpp
,
412 struct psi_cpp_macro_decl
*macro
)
414 /* function-like macro
415 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
416 * # if FOO(1,2) // expands to if 1 > 2
418 size_t start
= psi_cpp_tokiter_index(cpp
);
419 struct psi_plist
**arg_tokens_list
;
421 /* read in tokens, until we have balanced parens */
422 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, psi_plist_count(macro
->sig
));
423 if (!arg_tokens_list
) {
424 psi_cpp_tokiter_seek(cpp
, start
);
428 /* ditch arg tokens */
429 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
430 psi_cpp_tokiter_seek(cpp
, start
);
432 /* insert and expand macro tokens */
433 psi_cpp_tokiter_expand_call_tokens(cpp
, macro
, arg_tokens_list
);
434 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, psi_plist_count(macro
->sig
), true);
436 /* back to where we took off */
437 psi_cpp_tokiter_seek(cpp
, start
);
442 bool psi_cpp_tokiter_expand(struct psi_cpp
*cpp
)
444 if (psi_cpp_tokiter_valid(cpp
)) {
445 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
448 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(
449 &cpp
->defs
, current
->text
, current
->size
);
451 /* don't expand itself */
452 if (macro
&& macro
->token
!= current
) {
454 fprintf(stderr
, "PSI: CPP expand < ");
455 psi_token_dump(2, current
);
458 return psi_cpp_tokiter_expand_call(cpp
, macro
);
460 size_t index
= psi_cpp_tokiter_index(cpp
);
462 /* delete current token from stream */
463 psi_cpp_tokiter_del_cur(cpp
, true);
465 if (index
!= psi_cpp_tokiter_index(cpp
)) {
466 /* might have been last token */
467 psi_cpp_tokiter_next(cpp
);
469 /* replace with tokens from macro */
470 psi_cpp_tokiter_expand_tokens(cpp
, macro
->tokens
);