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
;
159 psi_token_free(&exp
->token
);
172 case PSI_T_LONG_DOUBLE
:
179 psi_cpp_macro_call_free(&exp
->data
.call
);
184 case PSI_T_QUOTED_CHAR
:
185 zend_string_release(exp
->data
.numb
);
188 psi_decl_var_free(&exp
->data
.dvar
);
191 psi_decl_type_free(&exp
->data
.dtyp
);
200 struct psi_plist
*psi_number_tokens(struct psi_number
*exp
,
201 struct psi_plist
*list
)
203 struct psi_token
*ntoken
;
205 list
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
211 ntoken
= psi_token_copy(exp
->data
.dvar
->token
);
213 if (exp
->data
.dvar
->pointer_level
> 1 || !exp
->data
.dvar
->array_size
) {
214 struct psi_token
*temp
= ntoken
;
215 unsigned pl
= exp
->data
.dvar
->pointer_level
- !!exp
->data
.dvar
->array_size
;
218 ntoken
= psi_token_init(PSI_T_POINTER
, "*", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
219 list
= psi_plist_add(list
, &ntoken
);
224 list
= psi_plist_add(list
, &ntoken
);
226 if (exp
->data
.dvar
->array_size
) {
227 char buf
[0x20], *ptr
;
229 ntoken
= psi_token_init(PSI_T_LBRACKET
, "[", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
230 list
= psi_plist_add(list
, &ntoken
);
231 ptr
= zend_print_ulong_to_buf(&buf
[sizeof(buf
) - 1], exp
->data
.dvar
->array_size
);
233 ntoken
= psi_token_init(PSI_T_NUMBER
, ptr
, strlen(ptr
), ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
234 list
= psi_plist_add(list
, &ntoken
);
240 ntoken
= psi_token_copy(exp
->token
);
241 list
= psi_plist_add(list
, &ntoken
);
242 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
243 list
= psi_plist_add(list
, &ntoken
);
244 ntoken
= psi_token_copy(exp
->data
.dtyp
->token
);
245 list
= psi_plist_add(list
, &ntoken
);
246 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
247 list
= psi_plist_add(list
, &ntoken
);
251 ntoken
= psi_token_copy(exp
->token
);
252 list
= psi_plist_add(list
, &ntoken
);
259 void psi_number_dump(int fd
, struct psi_number
*exp
)
263 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
266 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
269 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
272 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
275 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
278 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
281 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
284 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
287 if (isinf(exp
->data
.ival
.dval
)) {
288 dprintf(fd
, "\\INF");
289 } else if (isnan(exp
->data
.ival
.dval
)) {
290 dprintf(fd
, "\\NAN");
292 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
296 if (isinf(exp
->data
.ival
.dval
)) {
297 dprintf(fd
, "\\INF");
298 } else if (isnan(exp
->data
.ival
.dval
)) {
299 dprintf(fd
, "\\NAN");
301 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
305 case PSI_T_LONG_DOUBLE
:
306 if (isinfl(exp
->data
.ival
.ldval
)) {
307 dprintf(fd
, "\\INF");
308 } else if (isnanl(exp
->data
.ival
.ldval
)) {
309 dprintf(fd
, "\\NAN");
311 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
321 case PSI_T_QUOTED_CHAR
:
322 dprintf(fd
, "%s", exp
->data
.numb
->val
);
325 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
328 dprintf(fd
, "%s", exp
->data
.cnst
->name
->val
);
331 dprintf(fd
, "%s", exp
->data
.enm
->name
->val
);
334 psi_decl_var_dump(fd
, exp
->data
.dvar
);
337 dprintf(fd
, "sizeof(");
338 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
346 static inline bool psi_number_validate_enum(struct psi_data
*data
,
347 struct psi_number
*exp
, struct psi_validate_scope
*scope
)
349 if (scope
&& scope
->current_enum
) {
351 struct psi_decl_enum_item
*itm
;
352 struct psi_decl_enum
*enm
;
354 enm
= scope
->current_enum
;
358 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
359 if (zend_string_equals(itm
->name
, exp
->data
.dvar
->name
)) {
360 psi_decl_var_free(&exp
->data
.dvar
);
361 exp
->type
= PSI_T_ENUM
;
363 return psi_number_validate(data
, exp
, scope
);
369 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
370 if (zend_string_equals(itm
->name
, exp
->data
.numb
)) {
371 zend_string_release(exp
->data
.numb
);
372 exp
->type
= PSI_T_ENUM
;
374 return psi_number_validate(data
, exp
, scope
);
386 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
389 token_t typ
= PSI_T_INT8
;
400 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
401 res
->i8
= strtol(&numb
[1], &endptr
, 8);
405 res
->i8
= strtol(&numb
[2], &endptr
, 16);
439 impl_val tmp_val
= {0};
440 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
446 res
->i32
= res
->i8
<< (8 * *lvl
);
447 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
454 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
458 token_t typ
= validate_char(exp
->data
.numb
->val
, &val
, &lvl
);
464 zend_string_release(exp
->data
.numb
);
466 exp
->data
.ival
= val
;
470 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
475 switch (exp
->flags
& 0x0f) {
477 switch (exp
->flags
& 0x0f00) {
480 tmp
.i64
= strtol(exp
->data
.numb
->val
, NULL
, 0);
481 zend_string_release(exp
->data
.numb
);
482 exp
->type
= PSI_T_INT64
;
483 exp
->data
.ival
.i64
= tmp
.i64
;
486 tmp
.i64
= strtoll(exp
->data
.numb
->val
, NULL
, 0);
487 zend_string_release(exp
->data
.numb
);
488 exp
->type
= PSI_T_INT64
;
489 exp
->data
.ival
.i64
= tmp
.i64
;
493 tmp
.u64
= strtoul(exp
->data
.numb
->val
, NULL
, 0);
494 zend_string_release(exp
->data
.numb
);
495 exp
->type
= PSI_T_UINT64
;
496 exp
->data
.ival
.u64
= tmp
.u64
;
499 tmp
.u64
= strtoull(exp
->data
.numb
->val
, NULL
, 0);
500 zend_string_release(exp
->data
.numb
);
501 exp
->type
= PSI_T_UINT64
;
502 exp
->data
.ival
.u64
= tmp
.u64
;
508 switch (exp
->flags
& 0x0ff00) {
511 tmp
.fval
= strtof(exp
->data
.numb
->val
, NULL
);
512 zend_string_release(exp
->data
.numb
);
513 exp
->type
= PSI_T_FLOAT
;
514 exp
->data
.ival
.fval
= tmp
.fval
;
519 tmp
.ldval
= strtold(exp
->data
.numb
->val
, NULL
);
520 zend_string_release(exp
->data
.numb
);
521 exp
->type
= PSI_T_LONG_DOUBLE
;
522 exp
->data
.ival
.ldval
= tmp
.ldval
;
527 tmp
.dval
= strtod(exp
->data
.numb
->val
, NULL
);
528 zend_string_release(exp
->data
.numb
);
529 exp
->type
= PSI_T_DOUBLE
;
530 exp
->data
.ival
.dval
= tmp
.dval
;
539 switch (is_numeric_str_function(exp
->data
.numb
, (zend_long
*) &tmp
, (double *) &tmp
)) {
541 zend_string_release(exp
->data
.numb
);
542 exp
->type
= PSI_T_INT64
;
543 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
547 zend_string_release(exp
->data
.numb
);
548 exp
->type
= PSI_T_DOUBLE
;
549 exp
->data
.ival
.dval
= tmp
.dval
;
553 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
557 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
558 struct psi_validate_scope
*scope
)
561 struct psi_const
*cnst
;
562 struct psi_decl_enum
*enm
;
566 exp
->type
= PSI_T_UINT8
;
580 case PSI_T_LONG_DOUBLE
:
586 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.dvar
->name
)) {
589 if (scope
&& scope
->current_enum
&& psi_number_validate_enum(data
, exp
, scope
)) {
592 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
593 struct psi_validate_scope enum_scope
= *scope
;
594 enum_scope
.current_enum
= enm
;
595 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
599 if (exp
->data
.dvar
->arg
) {
602 if (psi_decl_var_validate(data
, exp
->data
.dvar
, scope
)) {
605 data
->error(data
, exp
->token
, PSI_WARNING
,
606 "Unknown variable '%s' in numeric expression",
607 exp
->data
.dvar
->name
->val
);
611 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.numb
)) {
617 if (scope
&& scope
->defs
&& zend_hash_exists(scope
->defs
, exp
->data
.numb
)) {
618 if (!scope
->macro
|| !zend_string_equals(scope
->macro
->token
->text
, exp
->data
.numb
)) {
621 /* #define foo foo */
623 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
624 struct psi_validate_scope enum_scope
= *scope
;
625 enum_scope
.current_enum
= enm
;
626 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
633 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, NULL
, scope
)) {
634 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
636 exp
->type
= PSI_T_UINT64
;
637 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
638 psi_decl_type_free(&dtyp
);
641 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
643 data
->error(data
, exp
->token
, PSI_WARNING
,
644 "Cannot compute sizeof(%s) (%u)", dtyp
->name
->val
, dtyp
->type
);
646 exp
->type
= PSI_T_UINT8
;
647 exp
->data
.ival
.u8
= 0;
648 psi_decl_type_free(&dtyp
);
656 if (exp
->data
.numb
->val
[0] == '\\') {
657 zc
= zend_get_constant_str(&exp
->data
.numb
->val
[1], exp
->data
.numb
->len
- 1);
659 zc
= zend_get_constant(exp
->data
.numb
);
663 switch (Z_TYPE_P(zc
)) {
665 zend_string_release(exp
->data
.numb
);
666 exp
->type
= PSI_T_INT64
;
667 exp
->data
.ival
.i64
= Z_LVAL_P(zc
);
671 zend_string_release(exp
->data
.numb
);
672 exp
->type
= PSI_T_DOUBLE
;
673 exp
->data
.ival
.dval
= Z_DVAL_P(zc
);
681 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
682 if (zend_string_equals(cnst
->name
, exp
->data
.numb
)) {
683 zend_string_release(exp
->data
.numb
);
684 exp
->type
= PSI_T_CONST
;
685 exp
->data
.cnst
= cnst
;
689 data
->error(data
, exp
->token
, PSI_WARNING
,
690 "Unknown constant '%s' in numeric expression",
691 exp
->data
.numb
->val
);
695 return psi_number_validate_number(data
, exp
);
697 case PSI_T_QUOTED_CHAR
:
698 return psi_number_validate_char(data
, exp
);
707 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
708 impl_val
*res
, struct psi_call_frame
*frame
)
710 switch (exp
->data
.cnst
->type
->type
) {
712 res
->i64
= zend_get_constant(exp
->data
.cnst
->name
)->value
.lval
;
713 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
716 res
->dval
= zend_get_constant(exp
->data
.cnst
->name
)->value
.dval
;
717 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
720 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
726 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
727 impl_val
*res
, struct psi_call_frame
*frame
)
730 struct psi_call_frame_symbol
*sym
;
731 struct psi_decl_type
*real
;
732 struct psi_decl_var
*var
;
735 var
= exp
->data
.dvar
;
736 real
= psi_decl_type_get_real(var
->arg
->type
);
737 size
= psi_decl_arg_get_size(var
->arg
);
738 sym
= psi_call_frame_fetch_symbol(frame
, var
);
739 ref
= deref_impl_val(sym
->ptr
, var
);
741 memcpy(res
, ref
, size
);
743 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
744 switch (SIZEOF_VOID_P
) {
756 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
757 impl_val
*res
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
760 struct psi_cpp_macro_decl
*macro
;
762 macro
= zend_hash_find_ptr(defs
, exp
->data
.numb
);
763 if (macro
&& macro
->exp
&& macro
->exp
!= rec_guard
) {
764 return psi_num_exp_exec(macro
->exp
, res
, NULL
, defs
);
771 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
,
772 struct psi_call_frame
*frame
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
776 *res
= exp
->data
.ival
;
777 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
780 *res
= exp
->data
.ival
;
781 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
784 *res
= exp
->data
.ival
;
785 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
788 *res
= exp
->data
.ival
;
789 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
792 *res
= exp
->data
.ival
;
793 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
796 *res
= exp
->data
.ival
;
797 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
800 *res
= exp
->data
.ival
;
801 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
804 *res
= exp
->data
.ival
;
805 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
809 *res
= exp
->data
.ival
;
810 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIfval
, res
->fval
);
814 *res
= exp
->data
.ival
;
815 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
819 case PSI_T_LONG_DOUBLE
:
820 *res
= exp
->data
.ival
;
821 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
826 res
->i64
= exp
->data
.enm
->val
;
827 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
831 res
->i64
= atol(exp
->data
.numb
->val
);
835 return psi_number_eval_constant(exp
, res
, frame
);
838 return psi_number_eval_decl_var(exp
, res
, frame
);
841 return psi_number_eval_define(exp
, res
, defs
, rec_guard
);