f2b468eacee0cae9c7384c57dea7c95388294f09
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"
31 void psi_cpp_tokiter_dump(int fd
, struct psi_cpp
*cpp
)
33 size_t i
= cpp
->index
;
41 while (psi_plist_get(cpp
->tokens
.iter
, i
, &T
)) {
42 dprintf(fd
, "PSI: CPP tokens %5zu %c ", i
, cpp
->index
== i
? '*' : ' ');
44 psi_token_dump(fd
, T
);
46 dprintf(fd
, "TOKEN deleted\n");
48 if (i
>= cpp
->index
+ 40) {
49 dprintf(fd
, "PSI: CPP tokens .....\n");
56 void psi_cpp_tokiter_reset(struct psi_cpp
*cpp
)
59 fprintf(stderr
, "PSI: CPP reset -> iter.count=%zu, next.count=%zu\n",
60 psi_plist_count(cpp
->tokens
.iter
),
61 psi_plist_count(cpp
->tokens
.next
));
62 # if PSI_CPP_DEBUG > 1
63 psi_cpp_tokiter_dump(2, cpp
);
69 if (cpp
->tokens
.next
) {
70 free(cpp
->tokens
.iter
);
71 cpp
->tokens
.iter
= cpp
->tokens
.next
;
73 cpp
->tokens
.next
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
76 bool psi_cpp_tokiter_seek(struct psi_cpp
*cpp
, size_t index
)
78 if (index
< psi_plist_count(cpp
->tokens
.iter
)) {
85 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp
*cpp
)
87 struct psi_token
*current
= NULL
;
88 bool found
= psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, ¤t
);
95 size_t psi_cpp_tokiter_index(struct psi_cpp
*cpp
)
100 bool psi_cpp_tokiter_add_cur(struct psi_cpp
*cpp
)
102 struct psi_token
*cur
= NULL
;
104 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
105 struct psi_plist
*tokens
= psi_plist_add(cpp
->tokens
.next
, &cur
);
108 cpp
->tokens
.next
= tokens
;
111 fprintf(stderr
, "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu ",
112 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
113 psi_token_dump(2, cur
);
123 bool psi_cpp_tokiter_add(struct psi_cpp
*cpp
, struct psi_token
*tok
)
125 struct psi_plist
*tokens
= psi_plist_add(cpp
->tokens
.next
, &tok
);
130 cpp
->tokens
.next
= tokens
;
133 fprintf(stderr
, "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu ",
134 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
135 psi_token_dump(2, tok
);
142 bool psi_cpp_tokiter_add_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
144 struct psi_plist
*tokens
;
150 tokens
= psi_plist_add_r(cpp
->tokens
.next
, num_eles
, eles
);
154 cpp
->tokens
.next
= tokens
;
157 fprintf(stderr
, "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
158 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
165 void psi_cpp_tokiter_next(struct psi_cpp
*cpp
)
167 #if 0 && PSI_CPP_DEBUG
168 fprintf(stderr
, "PSI: CPP next -> index=%zu -> index=%zu\n",
169 cpp
->index
, cpp
->index
+1);
174 bool psi_cpp_tokiter_valid(struct psi_cpp
*cpp
)
176 #if 0 && PSI_CPP_DEBUG
177 fprintf(stderr
, "PSI: CPP valid -> index=%zu -> %d\n",
178 cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
.iter
));
180 return cpp
->index
< psi_plist_count(cpp
->tokens
.iter
);
183 bool psi_cpp_tokiter_del_prev(struct psi_cpp
*cpp
, bool free_token
)
185 struct psi_token
*cur
= NULL
;
188 fprintf(stderr
, "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count\n",
189 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
));
192 if (psi_plist_pop(cpp
->tokens
.next
, NULL
) && psi_plist_get(cpp
->tokens
.iter
, cpp
->index
- 1, &cur
)) {
193 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
- 1);
194 if (free_token
&& cur
) {
195 psi_token_free(&cur
);
202 bool psi_cpp_tokiter_del_cur(struct psi_cpp
*cpp
, bool free_token
)
204 struct psi_token
*cur
= NULL
;
207 fprintf(stderr
, "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu ",
208 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
211 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
213 psi_token_dump(2, cur
);
215 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
);
216 if (free_token
&& cur
) {
217 psi_token_free(&cur
);
226 bool psi_cpp_tokiter_del_range(struct psi_cpp
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
228 struct psi_token
*ptr
;
232 fprintf(stderr
, "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
233 cpp
->index
, offset
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
236 for (i
= offset
; i
< offset
+ num_eles
; ++i
) {
237 if (!psi_plist_get(cpp
->tokens
.iter
, i
, &ptr
)) {
241 fprintf(stderr
, "PSI: CPP del_range -> ");
242 psi_token_dump(2, ptr
);
244 psi_plist_unset(cpp
->tokens
.iter
, i
);
245 if (free_tokens
&& ptr
) {
246 psi_token_free(&ptr
);
254 bool psi_cpp_tokiter_ins_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
256 struct psi_plist
*tokens
;
262 tokens
= psi_plist_ins_r(cpp
->tokens
.iter
, cpp
->index
, num_eles
, eles
);
266 cpp
->tokens
.iter
= tokens
;
269 fprintf(stderr
, "PSI: CPP ins_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
270 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
276 bool psi_cpp_tokiter_defined(struct psi_cpp
*cpp
)
278 if (psi_cpp_tokiter_valid(cpp
)) {
279 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
281 return psi_cpp_defined(cpp
, current
);
287 static size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp
*cpp
,
288 struct psi_token
*target
, struct psi_plist
*tokens
)
290 if (tokens
&& psi_plist_count(tokens
)) {
292 bool stringify
= false, paste
= false;
293 struct psi_token
*tok
, **exp_tokens
= calloc(psi_plist_count(tokens
), sizeof(*exp_tokens
));
295 while (psi_plist_get(tokens
, i
++, &tok
)) {
296 struct psi_token
*new_tok
;
298 if (tok
->type
== PSI_T_EOL
) {
301 if (tok
->type
== PSI_T_HASH
) {
305 if (tok
->type
== PSI_T_CPP_PASTE
) {
310 if (paste
&& n
> 0 && exp_tokens
[n
- 1]) {
311 struct psi_token
*tmp_tok
, *old_tok
= exp_tokens
[n
- 1];
313 tmp_tok
= psi_token_init(old_tok
->type
, "", 0,
314 target
->col
, target
->line
,
315 target
->file
? target
->file
: zend_empty_string
);
317 new_tok
= psi_token_cat(NULL
, 3, tmp_tok
, old_tok
, tok
);
318 psi_token_free(&old_tok
);
319 psi_token_free(&tmp_tok
);
321 exp_tokens
[n
- 1] = new_tok
;
323 new_tok
= psi_token_init(stringify
? PSI_T_QUOTED_STRING
: tok
->type
,
324 tok
->text
->val
, tok
->text
->len
, target
->col
, target
->line
,
325 target
->file
?: zend_empty_string
);
327 exp_tokens
[n
++] = new_tok
;
331 fprintf(stderr
, "PSI: CPP expand > ");
332 psi_token_dump(2, tok
);
338 psi_cpp_tokiter_ins_range(cpp
, n
, (void *) exp_tokens
);
347 static void psi_cpp_tokiter_free_call_tokens(struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
351 for (i
= 0; i
< arg_count
; ++i
) {
352 if (arg_tokens_list
[i
]) {
354 struct psi_token
*tok
;
356 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
357 psi_token_free(&tok
);
360 psi_plist_free(arg_tokens_list
[i
]);
363 free(arg_tokens_list
);
366 static struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
367 struct psi_cpp
*cpp
, size_t arg_count
)
369 size_t arg_index
= 0, lparens
= 1, rparens
= 0;
370 struct psi_plist
**arg_tokens
= calloc(arg_count
, sizeof(*arg_tokens
));
371 struct psi_plist
*free_tokens
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
372 struct psi_token
*tok
;
374 arg_tokens
[0] = psi_plist_init(NULL
);
376 /* next token must be a LPAREN for a macro call */
377 psi_cpp_tokiter_next(cpp
);
378 tok
= psi_cpp_tokiter_current(cpp
);
379 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
383 /* free LPAREN on success */
384 free_tokens
= psi_plist_add(free_tokens
, &tok
);
386 while (lparens
> rparens
) {
387 psi_cpp_tokiter_next(cpp
);
388 if (!psi_cpp_tokiter_valid(cpp
)) {
391 tok
= psi_cpp_tokiter_current(cpp
);
396 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
399 if (++rparens
== lparens
) {
401 if (arg_index
+ 1 < arg_count
) {
404 free_tokens
= psi_plist_add(free_tokens
, &tok
);
406 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
410 if (1 == (lparens
- rparens
)) {
411 /* too many commas? */
412 if (++arg_index
>= arg_count
) {
415 free_tokens
= psi_plist_add(free_tokens
, &tok
);
417 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
419 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
423 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
427 psi_plist_free(free_tokens
);
431 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
435 static void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp
*cpp
,
436 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
,
437 struct psi_plist
**arg_tokens_list
)
440 struct psi_token
*tok
;
441 struct psi_plist
*tokens
= psi_plist_init(NULL
);
443 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
444 struct psi_plist
*arg_tokens
= NULL
;
446 if (tok
->type
== PSI_T_NAME
) {
448 struct psi_token
*arg_name
;
450 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
451 if (zend_string_equals(arg_name
->text
, tok
->text
)) {
452 arg_tokens
= arg_tokens_list
[s
];
459 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
461 tokens
= psi_plist_add(tokens
, &tok
);
465 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
466 psi_plist_free(tokens
);
469 static bool psi_cpp_tokiter_expand_call(struct psi_cpp
*cpp
,
470 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
472 /* function-like macro
473 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
474 * # if FOO(1,2) // expands to if 1 > 2
476 size_t start
= psi_cpp_tokiter_index(cpp
);
477 struct psi_plist
**arg_tokens_list
;
479 /* read in tokens, until we have balanced parens */
480 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, psi_plist_count(macro
->sig
));
481 if (!arg_tokens_list
) {
482 psi_cpp_tokiter_seek(cpp
, start
);
486 /* ditch arg tokens */
487 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
489 /* insert and expand macro tokens */
490 psi_cpp_tokiter_expand_call_tokens(cpp
, target
, macro
, arg_tokens_list
);
491 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, psi_plist_count(macro
->sig
), true);
493 psi_token_free(&target
);
498 static bool psi_cpp_tokiter_expand_def(struct psi_cpp
*cpp
,
499 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
501 /* delete current token from stream */
502 psi_cpp_tokiter_del_cur(cpp
, false);
503 /* replace with tokens from macro */
504 psi_cpp_tokiter_expand_tokens(cpp
, target
, macro
->tokens
);
506 psi_token_free(&target
);
511 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token
*t
,
512 struct psi_cpp_macro_decl
*m
)
514 if (psi_plist_count(m
->tokens
) == 1) {
517 psi_plist_get(m
->tokens
, 0, &r
);
519 return !zend_string_equals(r
->text
, t
->text
);
524 bool psi_cpp_tokiter_expand(struct psi_cpp
*cpp
)
526 if (psi_cpp_tokiter_valid(cpp
)) {
527 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
530 struct psi_cpp_macro_decl
*macro
= zend_hash_find_ptr(
531 &cpp
->defs
, current
->text
);
533 /* don't expand itself */
534 if (macro
&& macro
->token
!= current
) {
536 fprintf(stderr
, "PSI: CPP expand < ");
537 psi_token_dump(2, current
);
540 return psi_cpp_tokiter_expand_call(cpp
, current
, macro
);
541 } else if (psi_cpp_tokiter_expand_cmp(current
, macro
)) {
542 return psi_cpp_tokiter_expand_def(cpp
, current
, macro
);