1 /*******************************************************************************
2 Copyright (c) 2016, 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"
35 struct psi_number
*psi_number_init(token_t t
, void *num
, unsigned flags
)
37 struct psi_number
*exp
= calloc(1, sizeof(*exp
));
40 switch (exp
->type
= t
) {
42 exp
->data
.ival
.i8
= *(int8_t *) num
;
45 exp
->data
.ival
.u8
= *(uint8_t *) num
;
48 exp
->data
.ival
.i16
= *(int16_t *) num
;
51 exp
->data
.ival
.u16
= *(uint16_t *) num
;
54 exp
->data
.ival
.i32
= *(int32_t *) num
;
57 exp
->data
.ival
.u32
= *(uint32_t *) num
;
60 exp
->data
.ival
.i64
= *(int64_t *) num
;
63 exp
->data
.ival
.u64
= *(uint64_t *) num
;
66 exp
->data
.ival
.dval
= *(float *) num
;
67 exp
->type
= PSI_T_DOUBLE
;
70 exp
->data
.ival
.dval
= *(double *) num
;
73 case PSI_T_LONG_DOUBLE
:
74 exp
->data
.ival
.ldval
= *(long double *) num
;
79 case PSI_T_QUOTED_CHAR
:
83 exp
->data
.numb
= strdup(num
);
101 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
103 struct psi_number
*num
= calloc(1, sizeof(*num
));
108 num
->token
= psi_token_copy(num
->token
);
121 case PSI_T_LONG_DOUBLE
:
130 case PSI_T_QUOTED_CHAR
:
131 num
->data
.numb
= strdup(num
->data
.numb
);
134 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
137 num
->data
.call
= psi_cpp_macro_call_copy(num
->data
.call
);
140 num
->data
.dtyp
= psi_decl_type_copy(num
->data
.dtyp
);
148 void psi_number_free(struct psi_number
**exp_ptr
)
151 struct psi_number
*exp
= *exp_ptr
;
168 case PSI_T_LONG_DOUBLE
:
175 psi_cpp_macro_call_free(&exp
->data
.call
);
180 case PSI_T_QUOTED_CHAR
:
181 free(exp
->data
.numb
);
184 psi_decl_var_free(&exp
->data
.dvar
);
187 psi_decl_type_free(&exp
->data
.dtyp
);
196 void psi_number_dump(int fd
, struct psi_number
*exp
)
200 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
203 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
206 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
209 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
212 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
215 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
218 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
221 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
224 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
227 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
230 case PSI_T_LONG_DOUBLE
:
231 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
240 case PSI_T_QUOTED_CHAR
:
241 dprintf(fd
, "%s", exp
->data
.numb
);
244 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
247 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
250 dprintf(fd
, "%s", exp
->data
.enm
->name
);
253 psi_decl_var_dump(fd
, exp
->data
.dvar
);
256 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
263 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
264 struct psi_decl_enum
*enm
)
267 struct psi_decl_enum_item
*itm
;
269 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
270 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
271 psi_decl_var_free(&exp
->data
.dvar
);
272 exp
->type
= PSI_T_ENUM
;
274 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
281 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
284 token_t typ
= PSI_T_INT8
;
295 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
296 res
->i8
= strtol(&numb
[1], &endptr
, 8);
300 res
->i8
= strtol(&numb
[2], &endptr
, 16);
334 impl_val tmp_val
= {0};
335 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
341 res
->i32
= res
->i8
<< (8 * *lvl
);
342 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
349 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
353 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
359 free(exp
->data
.numb
);
361 exp
->data
.ival
= val
;
365 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
370 switch (exp
->flags
& 0x0f) {
372 switch (exp
->flags
& 0x0f00) {
375 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
376 free(exp
->data
.numb
);
377 exp
->type
= PSI_T_INT64
;
378 exp
->data
.ival
.i64
= tmp
.i64
;
381 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
382 free(exp
->data
.numb
);
383 exp
->type
= PSI_T_INT64
;
384 exp
->data
.ival
.i64
= tmp
.i64
;
388 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
389 free(exp
->data
.numb
);
390 exp
->type
= PSI_T_UINT64
;
391 exp
->data
.ival
.u64
= tmp
.u64
;
394 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
395 free(exp
->data
.numb
);
396 exp
->type
= PSI_T_UINT64
;
397 exp
->data
.ival
.u64
= tmp
.u64
;
403 switch (exp
->flags
& 0x0ff00) {
406 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
407 free(exp
->data
.numb
);
408 exp
->type
= PSI_T_FLOAT
;
409 exp
->data
.ival
.fval
= tmp
.fval
;
414 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
415 free(exp
->data
.numb
);
416 exp
->type
= PSI_T_LONG_DOUBLE
;
417 exp
->data
.ival
.ldval
= tmp
.ldval
;
422 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
423 free(exp
->data
.numb
);
424 exp
->type
= PSI_T_DOUBLE
;
425 exp
->data
.ival
.dval
= tmp
.dval
;
434 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
436 free(exp
->data
.numb
);
437 exp
->type
= PSI_T_INT64
;
438 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
442 free(exp
->data
.numb
);
443 exp
->type
= PSI_T_DOUBLE
;
444 exp
->data
.ival
.dval
= tmp
.dval
;
448 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
452 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
453 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
454 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
457 struct psi_const
*cnst
;
458 struct psi_decl_enum
*enm
;
462 exp
->type
= PSI_T_UINT8
;
475 case PSI_T_LONG_DOUBLE
:
483 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
486 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
487 if (psi_number_validate_enum(data
, exp
, enm
)) {
491 if (exp
->data
.dvar
->arg
) {
494 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
,
495 impl
? impl
->decl
: NULL
, current_let
, current_set
)) {
498 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
,
499 NULL
, cb_decl
, NULL
, NULL
)) {
502 data
->error(data
, exp
->token
, PSI_WARNING
,
503 "Unknown variable '%s' in numeric expression",
504 exp
->data
.dvar
->name
);
508 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, 0, NULL
)) {
509 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
511 exp
->type
= PSI_T_UINT64
;
512 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
515 data
->error(data
, exp
->token
, PSI_WARNING
,
516 "Cannot compute sizeof(%s) (%u)",
517 exp
->data
.dtyp
->name
, exp
->data
.dtyp
->type
);
522 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
523 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
524 free(exp
->data
.numb
);
525 exp
->type
= PSI_T_CONST
;
526 exp
->data
.cnst
= cnst
;
530 data
->error(data
, exp
->token
, PSI_WARNING
,
531 "Unknown constant '%s' in numeric expression",
536 return psi_number_validate_number(data
, exp
);
538 case PSI_T_QUOTED_CHAR
:
539 return psi_number_validate_char(data
, exp
);
548 #include "Zend/zend_constants.h"
550 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
551 impl_val
*res
, struct psi_call_frame
*frame
)
553 switch (exp
->data
.cnst
->type
->type
) {
555 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
556 strlen(exp
->data
.cnst
->name
))->value
.lval
;
557 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
560 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
561 strlen(exp
->data
.cnst
->name
))->value
.dval
;
562 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
565 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
571 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
572 impl_val
*res
, struct psi_call_frame
*frame
)
575 struct psi_call_frame_symbol
*sym
;
576 struct psi_decl_type
*real
;
577 struct psi_decl_var
*var
;
580 var
= exp
->data
.dvar
;
581 real
= psi_decl_type_get_real(var
->arg
->type
);
582 size
= psi_decl_arg_get_size(var
->arg
);
583 sym
= psi_call_frame_fetch_symbol(frame
, var
);
584 ref
= deref_impl_val(sym
->ptr
, var
);
586 memcpy(res
, ref
, size
);
588 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
589 switch (SIZEOF_VOID_P
) {
601 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
602 impl_val
*res
, HashTable
*defs
)
604 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
612 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
, HashTable
*defs
)
616 *res
= exp
->data
.ival
;
617 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
620 *res
= exp
->data
.ival
;
621 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
624 *res
= exp
->data
.ival
;
625 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
628 *res
= exp
->data
.ival
;
629 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
632 *res
= exp
->data
.ival
;
633 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
636 *res
= exp
->data
.ival
;
637 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
640 *res
= exp
->data
.ival
;
641 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
644 *res
= exp
->data
.ival
;
645 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
649 *res
= exp
->data
.ival
;
650 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
654 case PSI_T_LONG_DOUBLE
:
655 *res
= exp
->data
.ival
;
656 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
661 res
->i64
= exp
->data
.enm
->val
;
662 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
666 res
->i64
= atol(exp
->data
.numb
);
670 return psi_number_eval_constant(exp
, res
, frame
);
673 return psi_number_eval_decl_var(exp
, res
, frame
);
676 return psi_number_eval_define(exp
, res
, defs
);