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
.fval
= *(float *) num
;
69 exp
->data
.ival
.dval
= *(double *) num
;
72 case PSI_T_LONG_DOUBLE
:
73 exp
->data
.ival
.ldval
= *(long double *) num
;
78 case PSI_T_QUOTED_CHAR
:
82 exp
->data
.numb
= strdup(num
);
100 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
102 struct psi_number
*num
= calloc(1, sizeof(*num
));
107 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
;
169 case PSI_T_LONG_DOUBLE
:
176 psi_cpp_macro_call_free(&exp
->data
.call
);
181 case PSI_T_QUOTED_CHAR
:
182 free(exp
->data
.numb
);
185 psi_decl_var_free(&exp
->data
.dvar
);
188 psi_decl_type_free(&exp
->data
.dtyp
);
197 struct psi_plist
*psi_number_tokens(struct psi_number
*exp
,
198 struct psi_plist
*list
)
200 struct psi_token
*ntoken
;
202 list
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
208 ntoken
= psi_token_copy(exp
->data
.dvar
->token
);
210 if (exp
->data
.dvar
->pointer_level
> 1 || !exp
->data
.dvar
->array_size
) {
211 struct psi_token
*temp
= ntoken
;
212 unsigned pl
= exp
->data
.dvar
->pointer_level
- !!exp
->data
.dvar
->array_size
;
216 ntoken
= psi_token_init(PSI_T_POINTER
, "*", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
217 list
= psi_plist_add(list
, &ntoken
);
222 list
= psi_plist_add(list
, &ntoken
);
224 if (exp
->data
.dvar
->array_size
) {
225 char buf
[0x20], *ptr
;
227 ntoken
= psi_token_init(PSI_T_LBRACKET
, "[", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
228 list
= psi_plist_add(list
, &ntoken
);
229 ptr
= zend_print_ulong_to_buf(&buf
[sizeof(buf
) - 1], exp
->data
.dvar
->array_size
);
231 ntoken
= psi_token_init(PSI_T_NUMBER
, ptr
, strlen(ptr
), ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
232 list
= psi_plist_add(list
, &ntoken
);
238 ntoken
= psi_token_copy(exp
->token
);
239 list
= psi_plist_add(list
, &ntoken
);
240 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
241 list
= psi_plist_add(list
, &ntoken
);
242 ntoken
= psi_token_copy(exp
->data
.dtyp
->token
);
243 list
= psi_plist_add(list
, &ntoken
);
244 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->size
, ntoken
->line
, ntoken
->file
);
245 list
= psi_plist_add(list
, &ntoken
);
249 ntoken
= psi_token_copy(exp
->token
);
250 list
= psi_plist_add(list
, &ntoken
);
257 void psi_number_dump(int fd
, struct psi_number
*exp
)
261 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
264 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
267 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
270 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
273 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
276 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
279 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
282 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
285 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
288 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
291 case PSI_T_LONG_DOUBLE
:
292 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
301 case PSI_T_QUOTED_CHAR
:
302 dprintf(fd
, "%s", exp
->data
.numb
);
305 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
308 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
311 dprintf(fd
, "%s", exp
->data
.enm
->name
);
314 psi_decl_var_dump(fd
, exp
->data
.dvar
);
317 dprintf(fd
, "sizeof(");
318 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
326 static inline bool psi_number_validate_enum(struct psi_data
*data
,
327 struct psi_number
*exp
, struct psi_validate_scope
*scope
)
329 if (scope
&& scope
->current_enum
) {
331 struct psi_decl_enum_item
*itm
;
332 struct psi_decl_enum
*enm
;
334 enm
= scope
->current_enum
;
338 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
339 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
340 psi_decl_var_free(&exp
->data
.dvar
);
341 exp
->type
= PSI_T_ENUM
;
343 return psi_number_validate(data
, exp
, scope
);
349 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
350 if (!strcmp(itm
->name
, exp
->data
.numb
)) {
351 free(exp
->data
.numb
);
352 exp
->type
= PSI_T_ENUM
;
354 return psi_number_validate(data
, exp
, scope
);
366 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
369 token_t typ
= PSI_T_INT8
;
380 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
381 res
->i8
= strtol(&numb
[1], &endptr
, 8);
385 res
->i8
= strtol(&numb
[2], &endptr
, 16);
419 impl_val tmp_val
= {0};
420 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
426 res
->i32
= res
->i8
<< (8 * *lvl
);
427 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
434 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
438 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
444 free(exp
->data
.numb
);
446 exp
->data
.ival
= val
;
450 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
455 switch (exp
->flags
& 0x0f) {
457 switch (exp
->flags
& 0x0f00) {
460 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
461 free(exp
->data
.numb
);
462 exp
->type
= PSI_T_INT64
;
463 exp
->data
.ival
.i64
= tmp
.i64
;
466 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
467 free(exp
->data
.numb
);
468 exp
->type
= PSI_T_INT64
;
469 exp
->data
.ival
.i64
= tmp
.i64
;
473 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
474 free(exp
->data
.numb
);
475 exp
->type
= PSI_T_UINT64
;
476 exp
->data
.ival
.u64
= tmp
.u64
;
479 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
480 free(exp
->data
.numb
);
481 exp
->type
= PSI_T_UINT64
;
482 exp
->data
.ival
.u64
= tmp
.u64
;
488 switch (exp
->flags
& 0x0ff00) {
491 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
492 free(exp
->data
.numb
);
493 exp
->type
= PSI_T_FLOAT
;
494 exp
->data
.ival
.fval
= tmp
.fval
;
499 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
500 free(exp
->data
.numb
);
501 exp
->type
= PSI_T_LONG_DOUBLE
;
502 exp
->data
.ival
.ldval
= tmp
.ldval
;
507 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
508 free(exp
->data
.numb
);
509 exp
->type
= PSI_T_DOUBLE
;
510 exp
->data
.ival
.dval
= tmp
.dval
;
519 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
521 free(exp
->data
.numb
);
522 exp
->type
= PSI_T_INT64
;
523 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
527 free(exp
->data
.numb
);
528 exp
->type
= PSI_T_DOUBLE
;
529 exp
->data
.ival
.dval
= tmp
.dval
;
533 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
537 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
538 struct psi_validate_scope
*scope
)
541 struct psi_const
*cnst
;
542 struct psi_decl_enum
*enm
;
546 exp
->type
= PSI_T_UINT8
;
560 case PSI_T_LONG_DOUBLE
:
566 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.dvar
->name
, strlen(exp
->data
.dvar
->name
))) {
569 if (scope
&& scope
->current_enum
&& psi_number_validate_enum(data
, exp
, scope
)) {
572 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
573 struct psi_validate_scope enum_scope
= *scope
;
574 enum_scope
.current_enum
= enm
;
575 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
579 if (exp
->data
.dvar
->arg
) {
582 if (psi_decl_var_validate(data
, exp
->data
.dvar
, scope
)) {
585 data
->error(data
, exp
->token
, PSI_WARNING
,
586 "Unknown variable '%s' in numeric expression",
587 exp
->data
.dvar
->name
);
591 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.numb
, strlen(exp
->data
.numb
))) {
597 if (scope
&& scope
->defs
&& zend_hash_str_exists(scope
->defs
, exp
->data
.numb
, strlen(exp
->data
.numb
))) {
598 if (!scope
->macro
|| strcmp(scope
->macro
->token
->text
, exp
->data
.numb
)) {
601 /* #define foo foo */
603 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
604 struct psi_validate_scope enum_scope
= *scope
;
605 enum_scope
.current_enum
= enm
;
606 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
613 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, NULL
, scope
)) {
614 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
616 exp
->type
= PSI_T_UINT64
;
617 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
618 psi_decl_type_free(&dtyp
);
621 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
623 data
->error(data
, exp
->token
, PSI_WARNING
,
624 "Cannot compute sizeof(%s) (%u)", dtyp
->name
, dtyp
->type
);
626 exp
->type
= PSI_T_UINT8
;
627 exp
->data
.ival
.u8
= 0;
628 psi_decl_type_free(&dtyp
);
633 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
634 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
635 free(exp
->data
.numb
);
636 exp
->type
= PSI_T_CONST
;
637 exp
->data
.cnst
= cnst
;
641 data
->error(data
, exp
->token
, PSI_WARNING
,
642 "Unknown constant '%s' in numeric expression",
647 return psi_number_validate_number(data
, exp
);
649 case PSI_T_QUOTED_CHAR
:
650 return psi_number_validate_char(data
, exp
);
659 #include "Zend/zend_constants.h"
661 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
662 impl_val
*res
, struct psi_call_frame
*frame
)
664 switch (exp
->data
.cnst
->type
->type
) {
666 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
667 strlen(exp
->data
.cnst
->name
))->value
.lval
;
668 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
671 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
672 strlen(exp
->data
.cnst
->name
))->value
.dval
;
673 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
676 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
682 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
683 impl_val
*res
, struct psi_call_frame
*frame
)
686 struct psi_call_frame_symbol
*sym
;
687 struct psi_decl_type
*real
;
688 struct psi_decl_var
*var
;
691 var
= exp
->data
.dvar
;
692 real
= psi_decl_type_get_real(var
->arg
->type
);
693 size
= psi_decl_arg_get_size(var
->arg
);
694 sym
= psi_call_frame_fetch_symbol(frame
, var
);
695 ref
= deref_impl_val(sym
->ptr
, var
);
697 memcpy(res
, ref
, size
);
699 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
700 switch (SIZEOF_VOID_P
) {
712 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
713 impl_val
*res
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
716 struct psi_cpp_macro_decl
*macro
;
718 macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
719 if (macro
&& macro
->exp
&& macro
->exp
!= rec_guard
) {
720 return psi_num_exp_exec(macro
->exp
, res
, NULL
, defs
);
727 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
,
728 struct psi_call_frame
*frame
, HashTable
*defs
, struct psi_num_exp
*rec_guard
)
732 *res
= exp
->data
.ival
;
733 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
736 *res
= exp
->data
.ival
;
737 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
740 *res
= exp
->data
.ival
;
741 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
744 *res
= exp
->data
.ival
;
745 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
748 *res
= exp
->data
.ival
;
749 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
752 *res
= exp
->data
.ival
;
753 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
756 *res
= exp
->data
.ival
;
757 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
760 *res
= exp
->data
.ival
;
761 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
765 *res
= exp
->data
.ival
;
766 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIfval
, res
->fval
);
770 *res
= exp
->data
.ival
;
771 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
775 case PSI_T_LONG_DOUBLE
:
776 *res
= exp
->data
.ival
;
777 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
782 res
->i64
= exp
->data
.enm
->val
;
783 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
787 res
->i64
= atol(exp
->data
.numb
);
791 return psi_number_eval_constant(exp
, res
, frame
);
794 return psi_number_eval_decl_var(exp
, res
, frame
);
797 return psi_number_eval_define(exp
, res
, defs
, rec_guard
);