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
= strdup(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
= strdup(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 free(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
;
221 ntoken
= psi_token_init(PSI_T_POINTER
, "*", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
222 list
= psi_plist_add(list
, &ntoken
);
227 list
= psi_plist_add(list
, &ntoken
);
229 if (exp
->data
.dvar
->array_size
) {
230 char buf
[0x20], *ptr
;
232 ntoken
= psi_token_init(PSI_T_LBRACKET
, "[", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
233 list
= psi_plist_add(list
, &ntoken
);
234 ptr
= zend_print_ulong_to_buf(&buf
[sizeof(buf
) - 1], exp
->data
.dvar
->array_size
);
236 ntoken
= psi_token_init(PSI_T_NUMBER
, ptr
, strlen(ptr
), ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
237 list
= psi_plist_add(list
, &ntoken
);
243 ntoken
= psi_token_copy(exp
->token
);
244 list
= psi_plist_add(list
, &ntoken
);
245 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
246 list
= psi_plist_add(list
, &ntoken
);
247 ntoken
= psi_token_copy(exp
->data
.dtyp
->token
);
248 list
= psi_plist_add(list
, &ntoken
);
249 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
250 list
= psi_plist_add(list
, &ntoken
);
254 ntoken
= psi_token_copy(exp
->token
);
255 list
= psi_plist_add(list
, &ntoken
);
262 void psi_number_dump(int fd
, struct psi_number
*exp
)
266 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
269 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
272 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
275 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
278 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
281 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
284 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
287 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
290 if (isinf(exp
->data
.ival
.dval
)) {
291 dprintf(fd
, "\\INF");
292 } else if (isnan(exp
->data
.ival
.dval
)) {
293 dprintf(fd
, "\\NAN");
295 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
299 if (isinf(exp
->data
.ival
.dval
)) {
300 dprintf(fd
, "\\INF");
301 } else if (isnan(exp
->data
.ival
.dval
)) {
302 dprintf(fd
, "\\NAN");
304 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
308 case PSI_T_LONG_DOUBLE
:
309 if (isinfl(exp
->data
.ival
.ldval
)) {
310 dprintf(fd
, "\\INF");
311 } else if (isnanl(exp
->data
.ival
.ldval
)) {
312 dprintf(fd
, "\\NAN");
314 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
324 case PSI_T_QUOTED_CHAR
:
325 dprintf(fd
, "%s", exp
->data
.numb
);
328 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
331 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
334 dprintf(fd
, "%s", exp
->data
.enm
->name
);
337 psi_decl_var_dump(fd
, exp
->data
.dvar
);
340 dprintf(fd
, "sizeof(");
341 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
349 static inline bool psi_number_validate_enum(struct psi_data
*data
,
350 struct psi_number
*exp
, struct psi_validate_scope
*scope
)
352 if (scope
&& scope
->current_enum
) {
354 struct psi_decl_enum_item
*itm
;
355 struct psi_decl_enum
*enm
;
357 enm
= scope
->current_enum
;
361 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
362 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
363 psi_decl_var_free(&exp
->data
.dvar
);
364 exp
->type
= PSI_T_ENUM
;
366 return psi_number_validate(data
, exp
, scope
);
372 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
373 if (!strcmp(itm
->name
, exp
->data
.numb
)) {
374 free(exp
->data
.numb
);
375 exp
->type
= PSI_T_ENUM
;
377 return psi_number_validate(data
, exp
, scope
);
389 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
392 token_t typ
= PSI_T_INT8
;
403 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
404 res
->i8
= strtol(&numb
[1], &endptr
, 8);
408 res
->i8
= strtol(&numb
[2], &endptr
, 16);
442 impl_val tmp_val
= {0};
443 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
449 res
->i32
= res
->i8
<< (8 * *lvl
);
450 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
457 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
461 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
467 free(exp
->data
.numb
);
469 exp
->data
.ival
= val
;
473 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
478 switch (exp
->flags
& 0x0f) {
480 switch (exp
->flags
& 0x0f00) {
483 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
484 free(exp
->data
.numb
);
485 exp
->type
= PSI_T_INT64
;
486 exp
->data
.ival
.i64
= tmp
.i64
;
489 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
490 free(exp
->data
.numb
);
491 exp
->type
= PSI_T_INT64
;
492 exp
->data
.ival
.i64
= tmp
.i64
;
496 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
497 free(exp
->data
.numb
);
498 exp
->type
= PSI_T_UINT64
;
499 exp
->data
.ival
.u64
= tmp
.u64
;
502 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
503 free(exp
->data
.numb
);
504 exp
->type
= PSI_T_UINT64
;
505 exp
->data
.ival
.u64
= tmp
.u64
;
511 switch (exp
->flags
& 0x0ff00) {
514 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
515 free(exp
->data
.numb
);
516 exp
->type
= PSI_T_FLOAT
;
517 exp
->data
.ival
.fval
= tmp
.fval
;
522 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
523 free(exp
->data
.numb
);
524 exp
->type
= PSI_T_LONG_DOUBLE
;
525 exp
->data
.ival
.ldval
= tmp
.ldval
;
530 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
531 free(exp
->data
.numb
);
532 exp
->type
= PSI_T_DOUBLE
;
533 exp
->data
.ival
.dval
= tmp
.dval
;
542 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
544 free(exp
->data
.numb
);
545 exp
->type
= PSI_T_INT64
;
546 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
550 free(exp
->data
.numb
);
551 exp
->type
= PSI_T_DOUBLE
;
552 exp
->data
.ival
.dval
= tmp
.dval
;
556 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
560 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
561 struct psi_validate_scope
*scope
)
564 struct psi_const
*cnst
;
565 struct psi_decl_enum
*enm
;
569 exp
->type
= PSI_T_UINT8
;
583 case PSI_T_LONG_DOUBLE
:
589 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.dvar
->name
, strlen(exp
->data
.dvar
->name
))) {
592 if (scope
&& scope
->current_enum
&& psi_number_validate_enum(data
, exp
, scope
)) {
595 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
596 struct psi_validate_scope enum_scope
= *scope
;
597 enum_scope
.current_enum
= enm
;
598 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
602 if (exp
->data
.dvar
->arg
) {
605 if (psi_decl_var_validate(data
, exp
->data
.dvar
, scope
)) {
608 data
->error(data
, exp
->token
, PSI_WARNING
,
609 "Unknown variable '%s' in numeric expression",
610 exp
->data
.dvar
->name
);
614 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.numb
, strlen(exp
->data
.numb
))) {
620 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.numb
, strlen(exp
->data
.numb
))) {
621 if (!scope
->macro
|| strcmp(scope
->macro
->token
->text
, exp
->data
.numb
)) {
624 /* #define foo foo */
626 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
627 struct psi_validate_scope enum_scope
= *scope
;
628 enum_scope
.current_enum
= enm
;
629 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
636 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, NULL
, scope
)) {
637 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
639 exp
->type
= PSI_T_UINT64
;
640 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
641 psi_decl_type_free(&dtyp
);
644 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
646 data
->error(data
, exp
->token
, PSI_WARNING
,
647 "Cannot compute sizeof(%s) (%u)", dtyp
->name
, dtyp
->type
);
649 exp
->type
= PSI_T_UINT8
;
650 exp
->data
.ival
.u8
= 0;
651 psi_decl_type_free(&dtyp
);
659 if (*exp
->data
.numb
== '\\') {
660 zc
= zend_get_constant_str(exp
->data
.numb
+ 1, strlen(exp
->data
.numb
) - 1);
662 zc
= zend_get_constant_str(exp
->data
.numb
, strlen(exp
->data
.numb
));
666 switch (Z_TYPE_P(zc
)) {
668 free(exp
->data
.numb
);
669 exp
->type
= PSI_T_INT64
;
670 exp
->data
.ival
.i64
= Z_LVAL_P(zc
);
674 free(exp
->data
.numb
);
675 exp
->type
= PSI_T_DOUBLE
;
676 exp
->data
.ival
.dval
= Z_DVAL_P(zc
);
684 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
685 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
686 free(exp
->data
.numb
);
687 exp
->type
= PSI_T_CONST
;
688 exp
->data
.cnst
= cnst
;
692 data
->error(data
, exp
->token
, PSI_WARNING
,
693 "Unknown constant '%s' in numeric expression",
698 return psi_number_validate_number(data
, exp
);
700 case PSI_T_QUOTED_CHAR
:
701 return psi_number_validate_char(data
, exp
);
710 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
711 impl_val
*res
, struct psi_call_frame
*frame
)
713 switch (exp
->data
.cnst
->type
->type
) {
715 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
716 strlen(exp
->data
.cnst
->name
))->value
.lval
;
717 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
720 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
721 strlen(exp
->data
.cnst
->name
))->value
.dval
;
722 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
725 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
731 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
732 impl_val
*res
, struct psi_call_frame
*frame
)
735 struct psi_call_frame_symbol
*sym
;
736 struct psi_decl_type
*real
;
737 struct psi_decl_var
*var
;
740 var
= exp
->data
.dvar
;
741 real
= psi_decl_type_get_real(var
->arg
->type
);
742 size
= psi_decl_arg_get_size(var
->arg
);
743 sym
= psi_call_frame_fetch_symbol(frame
, var
);
744 ref
= deref_impl_val(sym
->ptr
, var
);
746 memcpy(res
, ref
, size
);
748 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
749 switch (SIZEOF_VOID_P
) {
761 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
762 impl_val
*res
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
765 struct psi_cpp_macro_decl
*macro
;
767 macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
768 if (macro
&& macro
->exp
&& macro
->exp
!= rec_guard
) {
769 return psi_num_exp_exec(macro
->exp
, res
, NULL
, defs
);
776 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
,
777 struct psi_call_frame
*frame
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
781 *res
= exp
->data
.ival
;
782 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
785 *res
= exp
->data
.ival
;
786 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
789 *res
= exp
->data
.ival
;
790 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
793 *res
= exp
->data
.ival
;
794 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
797 *res
= exp
->data
.ival
;
798 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
801 *res
= exp
->data
.ival
;
802 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
805 *res
= exp
->data
.ival
;
806 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
809 *res
= exp
->data
.ival
;
810 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
814 *res
= exp
->data
.ival
;
815 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIfval
, res
->fval
);
819 *res
= exp
->data
.ival
;
820 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
824 case PSI_T_LONG_DOUBLE
:
825 *res
= exp
->data
.ival
;
826 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
831 res
->i64
= exp
->data
.enm
->val
;
832 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
836 res
->i64
= atol(exp
->data
.numb
);
840 return psi_number_eval_constant(exp
, res
, frame
);
843 return psi_number_eval_decl_var(exp
, res
, frame
);
846 return psi_number_eval_define(exp
, res
, defs
, rec_guard
);