7aa938e07da101dceb0d330bb62e2a16be4c4e35
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_data
*cpp
)
37 for (i
= 0; psi_plist_get(cpp
->tokens
, i
, &T
); ++i
) {
38 dprintf(fd
, "PSI: CPP tokens %5zu %c ", i
, cpp
->index
== i
? '*' : ' ');
39 psi_token_dump(fd
, T
);
43 void psi_cpp_tokiter_reset(struct psi_cpp_data
*cpp
)
46 fprintf(stderr
, "PSI: CPP reset (%zu tokens)\n", psi_plist_count(cpp
->tokens
));
47 psi_cpp_tokiter_dump(2, cpp
);
53 bool psi_cpp_tokiter_seek(struct psi_cpp_data
*cpp
, size_t index
)
55 if (index
< psi_plist_count(cpp
->tokens
)) {
62 struct psi_token
*psi_cpp_tokiter_current(struct psi_cpp_data
*cpp
)
64 struct psi_token
*current
= NULL
;
65 bool found
= psi_plist_get(cpp
->tokens
, cpp
->index
, ¤t
);
72 size_t psi_cpp_tokiter_index(struct psi_cpp_data
*cpp
)
77 void psi_cpp_tokiter_next(struct psi_cpp_data
*cpp
)
79 #if 0 && PSI_CPP_DEBUG
80 fprintf(stderr
, "PSI: CPP next -> index=%zu -> index=%zu\n", cpp
->index
, cpp
->index
+1);
85 void psi_cpp_tokiter_prev(struct psi_cpp_data
*cpp
)
87 #if 0 && PSI_CPP_DEBUG
88 fprintf(stderr
, "PSI: CPP prev -> index=%zu -> index=%zu\n", cpp
->index
, cpp
->index
-1);
95 bool psi_cpp_tokiter_valid(struct psi_cpp_data
*cpp
)
97 #if 0 && PSI_CPP_DEBUG
98 fprintf(stderr
, "PSI: CPP valid -> index=%zu -> %d\n", cpp
->index
, cpp
->index
< psi_plist_count(cpp
->tokens
));
100 return cpp
->index
< psi_plist_count(cpp
->tokens
);
103 bool psi_cpp_tokiter_del_cur(struct psi_cpp_data
*cpp
, bool free_token
)
105 struct psi_token
*cur
= NULL
;
106 bool deleted
= psi_plist_del(cpp
->tokens
, cpp
->index
, &cur
);
109 fprintf(stderr
, "PSI: CPP del_cur -> index=%zu, del=%d, free=%d ",
110 cpp
->index
, (int) deleted
, (int) free_token
);
112 psi_token_dump(2, cur
);
114 fprintf(stderr
, "NULL\n");
117 if (cur
&& free_token
) {
120 if (deleted
&& cpp
->index
>= psi_plist_count(cpp
->tokens
)) {
121 cpp
->index
= MAX(0, psi_plist_count(cpp
->tokens
)-1);
126 bool psi_cpp_tokiter_del_range(struct psi_cpp_data
*cpp
, size_t offset
, size_t num_eles
, bool free_tokens
)
128 struct psi_token
**ptr
;
132 ptr
= calloc(num_eles
, sizeof(*ptr
));
138 fprintf(stderr
, "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu\n", cpp
->index
, offset
, num_eles
);
141 deleted
= psi_plist_del_r(cpp
->tokens
, offset
, num_eles
, (void *) ptr
);
144 if (cpp
->index
>= psi_plist_count(cpp
->tokens
)) {
145 cpp
->index
= MAX(0, psi_plist_count(cpp
->tokens
)-1);
159 bool psi_cpp_tokiter_ins_cur(struct psi_cpp_data
*cpp
, struct psi_token
*tok
)
161 struct psi_plist
*tokens
= psi_plist_ins(cpp
->tokens
, cpp
->index
, &tok
);
164 fprintf(stderr
, "PSI: CPP ins_cur -> index=%zu ", cpp
->index
);
165 psi_token_dump(2, tok
);
171 cpp
->tokens
= tokens
;
175 bool psi_cpp_tokiter_ins_range(struct psi_cpp_data
*cpp
, size_t offset
,
176 size_t num_eles
, void **eles
)
178 struct psi_plist
*tokens
= psi_plist_ins_r(cpp
->tokens
, offset
,
182 fprintf(stderr
, "PSI: CPP ins_range -> index=%zu, offset=%zu, num_eles=%zu\n", cpp
->index
, offset
, num_eles
);
188 cpp
->tokens
= tokens
;
192 bool psi_cpp_tokiter_defined(struct psi_cpp_data
*cpp
)
194 if (psi_cpp_tokiter_valid(cpp
)) {
195 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
197 return psi_cpp_defined(cpp
, current
);
203 void psi_cpp_tokiter_expand_tokens(struct psi_cpp_data
*cpp
, struct psi_plist
*tokens
)
205 if (tokens
&& psi_plist_count(tokens
)) {
207 bool stringify
= false, paste
= false;
208 struct psi_token
*tok
, **exp_tokens
= calloc(psi_plist_count(tokens
), sizeof(*exp_tokens
));
210 while (psi_plist_get(tokens
, i
++, &tok
)) {
211 struct psi_token
*new_tok
;
213 if (tok
->type
== PSI_T_HASH
) {
223 if (paste
&& n
> 0 && exp_tokens
[n
- 1] &&
224 (new_tok
= psi_token_cat(NULL
, 2, exp_tokens
[n
- 1], tok
))) {
225 free(exp_tokens
[n
- 1]);
226 exp_tokens
[n
- 1] = new_tok
;
228 struct psi_token
*cpy
= psi_token_copy(tok
);
231 cpy
= psi_token_append(NULL
,
232 psi_token_prepend(NULL
, cpy
, 1, "\""), 1, "\"");
233 cpy
->type
= PSI_T_QUOTED_STRING
;
235 exp_tokens
[n
++] = cpy
;
239 fprintf(stderr
, "PSI: CPP expand > ");
240 psi_token_dump(2, tok
);
245 psi_cpp_tokiter_ins_range(cpp
, psi_cpp_tokiter_index(cpp
), n
, (void *) exp_tokens
);
250 static void psi_cpp_tokiter_free_call_tokens(struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
254 for (i
= 0; i
< arg_count
; ++i
) {
255 if (arg_tokens_list
[i
]) {
257 struct psi_token
*tok
;
259 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
263 psi_plist_free(arg_tokens_list
[i
]);
266 free(arg_tokens_list
);
269 static struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
270 struct psi_cpp_data
*cpp
, size_t arg_count
)
272 size_t arg_index
= 0, lparens
= 1, rparens
= 0;
273 struct psi_plist
**arg_tokens
= calloc(arg_count
, sizeof(*arg_tokens
));
274 struct psi_plist
*free_tokens
= psi_plist_init((void (*)(void *)) psi_token_free
);
275 struct psi_token
*tok
;
277 arg_tokens
[0] = psi_plist_init(NULL
);
279 /* free macro name token on success */
280 tok
= psi_cpp_tokiter_current(cpp
);
281 free_tokens
= psi_plist_add(free_tokens
, &tok
);
283 /* next token must be a LPAREN for a macro call */
284 psi_cpp_tokiter_next(cpp
);
285 tok
= psi_cpp_tokiter_current(cpp
);
286 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
290 /* free LPAREN on success */
291 free_tokens
= psi_plist_add(free_tokens
, &tok
);
293 while (lparens
> rparens
) {
294 psi_cpp_tokiter_next(cpp
);
295 if (!psi_cpp_tokiter_valid(cpp
)) {
298 tok
= psi_cpp_tokiter_current(cpp
);
303 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
306 if (++rparens
== lparens
) {
308 if (arg_index
+ 1 < arg_count
) {
311 free_tokens
= psi_plist_add(free_tokens
, &tok
);
313 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
317 if (1 == (lparens
- rparens
)) {
318 /* too many commas? */
319 if (++arg_index
>= arg_count
) {
322 free_tokens
= psi_plist_add(free_tokens
, &tok
);
324 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
326 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
330 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
334 psi_plist_free(free_tokens
);
338 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
342 static void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp_data
*cpp
,
343 struct psi_cpp_macro_decl
*macro
, struct psi_plist
**arg_tokens_list
)
346 struct psi_token
*tok
;
347 struct psi_plist
*tokens
= psi_plist_init(NULL
);
349 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
350 struct psi_plist
*arg_tokens
= NULL
;
352 if (tok
->type
== PSI_T_NAME
) {
354 struct psi_token
*arg_name
;
356 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
357 if (arg_name
->size
== tok
->size
) {
358 if (!memcmp(arg_name
->text
, tok
->text
, tok
->size
)) {
359 arg_tokens
= arg_tokens_list
[s
];
367 tokens
= psi_plist_add_r(tokens
, psi_plist_count(arg_tokens
), psi_plist_eles(arg_tokens
));
369 tokens
= psi_plist_add(tokens
, &tok
);
373 psi_cpp_tokiter_expand_tokens(cpp
, tokens
);
374 psi_plist_free(tokens
);
377 static bool psi_cpp_tokiter_expand_call(struct psi_cpp_data
*cpp
,
378 struct psi_cpp_macro_decl
*macro
)
380 /* function-like macro
381 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
382 * # if FOO(1,2) // expands to if 1 > 2
384 size_t start
= psi_cpp_tokiter_index(cpp
);
385 struct psi_plist
**arg_tokens_list
;
387 /* read in tokens, until we have balanced parens */
388 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, psi_plist_count(macro
->sig
));
389 if (!arg_tokens_list
) {
390 psi_cpp_tokiter_seek(cpp
, start
);
394 /* ditch arg tokens */
395 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
396 psi_cpp_tokiter_seek(cpp
, start
);
398 /* insert and expand macro tokens */
399 psi_cpp_tokiter_expand_call_tokens(cpp
, macro
, arg_tokens_list
);
400 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, psi_plist_count(macro
->sig
), true);
402 /* back to where we took off */
403 psi_cpp_tokiter_seek(cpp
, start
);
408 bool psi_cpp_tokiter_expand(struct psi_cpp_data
*cpp
)
410 if (psi_cpp_tokiter_valid(cpp
)) {
411 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
414 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(
415 &cpp
->defs
, current
->text
, current
->size
);
417 /* don't expand itself */
418 if (macro
&& macro
->token
!= current
) {
420 fprintf(stderr
, "PSI: CPP expand < ");
421 psi_token_dump(2, current
);
424 return psi_cpp_tokiter_expand_call(cpp
, macro
);
426 size_t index
= psi_cpp_tokiter_index(cpp
);
428 /* delete current token from stream */
429 psi_cpp_tokiter_del_cur(cpp
, true);
431 if (index
!= psi_cpp_tokiter_index(cpp
)) {
432 /* might have been last token */
433 psi_cpp_tokiter_next(cpp
);
435 /* replace with tokens from macro */
436 psi_cpp_tokiter_expand_tokens(cpp
, macro
->tokens
);