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
? '*' : ' ');
49 psi_token_dump(dump
, T
);
51 PSI_DUMP(dump
, "TOKEN deleted\n");
53 if (i
>= cpp
->index
+ 40) {
54 PSI_DUMP(dump
, "PSI: CPP tokens .....\n");
61 void psi_cpp_tokiter_reset(struct psi_cpp
*cpp
)
64 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP reset -> iter.count=%zu, next.count=%zu\n",
65 psi_plist_count(cpp
->tokens
.iter
),
66 psi_plist_count(cpp
->tokens
.next
));
67 # if PSI_CPP_DEBUG > 1
68 PSI_DEBUG_DUMP(cpp
->parser
, psi_cpp_tokiter_dump
, cpp
);
78 if (cpp
->tokens
.next
) {
79 free(cpp
->tokens
.iter
);
80 cpp
->tokens
.iter
= cpp
->tokens
.next
;
82 cpp
->tokens
.next
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
83 cpp
->tokens
.exec
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
86 bool psi_cpp_tokiter_seek(struct psi_cpp
*cpp
, size_t index
)
88 if (index
< psi_plist_count(cpp
->tokens
.iter
)) {
95 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp
*cpp
)
97 struct psi_token
*current
= NULL
;
98 bool found
= psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, ¤t
);
105 size_t psi_cpp_tokiter_index(struct psi_cpp
*cpp
)
110 bool psi_cpp_tokiter_add_cur(struct psi_cpp
*cpp
)
112 struct psi_token
*cur
= NULL
;
114 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
116 cpp
->tokens
.exec
= psi_plist_add(cpp
->tokens
.exec
, &cur
);
118 cpp
->tokens
.next
= psi_plist_add(cpp
->tokens
.next
, &cur
);
122 PSI_DEBUG_PRINT(cpp
->parser
,
123 "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
124 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
125 psi_plist_count(cpp
->tokens
.exec
));
126 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
135 bool psi_cpp_tokiter_add(struct psi_cpp
*cpp
, struct psi_token
*tok
)
138 cpp
->tokens
.exec
= psi_plist_add(cpp
->tokens
.exec
, &tok
);
140 cpp
->tokens
.next
= psi_plist_add(cpp
->tokens
.next
, &tok
);
144 PSI_DEBUG_PRINT(cpp
->parser
,
145 "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
146 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
147 psi_plist_count(cpp
->tokens
.exec
));
148 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, tok
);
155 bool psi_cpp_tokiter_add_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
157 struct psi_plist
*tokens
;
164 cpp
->tokens
.exec
= psi_plist_add_r(cpp
->tokens
.exec
, num_eles
, eles
);
166 cpp
->tokens
.next
= psi_plist_add_r(cpp
->tokens
.next
, num_eles
, eles
);
170 PSI_DEBUG_PRINT(cpp
->parser
,
171 "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
172 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
173 psi_plist_count(cpp
->tokens
.exec
));
180 void psi_cpp_tokiter_next(struct psi_cpp
*cpp
)
182 #if 0 && PSI_CPP_DEBUG
183 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP next -> index=%zu -> index=%zu\n",
184 cpp
->index
, cpp
->index
+1);
189 bool psi_cpp_tokiter_valid(struct psi_cpp
*cpp
)
191 #if 0 && PSI_CPP_DEBUG
192 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP valid -> index=%zu -> %d\n",
193 cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
.iter
));
195 return cpp
->index
< psi_plist_count(cpp
->tokens
.iter
);
198 bool psi_cpp_tokiter_del_prev(struct psi_cpp
*cpp
, bool free_token
)
200 struct psi_token
*cur
= NULL
;
203 PSI_DEBUG_PRINT(cpp
->parser
,
204 "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
205 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
206 psi_plist_count(cpp
->tokens
.exec
));
210 if (!psi_plist_pop(cpp
->tokens
.exec
, NULL
)) {
213 } else if (!psi_plist_pop(cpp
->tokens
.next
, NULL
)) {
217 if (!psi_plist_get(cpp
->tokens
.iter
, cpp
->index
- 1, &cur
)) {
220 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
- 1);
221 if (free_token
&& cur
) {
222 psi_token_free(&cur
);
227 bool psi_cpp_tokiter_del_cur(struct psi_cpp
*cpp
, bool free_token
)
229 struct psi_token
*cur
= NULL
;
232 PSI_DEBUG_PRINT(cpp
->parser
,
233 "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
234 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
235 psi_plist_count(cpp
->tokens
.exec
));
238 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
240 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
242 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
);
243 if (free_token
&& cur
) {
244 psi_token_free(&cur
);
253 bool psi_cpp_tokiter_del_range(struct psi_cpp
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
255 struct psi_token
*ptr
;
259 PSI_DEBUG_PRINT(cpp
->parser
,
260 "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
261 cpp
->index
, offset
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
262 psi_plist_count(cpp
->tokens
.exec
));
265 for (i
= offset
; i
< offset
+ num_eles
; ++i
) {
266 if (!psi_plist_get(cpp
->tokens
.iter
, i
, &ptr
)) {
270 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_range -> ");
271 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, ptr
);
273 psi_plist_unset(cpp
->tokens
.iter
, i
);
274 if (free_tokens
&& ptr
) {
275 psi_token_free(&ptr
);
283 bool psi_cpp_tokiter_ins_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
285 struct psi_plist
*tokens
;
291 cpp
->tokens
.iter
= psi_plist_ins_r(cpp
->tokens
.iter
, cpp
->index
, num_eles
, eles
);
294 PSI_DEBUG_PRINT(cpp
->parser
,
295 "PSI: CPP ins_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
296 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
),
297 psi_plist_count(cpp
->tokens
.exec
));
303 bool psi_cpp_tokiter_defined(struct psi_cpp
*cpp
)
305 if (psi_cpp_tokiter_valid(cpp
)) {
306 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
308 return psi_cpp_defined(cpp
, current
);
314 static inline size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp
*cpp
,
315 struct psi_token
*target
, struct psi_plist
*tokens
)
318 bool stringify
= false, paste
= false;
319 struct psi_token
*tok
;
320 struct psi_plist
*exp
;
322 if (!psi_plist_count(tokens
)) {
326 exp
= psi_plist_init(NULL
);
327 while (psi_plist_get(tokens
, i
++, &tok
)) {
328 struct psi_token
*new_tok
;
330 if (tok
->type
== PSI_T_EOL
) {
333 if (tok
->type
== PSI_T_HASH
) {
337 if (tok
->type
== PSI_T_CPP_PASTE
) {
342 if (paste
&& psi_plist_count(exp
)) {
343 struct psi_token
*old_tok
;
344 struct psi_parser_input
*toscan
;
346 psi_plist_pop(exp
, &old_tok
);
347 new_tok
= psi_token_cat(NULL
, 2, old_tok
, tok
);
349 /* reclassify token(s) */
350 if ((toscan
= psi_parser_open_string(cpp
->parser
, new_tok
->text
->val
, new_tok
->text
->len
))) {
351 struct psi_plist
*scanned
;
353 scanned
= psi_parser_scan(cpp
->parser
, toscan
);
354 if (psi_plist_count(scanned
)) {
356 struct psi_token
*tmp_tok
;
358 exp
= psi_plist_add_r(exp
, psi_plist_count(scanned
), psi_plist_eles(scanned
));
361 while (psi_plist_get(scanned
, i
++, &tmp_tok
)) {
362 zend_string_release(tmp_tok
->file
);
363 tmp_tok
->file
= zend_string_copy(new_tok
->file
);
364 tmp_tok
->line
= new_tok
->line
;
365 tmp_tok
->col
= new_tok
->col
;
368 psi_token_free(&new_tok
);
369 psi_plist_top(scanned
, &new_tok
);
371 exp
= psi_plist_add(exp
, &new_tok
);
376 psi_parser_input_free(&toscan
);
378 exp
= psi_plist_add(exp
, &new_tok
);
381 psi_token_free(&old_tok
);
383 new_tok
= psi_token_init(stringify
? PSI_T_QUOTED_STRING
: tok
->type
,
384 tok
->text
->val
, tok
->text
->len
, target
->col
, target
->line
,
385 target
->file
?: zend_empty_string
);
387 exp
= psi_plist_add(exp
, &new_tok
);
391 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand > ");
392 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, new_tok
);
399 bool processed
= psi_cpp_process(cpp
, &exp
, target
);
402 n
= psi_plist_count(exp
);
403 psi_cpp_tokiter_add_range(cpp
, n
, psi_plist_eles(exp
));
409 static inline void psi_cpp_tokiter_free_call_tokens(
410 struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
414 for (i
= 0; i
< arg_count
; ++i
) {
415 if (arg_tokens_list
[i
]) {
417 struct psi_token
*tok
;
419 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
420 psi_token_free(&tok
);
423 psi_plist_free(arg_tokens_list
[i
]);
426 free(arg_tokens_list
);
429 static inline struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
430 struct psi_cpp
*cpp
, size_t arg_count
)
432 size_t arg_index
= 0, lparens
= 1, rparens
= 0, start
= psi_cpp_tokiter_index(cpp
);
433 struct psi_plist
**arg_tokens
= pecalloc(arg_count
, sizeof(*arg_tokens
), 1);
434 struct psi_plist
*free_tokens
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
435 struct psi_token
*tok
;
437 arg_tokens
[0] = psi_plist_init(NULL
);
439 /* next token must be a LPAREN for a macro call */
440 psi_cpp_tokiter_next(cpp
);
441 tok
= psi_cpp_tokiter_current(cpp
);
442 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
446 /* free LPAREN on success */
447 free_tokens
= psi_plist_add(free_tokens
, &tok
);
449 while (lparens
> rparens
) {
450 psi_cpp_tokiter_next(cpp
);
451 if (!psi_cpp_tokiter_valid(cpp
)) {
454 tok
= psi_cpp_tokiter_current(cpp
);
459 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
462 if (++rparens
== lparens
) {
464 if (arg_index
+ 1 < arg_count
) {
467 free_tokens
= psi_plist_add(free_tokens
, &tok
);
469 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
473 if (1 == (lparens
- rparens
)) {
474 /* too many commas? */
475 if (++arg_index
>= arg_count
) {
478 free_tokens
= psi_plist_add(free_tokens
, &tok
);
480 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
482 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
486 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
490 /* ditch arg tokens */
491 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
492 psi_plist_free(free_tokens
);
497 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
501 static inline void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp
*cpp
,
502 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
,
503 struct psi_plist
**arg_tokens_list
)
506 struct psi_token
*tok
;
507 struct psi_plist
*tokens
= psi_plist_init(NULL
);
510 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
511 struct psi_plist
*arg_tokens
= NULL
;
513 if (tok
->type
== PSI_T_HASH
|| tok
->type
== PSI_T_CPP_PASTE
) {
515 } else if (tok
->type
== PSI_T_NAME
) {
517 struct psi_token
*arg_name
;
519 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
520 if (zend_string_equals(arg_name
->text
, tok
->text
)) {
522 bool processed
= psi_cpp_process(cpp
,
523 &arg_tokens_list
[s
], target
);
527 arg_tokens
= arg_tokens_list
[s
];
534 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
536 tokens
= psi_plist_add(tokens
, &tok
);
540 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
541 psi_plist_free(tokens
);
544 static inline bool psi_cpp_tokiter_expand_call(struct psi_cpp
*cpp
,
545 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
547 /* function-like macro
548 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
549 * # if FOO(1,2) // expands to if 1 > 2
551 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= psi_plist_count(macro
->sig
);
552 struct psi_plist
**arg_tokens_list
;
555 /* read in tokens, until we have balanced parens */
556 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
557 if (!arg_tokens_list
) {
558 psi_cpp_tokiter_seek(cpp
, start
);
562 /* insert and expand macro tokens */
563 psi_cpp_tokiter_expand_call_tokens(cpp
, target
, macro
, arg_tokens_list
);
564 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
566 psi_token_free(&target
);
571 static inline void psi_cpp_tokiter_expand_builtin_tokens(struct psi_cpp
*cpp
,
572 struct psi_token
*target
, struct psi_builtin
*builtin
,
573 struct psi_plist
**arg_tokens_list
)
576 struct psi_plist
*res
= NULL
;
577 size_t argc
= psi_plist_count(builtin
->decl
->sig
);
580 for (s
= 0; s
< argc
; ++s
) {
581 bool processed
= psi_cpp_process(cpp
, &arg_tokens_list
[s
],
586 /* insert and expand macro tokens */
587 if (!builtin
->func(cpp
, target
, arg_tokens_list
, &res
)) {
588 struct psi_token
*zero
= psi_token_init(PSI_T_NUMBER
, "0", 1,
589 target
->col
, target
->line
, target
->file
);
590 psi_cpp_tokiter_add(cpp
, zero
);
592 struct psi_token
*one
= psi_token_init(PSI_T_NUMBER
, "1", 1,
593 target
->col
, target
->line
, target
->file
);
594 psi_cpp_tokiter_add(cpp
, one
);
596 psi_cpp_tokiter_expand_tokens(cpp
, target
, res
);
601 static inline bool psi_cpp_tokiter_expand_builtin(struct psi_cpp
*cpp
,
602 struct psi_token
*target
, struct psi_builtin
*builtin
)
604 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= 0;
605 struct psi_plist
**arg_tokens_list
= NULL
;
607 if (builtin
->decl
->sig
) {
608 argc
= psi_plist_count(builtin
->decl
->sig
);
609 /* read in tokens, until we have balanced parens */
610 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
611 if (!arg_tokens_list
) {
612 psi_cpp_tokiter_seek(cpp
, start
);
616 psi_cpp_tokiter_next(cpp
);
619 psi_cpp_tokiter_expand_builtin_tokens(cpp
, target
, builtin
, arg_tokens_list
);
620 if (arg_tokens_list
) {
621 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
624 psi_token_free(&target
);
630 static inline bool psi_cpp_tokiter_expand_def(struct psi_cpp
*cpp
,
631 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
633 /* delete current token from stream */
634 psi_cpp_tokiter_del_cur(cpp
, false);
637 struct psi_plist
*tokens
= psi_plist_copy(macro
->tokens
,
638 (void (*)(void *)) psi_token_copy_ctor
);
639 bool processed
= psi_cpp_process(cpp
, &tokens
, target
);
642 /* replace with tokens from macro */
643 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
648 psi_token_free(&target
);
652 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token
*t
,
653 struct psi_cpp_macro_decl
*m
)
655 if (psi_plist_count(m
->tokens
) == 1) {
658 if (psi_plist_get(m
->tokens
, 0, &r
) && r
->text
) {
659 return !zend_string_equals(r
->text
, t
->text
);
665 static inline bool psi_cpp_tokiter_expand_decl(struct psi_cpp
*cpp
,
666 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
672 /* don't expand itself */
673 // if (zend_string_equals(macro->token->text, target->text)) {
674 // PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand ~ skipping self token\n");
679 return psi_cpp_tokiter_expand_call(cpp
, target
, macro
);
680 } else if (psi_cpp_tokiter_expand_cmp(target
, macro
)) {
681 return psi_cpp_tokiter_expand_def(cpp
, target
, macro
);
687 bool psi_cpp_tokiter_expand(struct psi_cpp
*cpp
)
689 struct psi_token
*current
;
691 if (!psi_cpp_tokiter_valid(cpp
)) {
695 current
= psi_cpp_tokiter_current(cpp
);
700 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand < ");
701 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, current
);
704 if (psi_builtin_exists(current
->text
)) {
705 return psi_cpp_tokiter_expand_builtin(cpp
, current
,
706 psi_builtin_get(current
->text
));
708 return psi_cpp_tokiter_expand_decl(cpp
, current
,
709 zend_hash_find_ptr(&cpp
->defs
, current
->text
));