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
= pecalloc(1, sizeof(*exp
), 1);
45 switch (exp
->type
= t
) {
47 exp
->data
.ival
.i8
= *(int8_t *) num
;
51 exp
->data
.ival
.u8
= *(uint8_t *) num
;
54 exp
->data
.ival
.i16
= *(int16_t *) num
;
57 exp
->data
.ival
.u16
= *(uint16_t *) num
;
60 exp
->data
.ival
.i32
= *(int32_t *) num
;
63 exp
->data
.ival
.u32
= *(uint32_t *) num
;
66 exp
->data
.ival
.i64
= *(int64_t *) num
;
69 exp
->data
.ival
.u64
= *(uint64_t *) num
;
72 exp
->data
.ival
.fval
= *(float *) num
;
75 exp
->data
.ival
.dval
= *(double *) num
;
78 case PSI_T_LONG_DOUBLE
:
79 exp
->data
.ival
.ldval
= *(long double *) num
;
84 case PSI_T_QUOTED_CHAR
:
88 case PSI_T_CPP_HEADER
:
89 exp
->data
.numb
= zend_string_copy(num
);
107 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
109 struct psi_number
*num
= pecalloc(1, sizeof(*num
), 1);
114 num
->token
= psi_token_copy(num
->token
);
129 case PSI_T_LONG_DOUBLE
:
138 case PSI_T_QUOTED_CHAR
:
139 case PSI_T_CPP_HEADER
:
140 num
->data
.numb
= zend_string_copy(num
->data
.numb
);
143 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
146 num
->data
.call
= psi_cpp_macro_call_copy(num
->data
.call
);
149 num
->data
.dtyp
= psi_decl_type_copy(num
->data
.dtyp
);
157 void psi_number_free(struct psi_number
**exp_ptr
)
160 struct psi_number
*exp
= *exp_ptr
;
163 psi_token_free(&exp
->token
);
177 case PSI_T_LONG_DOUBLE
:
184 psi_cpp_macro_call_free(&exp
->data
.call
);
189 case PSI_T_QUOTED_CHAR
:
190 case PSI_T_CPP_HEADER
:
191 zend_string_release(exp
->data
.numb
);
194 psi_decl_var_free(&exp
->data
.dvar
);
197 psi_decl_type_free(&exp
->data
.dtyp
);
206 struct psi_plist
*psi_number_tokens(struct psi_number
*exp
,
207 struct psi_plist
*list
)
209 struct psi_token
*ntoken
;
213 list
= psi_plist_init((psi_plist_dtor
) psi_token_free
);
219 ntoken
= psi_token_copy(exp
->data
.dvar
->token
);
221 if (exp
->data
.dvar
->pointer_level
> 1 || !exp
->data
.dvar
->array_size
) {
222 struct psi_token
*temp
= ntoken
;
223 unsigned pl
= exp
->data
.dvar
->pointer_level
- !!exp
->data
.dvar
->array_size
;
226 ntoken
= psi_token_init(PSI_T_POINTER
, "*", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
227 list
= psi_plist_add(list
, &ntoken
);
232 list
= psi_plist_add(list
, &ntoken
);
234 if (exp
->data
.dvar
->array_size
) {
235 char buf
[0x20], *ptr
;
237 ntoken
= psi_token_init(PSI_T_LBRACKET
, "[", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
238 list
= psi_plist_add(list
, &ntoken
);
239 ptr
= zend_print_ulong_to_buf(&buf
[sizeof(buf
) - 1], exp
->data
.dvar
->array_size
);
241 ntoken
= psi_token_init(PSI_T_NUMBER
, ptr
, strlen(ptr
), ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
242 list
= psi_plist_add(list
, &ntoken
);
248 ntoken
= psi_token_copy(exp
->token
);
249 list
= psi_plist_add(list
, &ntoken
);
250 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
251 list
= psi_plist_add(list
, &ntoken
);
252 ntoken
= psi_token_copy(exp
->data
.dtyp
->token
);
253 list
= psi_plist_add(list
, &ntoken
);
254 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
255 list
= psi_plist_add(list
, &ntoken
);
259 ntoken
= psi_token_copy(exp
->token
);
260 list
= psi_plist_add(list
, &ntoken
);
261 ntoken
= psi_token_init(PSI_T_LPAREN
, "(", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
262 list
= psi_plist_add(list
, &ntoken
);
263 for (i
= 0; i
< psi_plist_count(exp
->data
.call
->args
); ++i
) {
264 struct psi_num_exp
*tmp_exp
;
267 ntoken
= psi_token_init(PSI_T_COMMA
, ",", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
268 list
= psi_plist_add(list
, &ntoken
);
270 if (psi_plist_get(exp
->data
.call
->args
, i
, &tmp_exp
)) {
271 struct psi_plist
*tmp
= psi_num_exp_tokens(tmp_exp
, NULL
);
272 list
= psi_plist_add_r(list
, psi_plist_count(tmp
), psi_plist_eles(tmp
));
273 psi_plist_top(list
, &ntoken
);
277 ntoken
= psi_token_init(PSI_T_RPAREN
, ")", 1, ntoken
->col
+ntoken
->text
->len
, ntoken
->line
, ntoken
->file
);
278 list
= psi_plist_add(list
, &ntoken
);
282 ntoken
= psi_token_init(PSI_T_DEFINED
, "defined", sizeof("defined")-1, exp
->token
->col
, exp
->token
->line
, exp
->token
->file
);
283 list
= psi_plist_add(list
, &ntoken
);
287 ntoken
= psi_token_copy(exp
->token
);
288 list
= psi_plist_add(list
, &ntoken
);
295 void psi_number_dump(int fd
, struct psi_number
*exp
)
299 CASE_IMPLVAL_NUM_PRINTF(dprintf
, fd
, exp
->data
.ival
)
306 case PSI_T_QUOTED_CHAR
:
307 case PSI_T_CPP_HEADER
:
308 dprintf(fd
, "%s", exp
->data
.numb
->val
);
311 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
314 dprintf(fd
, "%s", exp
->data
.cnst
->name
->val
);
317 dprintf(fd
, "%s", exp
->data
.enm
->name
->val
);
320 psi_decl_var_dump(fd
, exp
->data
.dvar
);
323 dprintf(fd
, "sizeof(");
324 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
332 static inline bool psi_number_validate_enum(struct psi_data
*data
,
333 struct psi_number
*exp
, struct psi_validate_scope
*scope
)
335 if (scope
&& scope
->current_enum
) {
337 struct psi_decl_enum_item
*itm
;
338 struct psi_decl_enum
*enm
;
340 enm
= scope
->current_enum
;
344 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
345 if (zend_string_equals(itm
->name
, exp
->data
.dvar
->name
)) {
346 psi_decl_var_free(&exp
->data
.dvar
);
347 exp
->type
= PSI_T_ENUM
;
349 return psi_number_validate(data
, exp
, scope
);
355 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
356 if (zend_string_equals(itm
->name
, exp
->data
.numb
)) {
357 zend_string_release(exp
->data
.numb
);
358 exp
->type
= PSI_T_ENUM
;
360 return psi_number_validate(data
, exp
, scope
);
372 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
375 token_t typ
= PSI_T_INT8
;
386 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
387 res
->i8
= strtol(&numb
[1], &endptr
, 8);
391 res
->i8
= strtol(&numb
[2], &endptr
, 16);
425 impl_val tmp_val
= {0};
426 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
432 res
->i32
= res
->i8
<< (8 * *lvl
);
433 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
440 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
444 token_t typ
= validate_char(exp
->data
.numb
->val
, &val
, &lvl
);
450 zend_string_release(exp
->data
.numb
);
452 exp
->data
.ival
= val
;
456 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
461 switch (exp
->flags
& 0x0f) {
463 switch (exp
->flags
& 0x0f00) {
466 tmp
.i64
= strtol(exp
->data
.numb
->val
, NULL
, 0);
467 zend_string_release(exp
->data
.numb
);
468 exp
->type
= PSI_T_INT64
;
469 exp
->data
.ival
.i64
= tmp
.i64
;
472 tmp
.i64
= strtoll(exp
->data
.numb
->val
, NULL
, 0);
473 zend_string_release(exp
->data
.numb
);
474 exp
->type
= PSI_T_INT64
;
475 exp
->data
.ival
.i64
= tmp
.i64
;
479 tmp
.u64
= strtoul(exp
->data
.numb
->val
, NULL
, 0);
480 zend_string_release(exp
->data
.numb
);
481 exp
->type
= PSI_T_UINT64
;
482 exp
->data
.ival
.u64
= tmp
.u64
;
485 tmp
.u64
= strtoull(exp
->data
.numb
->val
, NULL
, 0);
486 zend_string_release(exp
->data
.numb
);
487 exp
->type
= PSI_T_UINT64
;
488 exp
->data
.ival
.u64
= tmp
.u64
;
494 switch (exp
->flags
& 0x0ff00) {
497 tmp
.fval
= strtof(exp
->data
.numb
->val
, NULL
);
498 zend_string_release(exp
->data
.numb
);
499 exp
->type
= PSI_T_FLOAT
;
500 exp
->data
.ival
.fval
= tmp
.fval
;
505 tmp
.ldval
= strtold(exp
->data
.numb
->val
, NULL
);
506 zend_string_release(exp
->data
.numb
);
507 exp
->type
= PSI_T_LONG_DOUBLE
;
508 exp
->data
.ival
.ldval
= tmp
.ldval
;
513 tmp
.dval
= strtod(exp
->data
.numb
->val
, NULL
);
514 zend_string_release(exp
->data
.numb
);
515 exp
->type
= PSI_T_DOUBLE
;
516 exp
->data
.ival
.dval
= tmp
.dval
;
525 int type
= is_numeric_string(exp
->data
.numb
->val
, exp
->data
.numb
->len
, (zend_long
*) &tmp
, (double *)&tmp
, 0);
532 zend_string_release(exp
->data
.numb
);
533 exp
->type
= PSI_T_INT64
;
534 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
538 zend_string_release(exp
->data
.numb
);
539 exp
->type
= PSI_T_DOUBLE
;
540 exp
->data
.ival
.dval
= tmp
.dval
;
547 stop
= exp
->data
.numb
->val
+ exp
->data
.numb
->len
;
548 lval
= strtol(exp
->data
.numb
->val
, &stop
, 0);
551 assert(stop
== exp
->data
.numb
->val
+ exp
->data
.numb
->len
);
557 if (errno
== ERANGE
) {
560 stop
= exp
->data
.numb
->val
+ exp
->data
.numb
->len
;
561 ulval
= strtoul(exp
->data
.numb
->val
, &stop
, 0);
564 assert(stop
== exp
->data
.numb
->val
+ exp
->data
.numb
->len
);
568 zend_string_release(exp
->data
.numb
);
569 exp
->type
= PSI_T_UINT64
;
570 exp
->data
.ival
.u64
= ulval
;
576 zend_string_release(exp
->data
.numb
);
577 exp
->type
= PSI_T_INT64
;
578 exp
->data
.ival
.i64
= lval
;
582 data
->error(data
, exp
->token
, PSI_WARNING
, "Not a numeric string: '%s'", exp
->data
.numb
->val
);
585 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
589 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
590 struct psi_validate_scope
*scope
)
593 struct psi_const
*cnst
;
594 struct psi_decl_enum
*enm
;
598 exp
->type
= PSI_T_UINT8
;
612 case PSI_T_LONG_DOUBLE
:
619 if (scope
&& scope
->cpp
&& zend_hash_exists(&scope
->cpp
->defs
, exp
->data
.dvar
->name
)) {
620 exp
->type
= PSI_T_DEFINE
;
623 if (scope
&& scope
->current_enum
&& psi_number_validate_enum(data
, exp
, scope
)) {
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
)) {
633 if (exp
->data
.dvar
->arg
) {
636 if (psi_decl_var_validate(data
, exp
->data
.dvar
, scope
)) {
639 data
->error(data
, exp
->token
, PSI_WARNING
,
640 "Unknown variable '%s' in numeric expression",
641 exp
->data
.dvar
->name
->val
);
645 if (scope
&& scope
->cpp
&& zend_hash_exists(&scope
->cpp
->defs
, exp
->data
.call
->name
)) {
647 struct psi_cpp_macro_call
*call
= exp
->data
.call
;
649 for (i
= 0, argc
= psi_plist_count(call
->args
); i
< argc
; ++i
) {
650 struct psi_num_exp
*arg
;
652 if (!psi_plist_get(call
->args
, i
, &arg
)) {
655 if (!psi_num_exp_validate(data
, arg
, scope
)) {
661 if (psi_builtin_exists(exp
->data
.call
->name
)) {
662 exp
->data
.call
->builtin
= psi_builtin_get(exp
->data
.call
->name
);
668 if (scope
&& scope
->cpp
&& zend_hash_exists(&scope
->cpp
->defs
, exp
->data
.numb
)) {
670 if (!scope
->macro
|| !zend_string_equals(scope
->macro
->token
->text
, exp
->data
.numb
)) {
673 /* #define foo foo */
675 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
676 struct psi_validate_scope enum_scope
= *scope
;
677 enum_scope
.current_enum
= enm
;
678 if (psi_number_validate_enum(data
, exp
, &enum_scope
)) {
685 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, NULL
, scope
)) {
686 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
688 exp
->type
= PSI_T_UINT64
;
689 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
690 psi_decl_type_free(&dtyp
);
693 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
695 data
->error(data
, exp
->token
, PSI_WARNING
,
696 "Cannot compute sizeof(%s) (%u)", dtyp
->name
->val
, dtyp
->type
);
698 exp
->type
= PSI_T_UINT8
;
699 exp
->data
.ival
.u8
= 0;
700 psi_decl_type_free(&dtyp
);
708 if (exp
->data
.numb
->val
[0] == '\\') {
709 zc
= zend_get_constant_str(&exp
->data
.numb
->val
[1], exp
->data
.numb
->len
- 1);
711 zc
= zend_get_constant(exp
->data
.numb
);
715 switch (Z_TYPE_P(zc
)) {
717 zend_string_release(exp
->data
.numb
);
718 exp
->type
= PSI_T_INT64
;
719 exp
->data
.ival
.i64
= Z_LVAL_P(zc
);
723 zend_string_release(exp
->data
.numb
);
724 exp
->type
= PSI_T_DOUBLE
;
725 exp
->data
.ival
.dval
= Z_DVAL_P(zc
);
733 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
734 if (zend_string_equals(cnst
->name
, exp
->data
.numb
)) {
735 zend_string_release(exp
->data
.numb
);
736 exp
->type
= PSI_T_CONST
;
737 exp
->data
.cnst
= cnst
;
741 data
->error(data
, exp
->token
, PSI_WARNING
,
742 "Unknown constant '%s' in numeric expression",
743 exp
->data
.numb
->val
);
747 return psi_number_validate_number(data
, exp
);
749 case PSI_T_QUOTED_CHAR
:
750 return psi_number_validate_char(data
, exp
);
752 case PSI_T_CPP_HEADER
:
762 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
763 impl_val
*res
, struct psi_call_frame
*frame
)
765 token_t typ
= exp
->data
.cnst
->type
? exp
->data
.cnst
->type
->type
: PSI_T_MIXED
;
769 res
->i64
= zend_get_constant(exp
->data
.cnst
->name
)->value
.lval
;
770 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
773 res
->dval
= zend_get_constant(exp
->data
.cnst
->name
)->value
.dval
;
774 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
777 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%u)", exp
->data
.cnst
->type
->type
);
783 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
784 impl_val
*res
, struct psi_call_frame
*frame
)
787 struct psi_call_frame_symbol
*sym
;
788 struct psi_decl_type
*real
;
789 struct psi_decl_var
*var
;
792 var
= exp
->data
.dvar
;
793 real
= psi_decl_type_get_real(var
->arg
->type
);
794 size
= psi_decl_arg_get_size(var
->arg
);
795 sym
= psi_call_frame_fetch_symbol(frame
, var
);
796 ref
= deref_impl_val(sym
->ptr
, var
);
798 memcpy(res
, ref
, size
);
800 if (var
->arg
->var
->pointer_level
> var
->pointer_level
) {
801 switch (SIZEOF_VOID_P
) {
813 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
814 impl_val
*res
, struct psi_cpp
*cpp
, struct psi_num_exp
*rec_guard
)
817 struct psi_cpp_macro_decl
*macro
;
819 macro
= zend_hash_find_ptr(&cpp
->defs
, exp
->data
.numb
);
820 if (macro
&& macro
->exp
&& macro
->exp
!= rec_guard
) {
821 return psi_num_exp_exec(macro
->exp
, res
, NULL
, cpp
);
829 static inline token_t
psi_number_eval_function(struct psi_number
*exp
,
830 impl_val
*res
, struct psi_cpp
*cpp
, struct psi_num_exp
*rec_guard
)
833 PSI_DEBUG_PRINT(cpp
->parser
, "psi_number_eval(PSI_T_FUNCTION): %s\n", exp
->token
->text
->val
);
839 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
,
840 struct psi_call_frame
*frame
, struct psi_cpp
*cpp
, struct psi_num_exp
*rec_guard
)
844 *res
= exp
->data
.ival
;
845 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
849 *res
= exp
->data
.ival
;
850 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
853 *res
= exp
->data
.ival
;
854 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
857 *res
= exp
->data
.ival
;
858 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
861 *res
= exp
->data
.ival
;
862 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
865 *res
= exp
->data
.ival
;
866 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
869 *res
= exp
->data
.ival
;
870 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
873 *res
= exp
->data
.ival
;
874 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
878 *res
= exp
->data
.ival
;
879 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIfval
, res
->fval
);
883 *res
= exp
->data
.ival
;
884 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
888 case PSI_T_LONG_DOUBLE
:
889 *res
= exp
->data
.ival
;
890 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
895 res
->i64
= exp
->data
.enm
->val
;
896 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
900 res
->i64
= atol(exp
->data
.numb
->val
);
904 return psi_number_eval_constant(exp
, res
, frame
);
907 return psi_number_eval_decl_var(exp
, res
, frame
);
910 return psi_number_eval_define(exp
, res
, cpp
, rec_guard
);
913 return psi_number_eval_function(exp
, res
, cpp
, rec_guard
);
915 case PSI_T_CPP_HEADER
: