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
.dval
= *(float *) num
;
67 exp
->type
= PSI_T_DOUBLE
;
70 exp
->data
.ival
.dval
= *(double *) num
;
73 case PSI_T_LONG_DOUBLE
:
74 exp
->data
.ival
.ldval
= *(long double *) num
;
77 case PSI_T_QUOTED_CHAR
:
81 exp
->data
.numb
= strdup(num
);
99 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
101 struct psi_number
*num
= calloc(1, sizeof(*num
));
106 num
->token
= psi_token_copy(num
->token
);
119 case PSI_T_LONG_DOUBLE
:
127 case PSI_T_QUOTED_CHAR
:
128 num
->data
.numb
= strdup(num
->data
.numb
);
131 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
134 num
->data
.call
= psi_cpp_macro_call_copy(num
->data
.call
);
137 num
->data
.dtyp
= psi_decl_type_copy(num
->data
.dtyp
);
145 void psi_number_free(struct psi_number
**exp_ptr
)
148 struct psi_number
*exp
= *exp_ptr
;
165 case PSI_T_LONG_DOUBLE
:
171 psi_cpp_macro_call_free(&exp
->data
.call
);
176 case PSI_T_QUOTED_CHAR
:
177 free(exp
->data
.numb
);
180 psi_decl_var_free(&exp
->data
.dvar
);
183 psi_decl_type_free(&exp
->data
.dtyp
);
192 void psi_number_dump(int fd
, struct psi_number
*exp
)
196 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
199 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
202 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
205 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
208 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
211 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
214 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
217 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
220 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
223 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
226 case PSI_T_LONG_DOUBLE
:
227 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
233 case PSI_T_QUOTED_CHAR
:
234 dprintf(fd
, "%s", exp
->data
.numb
);
237 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
240 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
243 dprintf(fd
, "%s", exp
->data
.enm
->name
);
246 psi_decl_var_dump(fd
, exp
->data
.dvar
);
249 psi_decl_type_dump(fd
, exp
->data
.dtyp
, 0);
256 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
257 struct psi_decl_enum
*enm
)
260 struct psi_decl_enum_item
*itm
;
262 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
263 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
264 psi_decl_var_free(&exp
->data
.dvar
);
265 exp
->type
= PSI_T_ENUM
;
267 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
274 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
277 token_t typ
= PSI_T_INT8
;
288 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
289 res
->i8
= strtol(&numb
[1], &endptr
, 8);
293 res
->i8
= strtol(&numb
[2], &endptr
, 16);
327 impl_val tmp_val
= {0};
328 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
334 res
->i32
= res
->i8
<< (8 * *lvl
);
335 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
342 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
346 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
352 free(exp
->data
.numb
);
354 exp
->data
.ival
= val
;
358 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
363 switch (exp
->flags
& 0x0f) {
365 switch (exp
->flags
& 0x0f00) {
368 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
369 free(exp
->data
.numb
);
370 exp
->type
= PSI_T_INT64
;
371 exp
->data
.ival
.i64
= tmp
.i64
;
374 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
375 free(exp
->data
.numb
);
376 exp
->type
= PSI_T_INT64
;
377 exp
->data
.ival
.i64
= tmp
.i64
;
381 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
382 free(exp
->data
.numb
);
383 exp
->type
= PSI_T_UINT64
;
384 exp
->data
.ival
.u64
= tmp
.u64
;
387 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
388 free(exp
->data
.numb
);
389 exp
->type
= PSI_T_UINT64
;
390 exp
->data
.ival
.u64
= tmp
.u64
;
396 switch (exp
->flags
& 0x0ff00) {
399 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
400 free(exp
->data
.numb
);
401 exp
->type
= PSI_T_FLOAT
;
402 exp
->data
.ival
.fval
= tmp
.fval
;
407 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
408 free(exp
->data
.numb
);
409 exp
->type
= PSI_T_LONG_DOUBLE
;
410 exp
->data
.ival
.ldval
= tmp
.ldval
;
415 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
416 free(exp
->data
.numb
);
417 exp
->type
= PSI_T_DOUBLE
;
418 exp
->data
.ival
.dval
= tmp
.dval
;
427 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
429 free(exp
->data
.numb
);
430 exp
->type
= PSI_T_INT64
;
431 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
435 free(exp
->data
.numb
);
436 exp
->type
= PSI_T_DOUBLE
;
437 exp
->data
.ival
.dval
= tmp
.dval
;
441 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
445 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
446 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
447 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
450 struct psi_const
*cnst
;
451 struct psi_decl_enum
*enm
;
465 case PSI_T_LONG_DOUBLE
:
473 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
476 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
477 if (psi_number_validate_enum(data
, exp
, enm
)) {
481 if (exp
->data
.dvar
->arg
) {
484 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
? impl
->decl
: NULL
,
485 current_let
, current_set
)) {
488 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
, cb_decl
, NULL
, NULL
)) {
491 data
->error(data
, exp
->token
, PSI_WARNING
,
492 "Unknown variable '%s' in numeric expression",
493 exp
->data
.dvar
->name
);
497 if (psi_decl_type_validate(data
, exp
->data
.dtyp
, 0, NULL
)) {
498 struct psi_decl_type
*dtyp
= exp
->data
.dtyp
;
500 exp
->type
= PSI_T_UINT64
;
501 exp
->data
.ival
.u64
= psi_decl_type_get_size(dtyp
, NULL
);
507 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
508 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
509 free(exp
->data
.numb
);
510 exp
->type
= PSI_T_CONST
;
511 exp
->data
.cnst
= cnst
;
515 data
->error(data
, exp
->token
, PSI_WARNING
,
516 "Unknown constant '%s' in numeric expression",
521 return psi_number_validate_number(data
, exp
);
523 case PSI_T_QUOTED_CHAR
:
524 return psi_number_validate_char(data
, exp
);
533 #include "Zend/zend_constants.h"
535 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
536 impl_val
*res
, struct psi_call_frame
*frame
)
538 switch (exp
->data
.cnst
->type
->type
) {
540 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
541 strlen(exp
->data
.cnst
->name
))->value
.lval
;
542 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
545 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
546 strlen(exp
->data
.cnst
->name
))->value
.dval
;
547 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
550 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%d)", exp
->data
.cnst
->type
->type
);
556 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
557 impl_val
*res
, struct psi_call_frame
*frame
)
560 struct psi_call_frame_symbol
*sym
;
561 struct psi_decl_type
*real
;
564 real
= psi_decl_type_get_real(exp
->data
.dvar
->arg
->type
);
565 size
= psi_decl_arg_get_size(exp
->data
.dvar
->arg
);
566 sym
= psi_call_frame_fetch_symbol(frame
, exp
->data
.dvar
);
567 ref
= deref_impl_val(sym
->ptr
, exp
->data
.dvar
);
569 memcpy(res
, ref
, size
);
574 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
575 impl_val
*res
, HashTable
*defs
)
577 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
585 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
, HashTable
*defs
)
589 *res
= exp
->data
.ival
;
590 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
593 *res
= exp
->data
.ival
;
594 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
597 *res
= exp
->data
.ival
;
598 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
601 *res
= exp
->data
.ival
;
602 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
605 *res
= exp
->data
.ival
;
606 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
609 *res
= exp
->data
.ival
;
610 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
613 *res
= exp
->data
.ival
;
614 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
617 *res
= exp
->data
.ival
;
618 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
622 *res
= exp
->data
.ival
;
623 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
627 case PSI_T_LONG_DOUBLE
:
628 *res
= exp
->data
.ival
;
629 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
634 res
->i64
= exp
->data
.enm
->val
;
635 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
639 res
->i64
= atol(exp
->data
.numb
);
643 return psi_number_eval_constant(exp
, res
, frame
);
646 return psi_number_eval_decl_var(exp
, res
, frame
);
649 return psi_number_eval_define(exp
, res
, defs
);