fdf6e86b6cb16c186b799f3add0592e2cd36e6c4
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 *******************************************************************************/
29 # include "php_config.h"
35 void psi_cpp_tokiter_dump(struct psi_dump
*dump
, struct psi_cpp
*cpp
);
36 void psi_cpp_tokiter_dump(struct psi_dump
*dump
, struct psi_cpp
*cpp
)
38 size_t i
= cpp
->index
;
46 while (psi_plist_get(cpp
->tokens
.iter
, i
, &T
)) {
47 PSI_DUMP(dump
, "PSI: CPP tokens %5zu %c ", i
, cpp
->index
== i
? '*' : ' ');
48 psi_token_dump(dump
, T
);
49 if (i
>= cpp
->index
+ 40) {
50 PSI_DUMP(dump
, "PSI: CPP tokens .....\n");
57 void psi_cpp_tokiter_reset(struct psi_cpp
*cpp
)
66 if (cpp
->tokens
.next
) {
67 psi_plist_free(cpp
->tokens
.iter
);
68 cpp
->tokens
.iter
= cpp
->tokens
.next
;
70 cpp
->tokens
.next
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
71 if (cpp
->tokens
.exec
) {
72 assert(!psi_plist_count(cpp
->tokens
.exec
));
73 psi_plist_clean(cpp
->tokens
.exec
);
75 cpp
->tokens
.exec
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
78 PSI_DEBUG_PRINT(cpp
->parser
,
79 "PSI: CPP reset -> iter.count=%zu, next.count=%zu, exec.count=%zu\n",
80 psi_plist_count(cpp
->tokens
.iter
),
81 psi_plist_count(cpp
->tokens
.next
),
82 psi_plist_count(cpp
->tokens
.exec
));
83 # if PSI_CPP_DEBUG > 1
84 PSI_DEBUG_DUMP(cpp
->parser
, psi_cpp_tokiter_dump
, cpp
);
89 bool psi_cpp_tokiter_seek(struct psi_cpp
*cpp
, size_t index
)
91 if (index
< psi_plist_count(cpp
->tokens
.iter
)) {
98 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp
*cpp
)
100 struct psi_token
*current
= NULL
;
101 bool found
= psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, ¤t
);
108 size_t psi_cpp_tokiter_index(struct psi_cpp
*cpp
)
113 bool psi_cpp_tokiter_add_cur(struct psi_cpp
*cpp
)
115 struct psi_token
*cur
= NULL
;
117 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
118 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
);
120 cpp
->tokens
.exec
= psi_plist_add(cpp
->tokens
.exec
, &cur
);
122 cpp
->tokens
.next
= psi_plist_add(cpp
->tokens
.next
, &cur
);
126 PSI_DEBUG_PRINT(cpp
->parser
,
127 "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
128 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
129 psi_plist_count(cpp
->tokens
.exec
));
130 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
139 bool psi_cpp_tokiter_add(struct psi_cpp
*cpp
, struct psi_token
*tok
)
142 cpp
->tokens
.exec
= psi_plist_add(cpp
->tokens
.exec
, &tok
);
144 cpp
->tokens
.next
= psi_plist_add(cpp
->tokens
.next
, &tok
);
148 PSI_DEBUG_PRINT(cpp
->parser
,
149 "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
150 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
151 psi_plist_count(cpp
->tokens
.exec
));
152 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, tok
);
159 bool psi_cpp_tokiter_add_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
166 cpp
->tokens
.exec
= psi_plist_add_r(cpp
->tokens
.exec
, num_eles
, eles
);
168 cpp
->tokens
.next
= psi_plist_add_r(cpp
->tokens
.next
, num_eles
, eles
);
172 PSI_DEBUG_PRINT(cpp
->parser
,
173 "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
174 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
175 psi_plist_count(cpp
->tokens
.exec
));
182 void psi_cpp_tokiter_next(struct psi_cpp
*cpp
)
184 #if 0 && PSI_CPP_DEBUG
185 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP next -> index=%zu -> index=%zu\n",
186 cpp
->index
, cpp
->index
+1);
191 bool psi_cpp_tokiter_valid(struct psi_cpp
*cpp
)
193 #if PSI_CPP_DEBUG > 1
194 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP valid -> index=%zu -> %s\n",
195 cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
.iter
)
198 return cpp
->index
< psi_plist_count(cpp
->tokens
.iter
);
201 bool psi_cpp_tokiter_del_prev(struct psi_cpp
*cpp
, bool free_token
)
203 struct psi_token
*cur
= NULL
;
206 PSI_DEBUG_PRINT(cpp
->parser
,
207 "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
208 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
209 psi_plist_count(cpp
->tokens
.exec
));
213 if (!psi_plist_pop(cpp
->tokens
.exec
, &cur
)) {
216 } else if (!psi_plist_pop(cpp
->tokens
.next
, &cur
)) {
219 if (free_token
&& cur
) {
220 psi_token_free(&cur
);
225 bool psi_cpp_tokiter_del_cur(struct psi_cpp
*cpp
, bool free_token
)
227 struct psi_token
*cur
= NULL
;
230 PSI_DEBUG_PRINT(cpp
->parser
,
231 "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
232 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
233 psi_plist_count(cpp
->tokens
.exec
));
236 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
238 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
240 if (cpp
->index
== psi_plist_count(cpp
->tokens
.iter
) - 1) {
241 psi_plist_pop(cpp
->tokens
.iter
, NULL
);
243 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
);
245 if (free_token
&& cur
) {
246 psi_token_free(&cur
);
255 bool psi_cpp_tokiter_del_range(struct psi_cpp
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
257 struct psi_token
*ptr
;
261 PSI_DEBUG_PRINT(cpp
->parser
,
262 "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
263 cpp
->index
, offset
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
264 psi_plist_count(cpp
->tokens
.exec
));
267 for (i
= offset
; i
< offset
+ num_eles
; ++i
) {
268 if (!psi_plist_get(cpp
->tokens
.iter
, i
, &ptr
)) {
272 PSI_DEBUG_LOCK(cpp
->parser
,
273 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_range -> ");
274 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, ptr
);
277 psi_plist_unset(cpp
->tokens
.iter
, i
);
278 if (free_tokens
&& ptr
) {
279 psi_token_free(&ptr
);
287 bool psi_cpp_tokiter_defined(struct psi_cpp
*cpp
)
289 if (psi_cpp_tokiter_valid(cpp
)) {
290 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
292 return psi_cpp_defined(cpp
, current
);
298 static inline size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp
*cpp
,
299 struct psi_token
*target
, struct psi_plist
*tokens
)
302 bool stringify
= false, paste
= false;
303 struct psi_token
*tok
;
304 struct psi_plist
*exp
;
306 if (!psi_plist_count(tokens
)) {
310 exp
= psi_plist_init(NULL
);
311 while (psi_plist_get(tokens
, i
++, &tok
)) {
312 struct psi_token
*new_tok
;
314 if (tok
->type
== PSI_T_EOL
) {
317 if (tok
->type
== PSI_T_HASH
) {
321 if (tok
->type
== PSI_T_CPP_PASTE
) {
326 if (paste
&& psi_plist_count(exp
)) {
327 struct psi_token
*old_tok
;
328 struct psi_parser_input
*toscan
;
330 psi_plist_pop(exp
, &old_tok
);
331 new_tok
= psi_token_cat(NULL
, 2, old_tok
, tok
);
333 /* reclassify token(s) */
334 if ((toscan
= psi_parser_open_string(cpp
->parser
, new_tok
->text
->val
, new_tok
->text
->len
))) {
335 struct psi_plist
*scanned
;
337 scanned
= psi_parser_scan(cpp
->parser
, toscan
);
338 if (psi_plist_count(scanned
)) {
340 struct psi_token
*tmp_tok
;
342 exp
= psi_plist_add_r(exp
, psi_plist_count(scanned
), psi_plist_eles(scanned
));
345 while (psi_plist_get(scanned
, i
++, &tmp_tok
)) {
346 zend_string_release(tmp_tok
->file
);
347 tmp_tok
->file
= zend_string_copy(new_tok
->file
);
348 tmp_tok
->line
= new_tok
->line
;
349 tmp_tok
->col
= new_tok
->col
;
352 psi_token_free(&new_tok
);
353 psi_plist_top(scanned
, &new_tok
);
355 exp
= psi_plist_add(exp
, &new_tok
);
360 psi_parser_input_free(&toscan
);
362 exp
= psi_plist_add(exp
, &new_tok
);
365 psi_token_free(&old_tok
);
367 new_tok
= psi_token_init(stringify
? PSI_T_QUOTED_STRING
: tok
->type
,
368 tok
->text
->val
, tok
->text
->len
, target
->col
, target
->line
,
369 target
->file
?: zend_empty_string
);
371 exp
= psi_plist_add(exp
, &new_tok
);
375 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand > ");
376 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, new_tok
);
383 bool processed
= psi_cpp_process(cpp
, &exp
, target
);
386 n
= psi_plist_count(exp
);
387 psi_cpp_tokiter_add_range(cpp
, n
, psi_plist_eles(exp
));
393 static inline void psi_cpp_tokiter_free_call_tokens(
394 struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
398 for (i
= 0; i
< arg_count
; ++i
) {
399 if (arg_tokens_list
[i
]) {
401 struct psi_token
*tok
;
403 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
404 psi_token_free(&tok
);
407 psi_plist_free(arg_tokens_list
[i
]);
410 free(arg_tokens_list
);
413 static inline struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
414 struct psi_cpp
*cpp
, size_t arg_count
)
416 size_t arg_index
= 0, lparens
= 1, rparens
= 0, start
= psi_cpp_tokiter_index(cpp
);
417 struct psi_plist
**arg_tokens
= pecalloc(arg_count
, sizeof(*arg_tokens
), 1);
418 struct psi_plist
*free_tokens
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
419 struct psi_token
*tok
;
421 arg_tokens
[0] = psi_plist_init(NULL
);
423 /* next token must be a LPAREN for a macro call */
424 psi_cpp_tokiter_next(cpp
);
425 tok
= psi_cpp_tokiter_current(cpp
);
426 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
430 /* free LPAREN on success */
431 free_tokens
= psi_plist_add(free_tokens
, &tok
);
433 while (lparens
> rparens
) {
434 psi_cpp_tokiter_next(cpp
);
435 if (!psi_cpp_tokiter_valid(cpp
)) {
438 tok
= psi_cpp_tokiter_current(cpp
);
443 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
446 if (++rparens
== lparens
) {
448 if (arg_index
+ 1 < arg_count
) {
451 free_tokens
= psi_plist_add(free_tokens
, &tok
);
453 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
457 if (1 == (lparens
- rparens
)) {
458 /* too many commas? */
459 if (++arg_index
>= arg_count
) {
462 free_tokens
= psi_plist_add(free_tokens
, &tok
);
464 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
466 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
470 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
474 /* ditch arg tokens */
475 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
476 psi_plist_free(free_tokens
);
481 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
485 static inline void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp
*cpp
,
486 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
,
487 struct psi_plist
**arg_tokens_list
)
490 struct psi_token
*tok
;
491 struct psi_plist
*tokens
= psi_plist_init(NULL
);
494 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
495 struct psi_plist
*arg_tokens
= NULL
;
497 if (tok
->type
== PSI_T_HASH
|| tok
->type
== PSI_T_CPP_PASTE
) {
499 } else if (tok
->type
== PSI_T_NAME
) {
501 struct psi_token
*arg_name
;
503 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
504 if (zend_string_equals(arg_name
->text
, tok
->text
)) {
506 bool processed
= psi_cpp_process(cpp
,
507 &arg_tokens_list
[s
], target
);
511 arg_tokens
= arg_tokens_list
[s
];
518 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
520 tokens
= psi_plist_add(tokens
, &tok
);
524 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
525 psi_plist_free(tokens
);
528 static inline bool psi_cpp_tokiter_expand_call(struct psi_cpp
*cpp
,
529 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
531 /* function-like macro
532 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
533 * # if FOO(1,2) // expands to if 1 > 2
535 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= psi_plist_count(macro
->sig
);
536 struct psi_plist
**arg_tokens_list
;
539 /* read in tokens, until we have balanced parens */
540 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
541 if (!arg_tokens_list
) {
542 psi_cpp_tokiter_seek(cpp
, start
);
546 /* insert and expand macro tokens */
547 psi_cpp_tokiter_expand_call_tokens(cpp
, target
, macro
, arg_tokens_list
);
548 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
550 psi_token_free(&target
);
555 static inline void psi_cpp_tokiter_expand_builtin_tokens(struct psi_cpp
*cpp
,
556 struct psi_token
*target
, struct psi_builtin
*builtin
,
557 struct psi_plist
**arg_tokens_list
)
560 struct psi_plist
*res
= NULL
;
561 size_t argc
= psi_plist_count(builtin
->decl
->sig
);
564 for (s
= 0; s
< argc
; ++s
) {
565 bool processed
= psi_cpp_process(cpp
, &arg_tokens_list
[s
],
570 /* insert and expand macro tokens */
571 if (!builtin
->func(cpp
, target
, arg_tokens_list
, &res
)) {
572 struct psi_token
*zero
= psi_token_init(PSI_T_NUMBER
, "0", 1,
573 target
->col
, target
->line
, target
->file
);
574 psi_cpp_tokiter_add(cpp
, zero
);
576 struct psi_token
*one
= psi_token_init(PSI_T_NUMBER
, "1", 1,
577 target
->col
, target
->line
, target
->file
);
578 psi_cpp_tokiter_add(cpp
, one
);
580 psi_cpp_tokiter_expand_tokens(cpp
, target
, res
);
585 static inline bool psi_cpp_tokiter_expand_builtin(struct psi_cpp
*cpp
,
586 struct psi_token
*target
, struct psi_builtin
*builtin
)
588 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= 0;
589 struct psi_plist
**arg_tokens_list
= NULL
;
591 if (builtin
->decl
->sig
) {
592 argc
= psi_plist_count(builtin
->decl
->sig
);
593 /* read in tokens, until we have balanced parens */
594 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
595 if (!arg_tokens_list
) {
596 psi_cpp_tokiter_seek(cpp
, start
);
600 psi_cpp_tokiter_del_cur(cpp
, false);
603 psi_cpp_tokiter_expand_builtin_tokens(cpp
, target
, builtin
, arg_tokens_list
);
604 if (arg_tokens_list
) {
605 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
608 psi_token_free(&target
);
614 static inline bool psi_cpp_tokiter_expand_def(struct psi_cpp
*cpp
,
615 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
618 struct psi_plist
*tokens
= psi_plist_copy(macro
->tokens
,
619 (void (*)(void *)) psi_token_copy_ctor
);
620 bool processed
= psi_cpp_process(cpp
, &tokens
, target
);
623 /* replace with tokens from macro */
624 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
626 psi_plist_free(tokens
);
630 psi_cpp_tokiter_del_cur(cpp
, true);
634 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token
*t
,
635 struct psi_cpp_macro_decl
*m
)
637 if (psi_plist_count(m
->tokens
) == 1) {
640 if (psi_plist_get(m
->tokens
, 0, &r
) && r
->text
) {
641 return !zend_string_equals(r
->text
, t
->text
);
647 static inline bool psi_cpp_tokiter_expand_decl(struct psi_cpp
*cpp
,
648 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
655 return psi_cpp_tokiter_expand_call(cpp
, target
, macro
);
656 } else if (psi_cpp_tokiter_expand_cmp(target
, macro
)) {
657 return psi_cpp_tokiter_expand_def(cpp
, target
, macro
);
663 bool psi_cpp_tokiter_expand(struct psi_cpp
*cpp
)
665 struct psi_token
*current
;
667 if (!psi_cpp_tokiter_valid(cpp
)) {
671 current
= psi_cpp_tokiter_current(cpp
);
676 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand < ");
677 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, current
);
680 if (psi_builtin_exists(current
->text
)) {
681 return psi_cpp_tokiter_expand_builtin(cpp
, current
,
682 psi_builtin_get(current
->text
));
684 return psi_cpp_tokiter_expand_decl(cpp
, current
,
685 zend_hash_find_ptr(&cpp
->defs
, current
->text
));