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
)
37 size_t i
= cpp
->index
;
45 while (psi_plist_get(cpp
->tokens
.iter
, i
, &T
)) {
46 PSI_DUMP(dump
, "PSI: CPP tokens %5zu %c ", i
, cpp
->index
== i
? '*' : ' ');
48 psi_token_dump(dump
, T
);
50 PSI_DUMP(dump
, "TOKEN deleted\n");
52 if (i
>= cpp
->index
+ 40) {
53 PSI_DUMP(dump
, "PSI: CPP tokens .....\n");
60 void psi_cpp_tokiter_reset(struct psi_cpp
*cpp
)
63 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP reset -> iter.count=%zu, next.count=%zu\n",
64 psi_plist_count(cpp
->tokens
.iter
),
65 psi_plist_count(cpp
->tokens
.next
));
66 # if PSI_CPP_DEBUG > 1
67 PSI_DEBUG_DUMP(cpp
->parser
, psi_cpp_tokiter_dump
, cpp
);
76 if (cpp
->tokens
.next
) {
77 free(cpp
->tokens
.iter
);
78 cpp
->tokens
.iter
= cpp
->tokens
.next
;
80 cpp
->tokens
.next
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
83 bool psi_cpp_tokiter_seek(struct psi_cpp
*cpp
, size_t index
)
85 if (index
< psi_plist_count(cpp
->tokens
.iter
)) {
92 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp
*cpp
)
94 struct psi_token
*current
= NULL
;
95 bool found
= psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, ¤t
);
102 size_t psi_cpp_tokiter_index(struct psi_cpp
*cpp
)
107 bool psi_cpp_tokiter_add_cur(struct psi_cpp
*cpp
)
109 struct psi_token
*cur
= NULL
;
111 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
112 struct psi_plist
*tokens
= psi_plist_add(cpp
->tokens
.next
, &cur
);
115 cpp
->tokens
.next
= tokens
;
118 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu ",
119 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
120 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
130 bool psi_cpp_tokiter_add(struct psi_cpp
*cpp
, struct psi_token
*tok
)
132 struct psi_plist
*tokens
= psi_plist_add(cpp
->tokens
.next
, &tok
);
137 cpp
->tokens
.next
= tokens
;
140 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu ",
141 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
142 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, tok
);
149 bool psi_cpp_tokiter_add_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
151 struct psi_plist
*tokens
;
157 tokens
= psi_plist_add_r(cpp
->tokens
.next
, num_eles
, eles
);
161 cpp
->tokens
.next
= tokens
;
164 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
165 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
172 void psi_cpp_tokiter_next(struct psi_cpp
*cpp
)
174 #if 0 && PSI_CPP_DEBUG
175 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP next -> index=%zu -> index=%zu\n",
176 cpp
->index
, cpp
->index
+1);
181 bool psi_cpp_tokiter_valid(struct psi_cpp
*cpp
)
183 #if 0 && PSI_CPP_DEBUG
184 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP valid -> index=%zu -> %d\n",
185 cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
.iter
));
187 return cpp
->index
< psi_plist_count(cpp
->tokens
.iter
);
190 bool psi_cpp_tokiter_del_prev(struct psi_cpp
*cpp
, bool free_token
)
192 struct psi_token
*cur
= NULL
;
195 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count=%zu\n",
196 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
199 if (psi_plist_pop(cpp
->tokens
.next
, NULL
) && psi_plist_get(cpp
->tokens
.iter
, cpp
->index
- 1, &cur
)) {
200 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
- 1);
201 if (free_token
&& cur
) {
202 psi_token_free(&cur
);
209 bool psi_cpp_tokiter_del_cur(struct psi_cpp
*cpp
, bool free_token
)
211 struct psi_token
*cur
= NULL
;
214 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu ",
215 cpp
->index
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
218 if (psi_plist_get(cpp
->tokens
.iter
, cpp
->index
, &cur
)) {
220 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, cur
);
222 psi_plist_unset(cpp
->tokens
.iter
, cpp
->index
);
223 if (free_token
&& cur
) {
224 psi_token_free(&cur
);
233 bool psi_cpp_tokiter_del_range(struct psi_cpp
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
235 struct psi_token
*ptr
;
239 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
240 cpp
->index
, offset
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
243 for (i
= offset
; i
< offset
+ num_eles
; ++i
) {
244 if (!psi_plist_get(cpp
->tokens
.iter
, i
, &ptr
)) {
248 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP del_range -> ");
249 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, ptr
);
251 psi_plist_unset(cpp
->tokens
.iter
, i
);
252 if (free_tokens
&& ptr
) {
253 psi_token_free(&ptr
);
261 bool psi_cpp_tokiter_ins_range(struct psi_cpp
*cpp
, size_t num_eles
, void **eles
)
263 struct psi_plist
*tokens
;
269 tokens
= psi_plist_ins_r(cpp
->tokens
.iter
, cpp
->index
, num_eles
, eles
);
273 cpp
->tokens
.iter
= tokens
;
276 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP ins_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu\n",
277 cpp
->index
, num_eles
, psi_plist_count(cpp
->tokens
.iter
), psi_plist_count(cpp
->tokens
.next
));
283 bool psi_cpp_tokiter_defined(struct psi_cpp
*cpp
)
285 if (psi_cpp_tokiter_valid(cpp
)) {
286 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
288 return psi_cpp_defined(cpp
, current
);
294 static inline size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp
*cpp
,
295 struct psi_token
*target
, struct psi_plist
*tokens
)
298 bool stringify
= false, paste
= false;
299 struct psi_token
*tok
;
300 struct psi_plist
*exp
;
302 if (!psi_plist_count(tokens
)) {
306 exp
= psi_plist_init(NULL
);
307 while (psi_plist_get(tokens
, i
++, &tok
)) {
308 struct psi_token
*new_tok
;
310 if (tok
->type
== PSI_T_EOL
) {
313 if (tok
->type
== PSI_T_HASH
) {
317 if (tok
->type
== PSI_T_CPP_PASTE
) {
322 if (paste
&& psi_plist_count(exp
)) {
323 struct psi_token
*old_tok
;
324 struct psi_parser_input
*toscan
;
326 psi_plist_pop(exp
, &old_tok
);
327 new_tok
= psi_token_cat(NULL
, 2, old_tok
, tok
);
329 /* reclassify token(s) */
330 if ((toscan
= psi_parser_open_string(cpp
->parser
, new_tok
->text
->val
, new_tok
->text
->len
))) {
331 struct psi_plist
*scanned
;
333 scanned
= psi_parser_scan(cpp
->parser
, toscan
);
334 if (psi_plist_count(scanned
)) {
336 struct psi_token
*tmp_tok
;
338 exp
= psi_plist_add_r(exp
, psi_plist_count(scanned
), psi_plist_eles(scanned
));
341 while (psi_plist_get(scanned
, i
++, &tmp_tok
)) {
342 zend_string_release(tmp_tok
->file
);
343 tmp_tok
->file
= zend_string_copy(new_tok
->file
);
344 tmp_tok
->line
= new_tok
->line
;
345 tmp_tok
->col
= new_tok
->col
;
348 psi_token_free(&new_tok
);
349 psi_plist_top(scanned
, &new_tok
);
351 exp
= psi_plist_add(exp
, &new_tok
);
356 psi_parser_input_free(&toscan
);
358 exp
= psi_plist_add(exp
, &new_tok
);
361 psi_token_free(&old_tok
);
363 new_tok
= psi_token_init(stringify
? PSI_T_QUOTED_STRING
: tok
->type
,
364 tok
->text
->val
, tok
->text
->len
, target
->col
, target
->line
,
365 target
->file
?: zend_empty_string
);
367 exp
= psi_plist_add(exp
, &new_tok
);
371 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand > ");
372 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, new_tok
);
379 n
= psi_plist_count(exp
);
380 psi_cpp_tokiter_ins_range(cpp
, n
, psi_plist_eles(exp
));
386 static inline void psi_cpp_tokiter_free_call_tokens(
387 struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
391 for (i
= 0; i
< arg_count
; ++i
) {
392 if (arg_tokens_list
[i
]) {
394 struct psi_token
*tok
;
396 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
397 psi_token_free(&tok
);
400 psi_plist_free(arg_tokens_list
[i
]);
403 free(arg_tokens_list
);
406 static inline struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
407 struct psi_cpp
*cpp
, size_t arg_count
)
409 size_t arg_index
= 0, lparens
= 1, rparens
= 0, start
= psi_cpp_tokiter_index(cpp
);
410 struct psi_plist
**arg_tokens
= pecalloc(arg_count
, sizeof(*arg_tokens
), 1);
411 struct psi_plist
*free_tokens
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
412 struct psi_token
*tok
;
414 arg_tokens
[0] = psi_plist_init(NULL
);
416 /* next token must be a LPAREN for a macro call */
417 psi_cpp_tokiter_next(cpp
);
418 tok
= psi_cpp_tokiter_current(cpp
);
419 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
423 /* free LPAREN on success */
424 free_tokens
= psi_plist_add(free_tokens
, &tok
);
426 while (lparens
> rparens
) {
427 psi_cpp_tokiter_next(cpp
);
428 if (!psi_cpp_tokiter_valid(cpp
)) {
431 tok
= psi_cpp_tokiter_current(cpp
);
436 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
439 if (++rparens
== lparens
) {
441 if (arg_index
+ 1 < arg_count
) {
444 free_tokens
= psi_plist_add(free_tokens
, &tok
);
446 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
450 if (1 == (lparens
- rparens
)) {
451 /* too many commas? */
452 if (++arg_index
>= arg_count
) {
455 free_tokens
= psi_plist_add(free_tokens
, &tok
);
457 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
459 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
463 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
467 /* ditch arg tokens */
468 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
469 psi_plist_free(free_tokens
);
474 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
478 static inline void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp
*cpp
,
479 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
,
480 struct psi_plist
**arg_tokens_list
)
483 struct psi_token
*tok
;
484 struct psi_plist
*tokens
= psi_plist_init(NULL
);
487 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
488 struct psi_plist
*arg_tokens
= NULL
;
490 if (tok
->type
== PSI_T_HASH
|| tok
->type
== PSI_T_CPP_PASTE
) {
492 } else if (tok
->type
== PSI_T_NAME
) {
494 struct psi_token
*arg_name
;
496 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
497 if (zend_string_equals(arg_name
->text
, tok
->text
)) {
499 bool processed
= psi_cpp_process(cpp
, &arg_tokens_list
[s
]);
503 arg_tokens
= arg_tokens_list
[s
];
510 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
512 tokens
= psi_plist_add(tokens
, &tok
);
516 psi_cpp_tokiter_expand_tokens(cpp
, target
, tokens
);
517 psi_plist_free(tokens
);
520 static inline bool psi_cpp_tokiter_expand_call(struct psi_cpp
*cpp
,
521 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
523 /* function-like macro
524 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
525 * # if FOO(1,2) // expands to if 1 > 2
527 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= psi_plist_count(macro
->sig
);
528 struct psi_plist
**arg_tokens_list
;
531 /* read in tokens, until we have balanced parens */
532 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
533 if (!arg_tokens_list
) {
534 psi_cpp_tokiter_seek(cpp
, start
);
538 /* insert and expand macro tokens */
539 psi_cpp_tokiter_expand_call_tokens(cpp
, target
, macro
, arg_tokens_list
);
540 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
542 psi_token_free(&target
);
547 static inline void psi_cpp_tokiter_expand_builtin_tokens(struct psi_cpp
*cpp
,
548 struct psi_token
*target
, struct psi_builtin
*builtin
,
549 struct psi_plist
**arg_tokens_list
)
552 struct psi_plist
*res
= NULL
;
553 size_t argc
= psi_plist_count(builtin
->decl
->sig
);
556 for (s
= 0; s
< argc
; ++s
) {
557 bool processed
= psi_cpp_process(cpp
, &arg_tokens_list
[s
]);
561 /* insert and expand macro tokens */
562 if (!builtin
->func(cpp
, target
, arg_tokens_list
, &res
)) {
563 struct psi_token
*zero
= psi_token_init(PSI_T_NUMBER
, "0", 1,
564 target
->col
, target
->line
, target
->file
);
565 psi_cpp_tokiter_ins_range(cpp
, 1, (void *) &zero
);
567 struct psi_token
*one
= psi_token_init(PSI_T_NUMBER
, "1", 1,
568 target
->col
, target
->line
, target
->file
);
569 psi_cpp_tokiter_ins_range(cpp
, 1, (void *) &one
);
571 psi_cpp_tokiter_expand_tokens(cpp
, target
, res
);
576 static inline bool psi_cpp_tokiter_expand_builtin(struct psi_cpp
*cpp
,
577 struct psi_token
*target
, struct psi_builtin
*builtin
)
579 size_t start
= psi_cpp_tokiter_index(cpp
), argc
= 0;
580 struct psi_plist
**arg_tokens_list
= NULL
;
582 if (builtin
->decl
->sig
) {
583 argc
= psi_plist_count(builtin
->decl
->sig
);
584 /* read in tokens, until we have balanced parens */
585 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, argc
);
586 if (!arg_tokens_list
) {
587 psi_cpp_tokiter_seek(cpp
, start
);
591 psi_cpp_tokiter_next(cpp
);
594 psi_cpp_tokiter_expand_builtin_tokens(cpp
, target
, builtin
, arg_tokens_list
);
595 if (arg_tokens_list
) {
596 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, argc
, true);
599 psi_token_free(&target
);
605 static inline bool psi_cpp_tokiter_expand_def(struct psi_cpp
*cpp
,
606 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
608 /* delete current token from stream */
609 psi_cpp_tokiter_del_cur(cpp
, false);
610 /* replace with tokens from macro */
611 psi_cpp_tokiter_expand_tokens(cpp
, target
, macro
->tokens
);
613 psi_token_free(&target
);
618 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token
*t
,
619 struct psi_cpp_macro_decl
*m
)
621 if (psi_plist_count(m
->tokens
) == 1) {
624 if (psi_plist_get(m
->tokens
, 0, &r
) && r
->text
) {
625 return !zend_string_equals(r
->text
, t
->text
);
631 static inline bool psi_cpp_tokiter_expand_decl(struct psi_cpp
*cpp
,
632 struct psi_token
*target
, struct psi_cpp_macro_decl
*macro
)
638 /* don't expand itself */
639 if (macro
->token
== target
) {
644 return psi_cpp_tokiter_expand_call(cpp
, target
, macro
);
645 } else if (psi_cpp_tokiter_expand_cmp(target
, macro
)) {
646 return psi_cpp_tokiter_expand_def(cpp
, target
, macro
);
652 bool psi_cpp_tokiter_expand(struct psi_cpp
*cpp
)
654 struct psi_token
*current
;
656 if (!psi_cpp_tokiter_valid(cpp
)) {
660 current
= psi_cpp_tokiter_current(cpp
);
665 PSI_DEBUG_PRINT(cpp
->parser
, "PSI: CPP expand < ");
666 PSI_DEBUG_DUMP(cpp
->parser
, psi_token_dump
, current
);
669 if (psi_builtin_exists(current
->text
)) {
670 return psi_cpp_tokiter_expand_builtin(cpp
, current
,
671 psi_builtin_get(current
->text
));
673 return psi_cpp_tokiter_expand_decl(cpp
, current
,
674 zend_hash_find_ptr(&cpp
->defs
, current
->text
));