e1d45f3bef82ecb6e1031e7fcf8b2b175b13a351
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_range(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_range(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 struct psi_token
**exp_tokens
= calloc(psi_plist_count(tokens
), sizeof(*exp_tokens
));
209 for (i
= 0; psi_plist_get(tokens
, i
, &exp_tokens
[i
]); ++i
) {
210 exp_tokens
[i
] = psi_token_copy(exp_tokens
[i
]);
213 fprintf(stderr
, "PSI: CPP expand > ");
214 psi_token_dump(2, exp_tokens
[i
]);
217 psi_cpp_tokiter_ins_range(cpp
, psi_cpp_tokiter_index(cpp
), i
, (void *) exp_tokens
);
222 static void psi_cpp_tokiter_free_call_tokens(struct psi_plist
**arg_tokens_list
, size_t arg_count
, bool free_tokens
)
226 for (i
= 0; i
< arg_count
; ++i
) {
227 if (arg_tokens_list
[i
]) {
229 struct psi_token
*tok
;
231 while (psi_plist_pop(arg_tokens_list
[i
], &tok
)) {
235 psi_plist_free(arg_tokens_list
[i
]);
238 free(arg_tokens_list
);
241 static struct psi_plist
**psi_cpp_tokiter_read_call_tokens(
242 struct psi_cpp_data
*cpp
, size_t arg_count
)
244 size_t arg_index
= 0, lparens
= 1, rparens
= 0;
245 struct psi_plist
**arg_tokens
= calloc(arg_count
, sizeof(*arg_tokens
));
246 struct psi_plist
*free_tokens
= psi_plist_init((void (*)(void *)) psi_token_free
);
247 struct psi_token
*tok
;
249 arg_tokens
[0] = psi_plist_init(NULL
);
251 /* free macro name token on success */
252 tok
= psi_cpp_tokiter_current(cpp
);
253 free_tokens
= psi_plist_add(free_tokens
, &tok
);
255 /* next token must be a LPAREN for a macro call */
256 psi_cpp_tokiter_next(cpp
);
257 tok
= psi_cpp_tokiter_current(cpp
);
258 if (!psi_cpp_tokiter_valid(cpp
) || tok
->type
!= PSI_T_LPAREN
) {
262 /* free LPAREN on success */
263 free_tokens
= psi_plist_add(free_tokens
, &tok
);
265 while (lparens
> rparens
) {
266 psi_cpp_tokiter_next(cpp
);
267 if (!psi_cpp_tokiter_valid(cpp
)) {
270 tok
= psi_cpp_tokiter_current(cpp
);
275 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
278 if (++rparens
== lparens
) {
280 if (arg_index
+ 1 < arg_count
) {
283 free_tokens
= psi_plist_add(free_tokens
, &tok
);
285 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
289 if (1 == (lparens
- rparens
)) {
290 /* too many commas? */
291 if (++arg_index
>= arg_count
) {
294 free_tokens
= psi_plist_add(free_tokens
, &tok
);
296 arg_tokens
[arg_index
] = psi_plist_init(NULL
);
298 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
302 arg_tokens
[arg_index
] = psi_plist_add(arg_tokens
[arg_index
], &tok
);
306 psi_plist_free(free_tokens
);
310 psi_cpp_tokiter_free_call_tokens(arg_tokens
, arg_count
, false);
314 static void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp_data
*cpp
,
315 struct psi_cpp_macro_decl
*macro
, struct psi_plist
**arg_tokens_list
)
318 struct psi_token
*tok
;
320 for (i
= 0; psi_plist_get(macro
->tokens
, i
, &tok
); ++i
) {
321 struct psi_plist
*arg_tokens
= NULL
;
323 if (tok
->type
== PSI_T_NAME
) {
325 struct psi_token
*arg_name
;
327 for (s
= 0; psi_plist_get(macro
->sig
, s
, &arg_name
); ++s
) {
328 if (arg_name
->size
== tok
->size
) {
329 if (!memcmp(arg_name
->text
, tok
->text
, tok
->size
)) {
330 arg_tokens
= arg_tokens_list
[s
];
338 size_t tok_count
= psi_plist_count(arg_tokens
);
341 psi_cpp_tokiter_expand_tokens(cpp
, arg_tokens
);
342 psi_cpp_tokiter_seek(cpp
, psi_cpp_tokiter_index(cpp
) + tok_count
);
345 psi_cpp_tokiter_ins_cur(cpp
, psi_token_copy(tok
));
346 psi_cpp_tokiter_next(cpp
);
351 static bool psi_cpp_tokiter_expand_call(struct psi_cpp_data
*cpp
,
352 struct psi_cpp_macro_decl
*macro
)
354 /* function-like macro
355 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
356 * # if FOO(1,2) // expands to if 1 > 2
358 size_t start
= psi_cpp_tokiter_index(cpp
);
359 struct psi_plist
**arg_tokens_list
;
361 /* read in tokens, until we have balanced parens */
362 arg_tokens_list
= psi_cpp_tokiter_read_call_tokens(cpp
, psi_plist_count(macro
->sig
));
363 if (!arg_tokens_list
) {
364 psi_cpp_tokiter_seek(cpp
, start
);
368 /* ditch arg tokens */
369 psi_cpp_tokiter_del_range(cpp
, start
, psi_cpp_tokiter_index(cpp
) - start
+ 1, false);
370 psi_cpp_tokiter_seek(cpp
, start
);
372 /* insert and expand macro tokens */
373 psi_cpp_tokiter_expand_call_tokens(cpp
, macro
, arg_tokens_list
);
374 psi_cpp_tokiter_free_call_tokens(arg_tokens_list
, psi_plist_count(macro
->sig
), true);
376 /* back to where we took off */
377 psi_cpp_tokiter_seek(cpp
, start
);
382 bool psi_cpp_tokiter_expand(struct psi_cpp_data
*cpp
)
384 if (psi_cpp_tokiter_valid(cpp
)) {
385 struct psi_token
*current
= psi_cpp_tokiter_current(cpp
);
388 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(
389 &cpp
->defs
, current
->text
, current
->size
);
391 /* don't expand itself */
392 if (macro
&& macro
->token
!= current
) {
394 fprintf(stderr
, "PSI: CPP expand < ");
395 psi_token_dump(2, current
);
398 return psi_cpp_tokiter_expand_call(cpp
, macro
);
400 size_t index
= psi_cpp_tokiter_index(cpp
);
402 /* delete current token from stream */
403 psi_cpp_tokiter_del_cur(cpp
, true);
405 if (index
!= psi_cpp_tokiter_index(cpp
)) {
406 /* might have been last token */
407 psi_cpp_tokiter_next(cpp
);
409 /* replace with tokens from macro */
410 psi_cpp_tokiter_expand_tokens(cpp
, macro
->tokens
);