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
);
96 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
98 struct psi_number
*num
= calloc(1, sizeof(*num
));
103 num
->token
= psi_token_copy(num
->token
);
116 case PSI_T_LONG_DOUBLE
:
124 case PSI_T_QUOTED_CHAR
:
125 num
->data
.numb
= strdup(num
->data
.numb
);
128 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
131 num
->data
.call
= psi_cpp_macro_call_copy(num
->data
.call
);
139 void psi_number_free(struct psi_number
**exp_ptr
)
142 struct psi_number
*exp
= *exp_ptr
;
159 case PSI_T_LONG_DOUBLE
:
165 psi_cpp_macro_call_free(&exp
->data
.call
);
170 case PSI_T_QUOTED_CHAR
:
171 free(exp
->data
.numb
);
174 psi_decl_var_free(&exp
->data
.dvar
);
183 void psi_number_dump(int fd
, struct psi_number
*exp
)
187 dprintf(fd
, "%" PRId8
, exp
->data
.ival
.i8
);
190 dprintf(fd
, "%" PRIu8
, exp
->data
.ival
.u8
);
193 dprintf(fd
, "%" PRId16
, exp
->data
.ival
.i16
);
196 dprintf(fd
, "%" PRIu16
, exp
->data
.ival
.u16
);
199 dprintf(fd
, "%" PRId32
, exp
->data
.ival
.i32
);
202 dprintf(fd
, "%" PRIu32
, exp
->data
.ival
.u32
);
205 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
208 dprintf(fd
, "%" PRIu64
, exp
->data
.ival
.u64
);
211 dprintf(fd
, "%" PRIfval
, exp
->data
.ival
.dval
);
214 dprintf(fd
, "%" PRIdval
, exp
->data
.ival
.dval
);
217 case PSI_T_LONG_DOUBLE
:
218 dprintf(fd
, "%" PRIldval
, exp
->data
.ival
.ldval
);
224 case PSI_T_QUOTED_CHAR
:
225 dprintf(fd
, "%s", exp
->data
.numb
);
228 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
231 dprintf(fd
, "%s", exp
->data
.enm
->name
);
234 psi_decl_var_dump(fd
, exp
->data
.dvar
);
241 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
242 struct psi_decl_enum
*enm
)
245 struct psi_decl_enum_item
*itm
;
247 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
248 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
249 psi_decl_var_free(&exp
->data
.dvar
);
250 exp
->type
= PSI_T_ENUM
;
252 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
259 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
262 token_t typ
= PSI_T_INT8
;
273 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
274 res
->i8
= strtol(&numb
[1], &endptr
, 8);
278 res
->i8
= strtol(&numb
[2], &endptr
, 16);
312 impl_val tmp_val
= {0};
313 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
319 res
->i32
= res
->i8
<< (8 * *lvl
);
320 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
327 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
331 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
337 free(exp
->data
.numb
);
339 exp
->data
.ival
= val
;
343 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
348 switch (exp
->flags
& 0x0f) {
350 switch (exp
->flags
& 0x0f00) {
353 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
354 free(exp
->data
.numb
);
355 exp
->type
= PSI_T_INT64
;
356 exp
->data
.ival
.i64
= tmp
.i64
;
359 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
360 free(exp
->data
.numb
);
361 exp
->type
= PSI_T_INT64
;
362 exp
->data
.ival
.i64
= tmp
.i64
;
366 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
367 free(exp
->data
.numb
);
368 exp
->type
= PSI_T_UINT64
;
369 exp
->data
.ival
.u64
= tmp
.u64
;
372 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
373 free(exp
->data
.numb
);
374 exp
->type
= PSI_T_UINT64
;
375 exp
->data
.ival
.u64
= tmp
.u64
;
381 switch (exp
->flags
& 0x0ff00) {
384 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
385 free(exp
->data
.numb
);
386 exp
->type
= PSI_T_FLOAT
;
387 exp
->data
.ival
.fval
= tmp
.fval
;
392 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
393 free(exp
->data
.numb
);
394 exp
->type
= PSI_T_LONG_DOUBLE
;
395 exp
->data
.ival
.ldval
= tmp
.ldval
;
400 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
401 free(exp
->data
.numb
);
402 exp
->type
= PSI_T_DOUBLE
;
403 exp
->data
.ival
.dval
= tmp
.dval
;
412 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
414 free(exp
->data
.numb
);
415 exp
->type
= PSI_T_INT64
;
416 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
420 free(exp
->data
.numb
);
421 exp
->type
= PSI_T_DOUBLE
;
422 exp
->data
.ival
.dval
= tmp
.dval
;
426 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
430 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
431 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
432 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
435 struct psi_const
*cnst
;
436 struct psi_decl_enum
*enm
;
450 case PSI_T_LONG_DOUBLE
:
458 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
461 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
462 if (psi_number_validate_enum(data
, exp
, enm
)) {
466 if (exp
->data
.dvar
->arg
) {
469 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
? impl
->decl
: NULL
,
470 current_let
, current_set
)) {
473 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
, cb_decl
, NULL
, NULL
)) {
476 data
->error(data
, exp
->token
, PSI_WARNING
,
477 "Unknown variable '%s' in numeric expression",
478 exp
->data
.dvar
->name
);
482 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
483 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
484 free(exp
->data
.numb
);
485 exp
->type
= PSI_T_CONST
;
486 exp
->data
.cnst
= cnst
;
490 data
->error(data
, exp
->token
, PSI_WARNING
,
491 "Unknown constant '%s' in numeric expression",
496 return psi_number_validate_number(data
, exp
);
498 case PSI_T_QUOTED_CHAR
:
499 return psi_number_validate_char(data
, exp
);
508 #include "Zend/zend_constants.h"
510 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
511 impl_val
*res
, struct psi_call_frame
*frame
)
513 switch (exp
->data
.cnst
->type
->type
) {
515 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
516 strlen(exp
->data
.cnst
->name
))->value
.lval
;
517 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
520 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
521 strlen(exp
->data
.cnst
->name
))->value
.dval
;
522 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
525 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%d)", exp
->data
.cnst
->type
->type
);
531 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
532 impl_val
*res
, struct psi_call_frame
*frame
)
535 struct psi_call_frame_symbol
*sym
;
536 struct psi_decl_type
*real
;
539 real
= psi_decl_type_get_real(exp
->data
.dvar
->arg
->type
);
540 size
= psi_decl_arg_get_size(exp
->data
.dvar
->arg
);
541 sym
= psi_call_frame_fetch_symbol(frame
, exp
->data
.dvar
);
542 ref
= deref_impl_val(sym
->ptr
, exp
->data
.dvar
);
544 memcpy(res
, ref
, size
);
549 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
550 impl_val
*res
, HashTable
*defs
)
552 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
560 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
, HashTable
*defs
)
564 *res
= exp
->data
.ival
;
565 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
568 *res
= exp
->data
.ival
;
569 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
572 *res
= exp
->data
.ival
;
573 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
576 *res
= exp
->data
.ival
;
577 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
580 *res
= exp
->data
.ival
;
581 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
584 *res
= exp
->data
.ival
;
585 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
588 *res
= exp
->data
.ival
;
589 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
592 *res
= exp
->data
.ival
;
593 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
597 *res
= exp
->data
.ival
;
598 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
602 case PSI_T_LONG_DOUBLE
:
603 *res
= exp
->data
.ival
;
604 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
609 res
->i64
= exp
->data
.enm
->val
;
610 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
614 return psi_number_eval_constant(exp
, res
, frame
);
617 return psi_number_eval_decl_var(exp
, res
, frame
);
620 return psi_number_eval_define(exp
, res
, defs
);