cpp: avoid errenous multiple expansions
[m6w6/ext-psi] / src / types / number.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
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.
13
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 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27
28 #include <assert.h>
29
30 #include "data.h"
31 #include "calc.h"
32 #include "call.h"
33 #include "parser.h"
34
35 struct psi_number *psi_number_init(token_t t, void *num, unsigned flags)
36 {
37 struct psi_number *exp = calloc(1, sizeof(*exp));
38
39 exp->flags = flags;
40 switch (exp->type = t) {
41 case PSI_T_INT8:
42 exp->data.ival.i8 = *(int8_t *) num;
43 break;
44 case PSI_T_UINT8:
45 exp->data.ival.u8 = *(uint8_t *) num;
46 break;
47 case PSI_T_INT16:
48 exp->data.ival.i16 = *(int16_t *) num;
49 break;
50 case PSI_T_UINT16:
51 exp->data.ival.u16 = *(uint16_t *) num;
52 break;
53 case PSI_T_INT32:
54 exp->data.ival.i32 = *(int32_t *) num;
55 break;
56 case PSI_T_UINT32:
57 exp->data.ival.u32 = *(uint32_t *) num;
58 break;
59 case PSI_T_INT64:
60 exp->data.ival.i64 = *(int64_t *) num;
61 break;
62 case PSI_T_UINT64:
63 exp->data.ival.u64 = *(uint64_t *) num;
64 break;
65 case PSI_T_FLOAT:
66 exp->data.ival.dval = *(float *) num;
67 exp->type = PSI_T_DOUBLE;
68 break;
69 case PSI_T_DOUBLE:
70 exp->data.ival.dval = *(double *) num;
71 break;
72 #if HAVE_LONG_DOUBLE
73 case PSI_T_LONG_DOUBLE:
74 exp->data.ival.ldval = *(long double *) num;
75 break;
76 #endif
77 case PSI_T_QUOTED_CHAR:
78 case PSI_T_NUMBER:
79 case PSI_T_NSNAME:
80 case PSI_T_DEFINE:
81 exp->data.numb = strdup(num);
82 break;
83 case PSI_T_NAME:
84 exp->data.dvar = num;
85 break;
86 case PSI_T_FUNCTION:
87 exp->data.call = num;
88 break;
89 default:
90 assert(0);
91 }
92
93 return exp;
94 }
95
96 struct psi_number *psi_number_copy(struct psi_number *exp)
97 {
98 struct psi_number *num = calloc(1, sizeof(*num));
99
100 *num = *exp;
101
102 if (num->token) {
103 num->token = psi_token_copy(num->token);
104 }
105 switch (num->type) {
106 case PSI_T_INT8:
107 case PSI_T_UINT8:
108 case PSI_T_INT16:
109 case PSI_T_UINT16:
110 case PSI_T_INT32:
111 case PSI_T_UINT32:
112 case PSI_T_INT64:
113 case PSI_T_UINT64:
114 case PSI_T_DOUBLE:
115 #if HAVE_LONG_DOUBLE
116 case PSI_T_LONG_DOUBLE:
117 #endif
118 case PSI_T_ENUM:
119 case PSI_T_CONST:
120 break;
121 case PSI_T_NUMBER:
122 case PSI_T_NSNAME:
123 case PSI_T_DEFINE:
124 case PSI_T_QUOTED_CHAR:
125 num->data.numb = strdup(num->data.numb);
126 break;
127 case PSI_T_NAME:
128 num->data.dvar = psi_decl_var_copy(num->data.dvar);
129 break;
130 case PSI_T_FUNCTION:
131 num->data.call = psi_cpp_macro_call_copy(num->data.call);
132 break;
133 default:
134 assert(0);
135 }
136 return num;
137 }
138
139 void psi_number_free(struct psi_number **exp_ptr)
140 {
141 if (*exp_ptr) {
142 struct psi_number *exp = *exp_ptr;
143
144 *exp_ptr = NULL;
145 if (exp->token) {
146 free(exp->token);
147 }
148 switch (exp->type) {
149 case PSI_T_INT8:
150 case PSI_T_UINT8:
151 case PSI_T_INT16:
152 case PSI_T_UINT16:
153 case PSI_T_INT32:
154 case PSI_T_UINT32:
155 case PSI_T_INT64:
156 case PSI_T_UINT64:
157 case PSI_T_DOUBLE:
158 #if HAVE_LONG_DOUBLE
159 case PSI_T_LONG_DOUBLE:
160 #endif
161 case PSI_T_ENUM:
162 case PSI_T_CONST:
163 break;
164 case PSI_T_FUNCTION:
165 psi_cpp_macro_call_free(&exp->data.call);
166 break;
167 case PSI_T_NSNAME:
168 case PSI_T_NUMBER:
169 case PSI_T_DEFINE:
170 case PSI_T_QUOTED_CHAR:
171 free(exp->data.numb);
172 break;
173 case PSI_T_NAME:
174 psi_decl_var_free(&exp->data.dvar);
175 break;
176 default:
177 assert(0);
178 }
179 free(exp);
180 }
181 }
182
183 void psi_number_dump(int fd, struct psi_number *exp)
184 {
185 switch (exp->type) {
186 case PSI_T_INT8:
187 dprintf(fd, "%" PRId8, exp->data.ival.i8);
188 break;
189 case PSI_T_UINT8:
190 dprintf(fd, "%" PRIu8, exp->data.ival.u8);
191 break;
192 case PSI_T_INT16:
193 dprintf(fd, "%" PRId16, exp->data.ival.i16);
194 break;
195 case PSI_T_UINT16:
196 dprintf(fd, "%" PRIu16, exp->data.ival.u16);
197 break;
198 case PSI_T_INT32:
199 dprintf(fd, "%" PRId32, exp->data.ival.i32);
200 break;
201 case PSI_T_UINT32:
202 dprintf(fd, "%" PRIu32, exp->data.ival.u32);
203 break;
204 case PSI_T_INT64:
205 dprintf(fd, "%" PRId64, exp->data.ival.i64);
206 break;
207 case PSI_T_UINT64:
208 dprintf(fd, "%" PRIu64, exp->data.ival.u64);
209 break;
210 case PSI_T_FLOAT:
211 dprintf(fd, "%" PRIfval, exp->data.ival.dval);
212 break;
213 case PSI_T_DOUBLE:
214 dprintf(fd, "%" PRIdval, exp->data.ival.dval);
215 break;
216 #if HAVE_LONG_DOUBLE
217 case PSI_T_LONG_DOUBLE:
218 dprintf(fd, "%" PRIldval, exp->data.ival.ldval);
219 break;
220 #endif
221 case PSI_T_NUMBER:
222 case PSI_T_NSNAME:
223 case PSI_T_DEFINE:
224 case PSI_T_QUOTED_CHAR:
225 dprintf(fd, "%s", exp->data.numb);
226 break;
227 case PSI_T_FUNCTION:
228 psi_cpp_macro_call_dump(fd, exp->data.call);
229 break;
230 case PSI_T_CONST:
231 dprintf(fd, "%s", exp->data.cnst->name);
232 break;
233 case PSI_T_ENUM:
234 dprintf(fd, "%s", exp->data.enm->name);
235 break;
236 case PSI_T_NAME:
237 psi_decl_var_dump(fd, exp->data.dvar);
238 break;
239 default:
240 assert(0);
241 }
242 }
243
244 static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
245 struct psi_decl_enum *enm)
246 {
247 size_t i = 0;
248 struct psi_decl_enum_item *itm;
249
250 while (psi_plist_get(enm->items, i++, &itm)) {
251 if (!strcmp(itm->name, exp->data.dvar->name)) {
252 psi_decl_var_free(&exp->data.dvar);
253 exp->type = PSI_T_ENUM;
254 exp->data.enm = itm;
255 return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
256 }
257 }
258
259 return false;
260 }
261
262 static inline token_t validate_char(char *numb, impl_val *res, unsigned *lvl)
263 {
264 char *endptr;
265 token_t typ = PSI_T_INT8;
266
267 res->i8 = numb[0];
268 endptr = &numb[1];
269
270 switch(res->i8) {
271 case '\\':
272 res->i8 = numb[1];
273 endptr = &numb[2];
274
275 switch(res->i8) {
276 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
277 res->i8 = strtol(&numb[1], &endptr, 8);
278 break;
279
280 case 'x':
281 res->i8 = strtol(&numb[2], &endptr, 16);
282 break;
283
284 case 'a':
285 res->i8 = '\a';
286 break;
287 case 'b':
288 res->i8 = '\b';
289 break;
290 case 'f':
291 res->i8 = '\f';
292 break;
293 case 'n':
294 res->i8 = '\n';
295 break;
296 case 'r':
297 res->i8 = '\r';
298 break;
299 case 't':
300 res->i8 = '\t';
301 break;
302 case 'v':
303 res->i8 = '\v';
304 break;
305 default:
306 break;
307 }
308 break;
309 default:
310 break;
311 }
312
313 /* more to grok? */
314 if (*endptr) {
315 impl_val tmp_val = {0};
316 token_t tmp_typ = validate_char(endptr, &tmp_val, lvl);
317
318 if (!tmp_typ) {
319 return 0;
320 }
321
322 res->i32 = res->i8 << (8 * *lvl);
323 typ = psi_calc_add(PSI_T_INT32, res, tmp_typ, &tmp_val, res);
324 }
325
326 ++(*lvl);
327
328 return typ;
329 }
330 static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
331 {
332 impl_val val = {0};
333 unsigned lvl = 1;
334 token_t typ = validate_char(exp->data.numb, &val, &lvl);
335
336 if (!typ) {
337 return false;
338 }
339
340 free(exp->data.numb);
341 exp->type = typ;
342 exp->data.ival = val;
343 return true;
344 }
345
346 static inline bool psi_number_validate_number(struct psi_data *data, struct psi_number *exp)
347 {
348 impl_val tmp = {0};
349
350 if (exp->flags) {
351 switch (exp->flags & 0x0f) {
352 case PSI_NUMBER_INT:
353 switch (exp->flags & 0x0f00) {
354 case PSI_NUMBER_L:
355 default:
356 tmp.i64 = strtol(exp->data.numb, NULL, 0);
357 free(exp->data.numb);
358 exp->type = PSI_T_INT64;
359 exp->data.ival.i64 = tmp.i64;
360 break;
361 case PSI_NUMBER_LL:
362 tmp.i64 = strtoll(exp->data.numb, NULL, 0);
363 free(exp->data.numb);
364 exp->type = PSI_T_INT64;
365 exp->data.ival.i64 = tmp.i64;
366 break;
367 case PSI_NUMBER_U:
368 case PSI_NUMBER_UL:
369 tmp.u64 = strtoul(exp->data.numb, NULL, 0);
370 free(exp->data.numb);
371 exp->type = PSI_T_UINT64;
372 exp->data.ival.u64 = tmp.u64;
373 break;
374 case PSI_NUMBER_ULL:
375 tmp.u64 = strtoull(exp->data.numb, NULL, 0);
376 free(exp->data.numb);
377 exp->type = PSI_T_UINT64;
378 exp->data.ival.u64 = tmp.u64;
379 break;
380 }
381 return true;
382
383 case PSI_NUMBER_FLT:
384 switch (exp->flags & 0x0ff00) {
385 case PSI_NUMBER_F:
386 case PSI_NUMBER_DF:
387 tmp.fval = strtof(exp->data.numb, NULL);
388 free(exp->data.numb);
389 exp->type = PSI_T_FLOAT;
390 exp->data.ival.fval = tmp.fval;
391 break;
392 case PSI_NUMBER_L:
393 case PSI_NUMBER_DL:
394 #if HAVE_LONG_DOUBLE
395 tmp.ldval = strtold(exp->data.numb, NULL);
396 free(exp->data.numb);
397 exp->type = PSI_T_LONG_DOUBLE;
398 exp->data.ival.ldval = tmp.ldval;
399 break;
400 #endif
401 case PSI_NUMBER_DD:
402 default:
403 tmp.dval = strtod(exp->data.numb, NULL);
404 free(exp->data.numb);
405 exp->type = PSI_T_DOUBLE;
406 exp->data.ival.dval = tmp.dval;
407 break;
408 }
409 return true;
410 default:
411 assert(0);
412 break;
413 }
414 } else {
415 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 1)) {
416 case IS_LONG:
417 free(exp->data.numb);
418 exp->type = PSI_T_INT64;
419 exp->data.ival.i64 = tmp.zend.lval;
420 return true;
421
422 case IS_DOUBLE:
423 free(exp->data.numb);
424 exp->type = PSI_T_DOUBLE;
425 exp->data.ival.dval = tmp.dval;
426 return true;
427 }
428 }
429 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
430 return false;
431
432 }
433 bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
434 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
435 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
436 {
437 size_t i = 0;
438 struct psi_const *cnst;
439 struct psi_decl_enum *enm;
440
441 switch (exp->type) {
442 case PSI_T_CONST:
443 case PSI_T_INT8:
444 case PSI_T_UINT8:
445 case PSI_T_INT16:
446 case PSI_T_UINT16:
447 case PSI_T_INT32:
448 case PSI_T_UINT32:
449 case PSI_T_INT64:
450 case PSI_T_UINT64:
451 case PSI_T_DOUBLE:
452 #if HAVE_LONG_DOUBLE
453 case PSI_T_LONG_DOUBLE:
454 #endif
455 case PSI_T_ENUM:
456 case PSI_T_DEFINE:
457 case PSI_T_FUNCTION:
458 return true;
459
460 case PSI_T_NAME:
461 if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
462 return true;
463 }
464 while (psi_plist_get(data->enums, i++, &enm)) {
465 if (psi_number_validate_enum(data, exp, enm)) {
466 return true;
467 }
468 }
469 if (exp->data.dvar->arg) {
470 return true;
471 }
472 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
473 current_let, current_set)) {
474 return true;
475 }
476 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
477 return true;
478 }
479 data->error(data, exp->token, PSI_WARNING,
480 "Unknown variable '%s' in numeric expression",
481 exp->data.dvar->name);
482 return false;
483
484 case PSI_T_NSNAME:
485 while (psi_plist_get(data->consts, i++, &cnst)) {
486 if (!strcmp(cnst->name, exp->data.numb)) {
487 free(exp->data.numb);
488 exp->type = PSI_T_CONST;
489 exp->data.cnst = cnst;
490 return true;
491 }
492 }
493 data->error(data, exp->token, PSI_WARNING,
494 "Unknown constant '%s' in numeric expression",
495 exp->data.numb);
496 return false;
497
498 case PSI_T_NUMBER:
499 return psi_number_validate_number(data, exp);
500
501 case PSI_T_QUOTED_CHAR:
502 return psi_number_validate_char(data, exp);
503
504 default:
505 assert(0);
506 }
507
508 return false;
509 }
510
511 #include "Zend/zend_constants.h"
512
513 static inline token_t psi_number_eval_constant(struct psi_number *exp,
514 impl_val *res, struct psi_call_frame *frame)
515 {
516 switch (exp->data.cnst->type->type) {
517 case PSI_T_INT:
518 res->i64 = zend_get_constant_str(exp->data.cnst->name,
519 strlen(exp->data.cnst->name))->value.lval;
520 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
521 return PSI_T_INT64;
522 case PSI_T_FLOAT:
523 res->dval = zend_get_constant_str(exp->data.cnst->name,
524 strlen(exp->data.cnst->name))->value.dval;
525 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
526 return PSI_T_DOUBLE;
527 default:
528 if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
529 return 0;
530 }
531 }
532
533
534 static inline token_t psi_number_eval_decl_var(struct psi_number *exp,
535 impl_val *res, struct psi_call_frame *frame)
536 {
537 impl_val *ref;
538 struct psi_call_frame_symbol *sym;
539 struct psi_decl_type *real;
540 size_t size;
541
542 real = psi_decl_type_get_real(exp->data.dvar->arg->type);
543 size = psi_decl_arg_get_size(exp->data.dvar->arg);
544 sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
545 ref = deref_impl_val(sym->ptr, exp->data.dvar);
546
547 memcpy(res, ref, size);
548
549 return real->type;
550 }
551
552 static inline token_t psi_number_eval_define(struct psi_number *exp,
553 impl_val *res, HashTable *defs)
554 {
555 struct psi_cpp_macro_decl *macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
556
557 assert(!macro);
558
559 res->u8 = 0;
560 return PSI_T_UINT8;
561 }
562
563 token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame, HashTable *defs)
564 {
565 switch (exp->type) {
566 case PSI_T_INT8:
567 *res = exp->data.ival;
568 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
569 return PSI_T_INT8;
570 case PSI_T_UINT8:
571 *res = exp->data.ival;
572 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu8, res->u8);
573 return PSI_T_UINT8;
574 case PSI_T_INT16:
575 *res = exp->data.ival;
576 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
577 return PSI_T_INT16;
578 case PSI_T_UINT16:
579 *res = exp->data.ival;
580 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu16, res->u16);
581 return PSI_T_UINT16;
582 case PSI_T_INT32:
583 *res = exp->data.ival;
584 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
585 return PSI_T_INT32;
586 case PSI_T_UINT32:
587 *res = exp->data.ival;
588 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu32, res->u32);
589 return PSI_T_UINT32;
590 case PSI_T_INT64:
591 *res = exp->data.ival;
592 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
593 return PSI_T_INT64;
594 case PSI_T_UINT64:
595 *res = exp->data.ival;
596 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu64, res->u64);
597 return PSI_T_UINT64;
598
599 case PSI_T_DOUBLE:
600 *res = exp->data.ival;
601 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
602 return exp->type;
603
604 #if HAVE_LONG_DOUBLE
605 case PSI_T_LONG_DOUBLE:
606 *res = exp->data.ival;
607 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIldval, res->ldval);
608 return exp->type;
609 #endif
610
611 case PSI_T_ENUM:
612 res->i64 = exp->data.enm->val;
613 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
614 return PSI_T_INT64;
615
616 case PSI_T_CONST:
617 return psi_number_eval_constant(exp, res, frame);
618
619 case PSI_T_NAME:
620 return psi_number_eval_decl_var(exp, res, frame);
621
622 case PSI_T_DEFINE:
623 return psi_number_eval_define(exp, res, defs);
624
625 case PSI_T_FUNCTION:
626 res->u8 = 0;
627 return PSI_T_UINT8;
628
629 default:
630 assert(0);
631 }
632 return 0;
633 }