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"
36 #include "Zend/zend_constants.h"
37 #include "Zend/zend_operators.h"
40 struct psi_number
*psi_number_init(token_t t
, void *num
, unsigned flags
)
42 struct psi_number
*exp
= calloc(1, sizeof(*exp
));
45 switch (exp
->type
= t
) {
47 exp
->data
.ival
.i8
= *(int8_t *) num
;
50 exp
->data
.ival
.u8
= *(uint8_t *) num
;
53 exp
->data
.ival
.i16
= *(int16_t *) num
;
56 exp
->data
.ival
.u16
= *(uint16_t *) num
;
59 exp
->data
.ival
.i32
= *(int32_t *) num
;
62 exp
->data
.ival
.u32
= *(uint32_t *) num
;
65 exp
->data
.ival
.i64
= *(int64_t *) num
;
68 exp
->data
.ival
.u64
= *(uint64_t *) num
;
71 exp
->data
.ival
.fval
= *(float *) num
;
74 exp
->data
.ival
.dval
= *(double *) num
;
77 case PSI_T_LONG_DOUBLE
:
78 exp
->data
.ival
.ldval
= *(long double *) num
;
83 case PSI_T_QUOTED_CHAR
:
87 exp
->data
.numb
= zend_string_copy(num
);
105 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
107 struct psi_number
*num
= calloc(1, sizeof(*num
));
112 num
->token
= psi_token_copy(num
->token
);
126 case PSI_T_LONG_DOUBLE
:
135 case PSI_T_QUOTED_CHAR
:
136 num
->data
.numb
= zend_string_copy(num
->data
.numb
);
139 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
142 num
->data
.call
= psi_cpp_macro_call_copy(num
->data
.call
);
145 num
->data
.dtyp
= psi_decl_type_copy(num
->data
.dtyp
);
153 void psi_number_free(struct psi_number
**exp_ptr
)
156 struct psi_number
*exp
= *exp_ptr
;
174 case PSI_T_LONG_DOUBLE
:
181 psi_cpp_macro_call_free(&exp
->data
.call
);
186 case PSI_T_QUOTED_CHAR
:
187 zend_string_release(exp
->data
.numb
);
190 psi_decl_var_free(&exp
->data
.dvar
);
193 psi_decl_type_free(&exp
->data
.dtyp
);
202 struct psi_plist
*psi_number_tokens(struct psi_number
*exp
,
203 struct psi_plist
*list
)
205 struct psi_token
*ntoken
;
207 list
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
213 ntoken
= psi_token_copy(exp
->data
.dvar
->token
);
215 if (exp
->data
.dvar
->pointer_level
> 1 || !exp
->data
.dvar
->array_size
) {
216 struct psi_token
*temp
= ntoken
;
217 unsigned pl
= exp
->data
.dvar
->pointer_level
- !!exp
->data
.dvar
->array_size
;
220 ntoken
= psi_token_init(PSI_T_POINTER
, "*", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
221 list
= psi_plist_add(list
, &ntoken
);
226 list
= psi_plist_add(list
, &ntoken
);
228 if (exp
->data
.dvar
->array_size
) {
229 char buf
[0x20], *ptr
;
231 ntoken
= psi_token_init(PSI_T_LBRACKET
, "[", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
232 list
= psi_plist_add(list
, &ntoken
);
233 ptr
= zend_print_ulong_to_buf(&buf
[sizeof(buf
) - 1], exp
->data
.dvar
->array_size
);
235 ntoken
= psi_token_init(PSI_T_NUMBER
, ptr
, strlen(ptr
), ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
236 list
= psi_plist_add(list
, &ntoken
);
242 ntoken
= psi_token_copy(exp
->token
);
243 list
= psi_plist_add(list
, &ntoken
);
244 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
245 list
= psi_plist_add(list
, &ntoken
);
246 ntoken
= psi_token_copy(exp
->data
.dtyp
->token
);
247 list
= psi_plist_add(list
, &ntoken
);
248 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
249 list
= psi_plist_add(list
, &ntoken
);
253 ntoken
= psi_token_copy(exp
->token
);
254 list
= psi_plist_add(list
, &ntoken
);
261 void psi_number_dump(int fd
, struct psi_number
*exp
)
265 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
268 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
271 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
274 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
277 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
280 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
283 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
286 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
289 if (isinf(exp
->data
.ival
.dval
)) {
290 dprintf(fd
, "\\INF");
291 } else if (isnan(exp
->data
.ival
.dval
)) {
292 dprintf(fd
, "\\NAN");
294 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
298 if (isinf(exp
->data
.ival
.dval
)) {
299 dprintf(fd
, "\\INF");
300 } else if (isnan(exp
->data
.ival
.dval
)) {
301 dprintf(fd
, "\\NAN");
303 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
307 case PSI_T_LONG_DOUBLE
:
308 if (isinfl(exp
->data
.ival
.ldval
)) {
309 dprintf(fd
, "\\INF");
310 } else if (isnanl(exp
->data
.ival
.ldval
)) {
311 dprintf(fd
, "\\NAN");
313 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
323 case PSI_T_QUOTED_CHAR
:
324 dprintf(fd
, "%s", exp
->data
.numb
->val
);
327 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
330 dprintf(fd
, "%s", exp
->data
.cnst
->name
->val
);
333 dprintf(fd
, "%s", exp
->data
.enm
->name
->val
);
336 psi_decl_var_dump(fd
, exp
->data
.dvar
);
339 dprintf(fd
, "sizeof(");
340 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
348 static inline bool psi_number_validate_enum(struct psi_data
*data
,
349 struct psi_number
*exp
, struct psi_validate_scope
*scope
)
351 if (scope
&& scope
->current_enum
) {
353 struct psi_decl_enum_item
*itm
;
354 struct psi_decl_enum
*enm
;
356 enm
= scope
->current_enum
;
360 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
361 if (zend_string_equals(itm
->name
, exp
->data
.dvar
->name
)) {
362 psi_decl_var_free(&exp
->data
.dvar
);
363 exp
->type
= PSI_T_ENUM
;
365 return psi_number_validate(data
, exp
, scope
);
371 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
372 if (zend_string_equals(itm
->name
, exp
->data
.numb
)) {
373 zend_string_release(exp
->data
.numb
);
374 exp
->type
= PSI_T_ENUM
;
376 return psi_number_validate(data
, exp
, scope
);
388 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
391 token_t typ
= PSI_T_INT8
;
402 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
403 res
->i8
= strtol(&numb
[1], &endptr
, 8);
407 res
->i8
= strtol(&numb
[2], &endptr
, 16);
441 impl_val tmp_val
= {0};
442 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
448 res
->i32
= res
->i8
<< (8 * *lvl
);
449 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
456 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
460 token_t typ
= validate_char(exp
->data
.numb
->val
, &val
, &lvl
);
466 zend_string_release(exp
->data
.numb
);
468 exp
->data
.ival
= val
;
472 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
477 switch (exp
->flags
& 0x0f) {
479 switch (exp
->flags
& 0x0f00) {
482 tmp
.i64
= strtol(exp
->data
.numb
->val
, NULL
, 0);
483 zend_string_release(exp
->data
.numb
);
484 exp
->type
= PSI_T_INT64
;
485 exp
->data
.ival
.i64
= tmp
.i64
;
488 tmp
.i64
= strtoll(exp
->data
.numb
->val
, NULL
, 0);
489 zend_string_release(exp
->data
.numb
);
490 exp
->type
= PSI_T_INT64
;
491 exp
->data
.ival
.i64
= tmp
.i64
;
495 tmp
.u64
= strtoul(exp
->data
.numb
->val
, NULL
, 0);
496 zend_string_release(exp
->data
.numb
);
497 exp
->type
= PSI_T_UINT64
;
498 exp
->data
.ival
.u64
= tmp
.u64
;
501 tmp
.u64
= strtoull(exp
->data
.numb
->val
, NULL
, 0);
502 zend_string_release(exp
->data
.numb
);
503 exp
->type
= PSI_T_UINT64
;
504 exp
->data
.ival
.u64
= tmp
.u64
;
510 switch (exp
->flags
& 0x0ff00) {
513 tmp
.fval
= strtof(exp
->data
.numb
->val
, NULL
);
514 zend_string_release(exp
->data
.numb
);
515 exp
->type
= PSI_T_FLOAT
;
516 exp
->data
.ival
.fval
= tmp
.fval
;
521 tmp
.ldval
= strtold(exp
->data
.numb
->val
, NULL
);
522 zend_string_release(exp
->data
.numb
);
523 exp
->type
= PSI_T_LONG_DOUBLE
;
524 exp
->data
.ival
.ldval
= tmp
.ldval
;
529 tmp
.dval
= strtod(exp
->data
.numb
->val
, NULL
);
530 zend_string_release(exp
->data
.numb
);
531 exp
->type
= PSI_T_DOUBLE
;
532 exp
->data
.ival
.dval
= tmp
.dval
;
541 switch (is_numeric_str_function(exp
->data
.numb
, (zend_long
*) &tmp
, (double *) &tmp
)) {
543 zend_string_release(exp
->data
.numb
);
544 exp
->type
= PSI_T_INT64
;
545 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
549 zend_string_release(exp
->data
.numb
);
550 exp
->type
= PSI_T_DOUBLE
;
551 exp
->data
.ival
.dval
= tmp
.dval
;
555 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
559 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
560 struct psi_validate_scope
*scope
)
563 struct psi_const
*cnst
;
564 struct psi_decl_enum
*enm
;
568 exp
->type
= PSI_T_UINT8
;
582 case PSI_T_LONG_DOUBLE
:
588 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.dvar
->name
)) {
591 if (scope
&& scope
->current_enum
&& psi_number_validate_enum(data
, exp
, scope
)) {
594 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
595 struct psi_validate_scope enum_scope
= *scope
;
596 enum_scope
.current_enum
= enm
;
597 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
601 if (exp
->data
.dvar
->arg
) {
604 if (psi_decl_var_validate(data
, exp
->data
.dvar
, scope
)) {
607 data
->error(data
, exp
->token
, PSI_WARNING
,
608 "Unknown variable '%s' in numeric expression",
609 exp
->data
.dvar
->name
->val
);
613 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.numb
)) {
619 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.numb
)) {
620 if (!scope
->macro
|| !zend_string_equals(scope
->macro
->token
->text
, exp
->data
.numb
)) {
623 /* #define foo foo */
625 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
626 struct psi_validate_scope enum_scope
= *scope
;
627 enum_scope
.current_enum
= enm
;
628 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
635 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, NULL
, scope
)) {
636 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
638 exp
->type
= PSI_T_UINT64
;
639 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
640 psi_decl_type_free(&dtyp
);
643 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
645 data
->error(data
, exp
->token
, PSI_WARNING
,
646 "Cannot compute sizeof(%s) (%u)", dtyp
->name
->val
, dtyp
->type
);
648 exp
->type
= PSI_T_UINT8
;
649 exp
->data
.ival
.u8
= 0;
650 psi_decl_type_free(&dtyp
);
658 if (exp
->data
.numb
->val
[0] == '\\') {
659 zc
= zend_get_constant_str(&exp
->data
.numb
->val
[1], exp
->data
.numb
->len
- 1);
661 zc
= zend_get_constant(exp
->data
.numb
);
665 switch (Z_TYPE_P(zc
)) {
667 zend_string_release(exp
->data
.numb
);
668 exp
->type
= PSI_T_INT64
;
669 exp
->data
.ival
.i64
= Z_LVAL_P(zc
);
673 zend_string_release(exp
->data
.numb
);
674 exp
->type
= PSI_T_DOUBLE
;
675 exp
->data
.ival
.dval
= Z_DVAL_P(zc
);
683 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
684 if (zend_string_equals(cnst
->name
, exp
->data
.numb
)) {
685 zend_string_release(exp
->data
.numb
);
686 exp
->type
= PSI_T_CONST
;
687 exp
->data
.cnst
= cnst
;
691 data
->error(data
, exp
->token
, PSI_WARNING
,
692 "Unknown constant '%s' in numeric expression",
693 exp
->data
.numb
->val
);
697 return psi_number_validate_number(data
, exp
);
699 case PSI_T_QUOTED_CHAR
:
700 return psi_number_validate_char(data
, exp
);
709 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
710 impl_val
*res
, struct psi_call_frame
*frame
)
712 switch (exp
->data
.cnst
->type
->type
) {
714 res
->i64
= zend_get_constant(exp
->data
.cnst
->name
)->value
.lval
;
715 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
718 res
->dval
= zend_get_constant(exp
->data
.cnst
->name
)->value
.dval
;
719 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
722 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
728 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
729 impl_val
*res
, struct psi_call_frame
*frame
)
732 struct psi_call_frame_symbol
*sym
;
733 struct psi_decl_type
*real
;
734 struct psi_decl_var
*var
;
737 var
= exp
->data
.dvar
;
738 real
= psi_decl_type_get_real(var
->arg
->type
);
739 size
= psi_decl_arg_get_size(var
->arg
);
740 sym
= psi_call_frame_fetch_symbol(frame
, var
);
741 ref
= deref_impl_val(sym
->ptr
, var
);
743 memcpy(res
, ref
, size
);
745 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
746 switch (SIZEOF_VOID_P
) {
758 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
759 impl_val
*res
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
762 struct psi_cpp_macro_decl
*macro
;
764 macro
= zend_hash_find_ptr(defs
, exp
->data
.numb
);
765 if (macro
&& macro
->exp
&& macro
->exp
!= rec_guard
) {
766 return psi_num_exp_exec(macro
->exp
, res
, NULL
, defs
);
773 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
,
774 struct psi_call_frame
*frame
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
778 *res
= exp
->data
.ival
;
779 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
782 *res
= exp
->data
.ival
;
783 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
786 *res
= exp
->data
.ival
;
787 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
790 *res
= exp
->data
.ival
;
791 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
794 *res
= exp
->data
.ival
;
795 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
798 *res
= exp
->data
.ival
;
799 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
802 *res
= exp
->data
.ival
;
803 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
806 *res
= exp
->data
.ival
;
807 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
811 *res
= exp
->data
.ival
;
812 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIfval
, res
->fval
);
816 *res
= exp
->data
.ival
;
817 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
821 case PSI_T_LONG_DOUBLE
:
822 *res
= exp
->data
.ival
;
823 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
828 res
->i64
= exp
->data
.enm
->val
;
829 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
833 res
->i64
= atol(exp
->data
.numb
->val
);
837 return psi_number_eval_constant(exp
, res
, frame
);
840 return psi_number_eval_decl_var(exp
, res
, frame
);
843 return psi_number_eval_define(exp
, res
, defs
, rec_guard
);