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 psi_cpp_macro_call_dump(fd
, exp
->data
.call
);
231 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
234 dprintf(fd
, "%s", exp
->data
.enm
->name
);
237 psi_decl_var_dump(fd
, exp
->data
.dvar
);
244 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
245 struct psi_decl_enum
*enm
)
248 struct psi_decl_enum_item
*itm
;
250 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
251 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
252 psi_decl_var_free(&exp
->data
.dvar
);
253 exp
->type
= PSI_T_ENUM
;
255 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
262 static inline token_t
validate_char(char *numb
, impl_val
*res
, unsigned *lvl
)
265 token_t typ
= PSI_T_INT8
;
276 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
277 res
->i8
= strtol(&numb
[1], &endptr
, 8);
281 res
->i8
= strtol(&numb
[2], &endptr
, 16);
315 impl_val tmp_val
= {0};
316 token_t tmp_typ
= validate_char(endptr
, &tmp_val
, lvl
);
322 res
->i32
= res
->i8
<< (8 * *lvl
);
323 typ
= psi_calc_add(PSI_T_INT32
, res
, tmp_typ
, &tmp_val
, res
);
330 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
334 token_t typ
= validate_char(exp
->data
.numb
, &val
, &lvl
);
340 free(exp
->data
.numb
);
342 exp
->data
.ival
= val
;
346 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
351 switch (exp
->flags
& 0x0f) {
353 switch (exp
->flags
& 0x0f00) {
356 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
357 free(exp
->data
.numb
);
358 exp
->type
= PSI_T_INT64
;
359 exp
->data
.ival
.i64
= tmp
.i64
;
362 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
363 free(exp
->data
.numb
);
364 exp
->type
= PSI_T_INT64
;
365 exp
->data
.ival
.i64
= tmp
.i64
;
369 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
370 free(exp
->data
.numb
);
371 exp
->type
= PSI_T_UINT64
;
372 exp
->data
.ival
.u64
= tmp
.u64
;
375 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
376 free(exp
->data
.numb
);
377 exp
->type
= PSI_T_UINT64
;
378 exp
->data
.ival
.u64
= tmp
.u64
;
384 switch (exp
->flags
& 0x0ff00) {
387 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
388 free(exp
->data
.numb
);
389 exp
->type
= PSI_T_FLOAT
;
390 exp
->data
.ival
.fval
= tmp
.fval
;
395 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
396 free(exp
->data
.numb
);
397 exp
->type
= PSI_T_LONG_DOUBLE
;
398 exp
->data
.ival
.ldval
= tmp
.ldval
;
403 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
404 free(exp
->data
.numb
);
405 exp
->type
= PSI_T_DOUBLE
;
406 exp
->data
.ival
.dval
= tmp
.dval
;
415 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
417 free(exp
->data
.numb
);
418 exp
->type
= PSI_T_INT64
;
419 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
423 free(exp
->data
.numb
);
424 exp
->type
= PSI_T_DOUBLE
;
425 exp
->data
.ival
.dval
= tmp
.dval
;
429 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
433 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
434 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
435 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
438 struct psi_const
*cnst
;
439 struct psi_decl_enum
*enm
;
453 case PSI_T_LONG_DOUBLE
:
461 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
464 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
465 if (psi_number_validate_enum(data
, exp
, enm
)) {
469 if (exp
->data
.dvar
->arg
) {
472 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
? impl
->decl
: NULL
,
473 current_let
, current_set
)) {
476 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
, cb_decl
, NULL
, NULL
)) {
479 data
->error(data
, exp
->token
, PSI_WARNING
,
480 "Unknown variable '%s' in numeric expression",
481 exp
->data
.dvar
->name
);
485 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
486 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
487 free(exp
->data
.numb
);
488 exp
->type
= PSI_T_CONST
;
489 exp
->data
.cnst
= cnst
;
493 data
->error(data
, exp
->token
, PSI_WARNING
,
494 "Unknown constant '%s' in numeric expression",
499 return psi_number_validate_number(data
, exp
);
501 case PSI_T_QUOTED_CHAR
:
502 return psi_number_validate_char(data
, exp
);
511 #include "Zend/zend_constants.h"
513 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
514 impl_val
*res
, struct psi_call_frame
*frame
)
516 switch (exp
->data
.cnst
->type
->type
) {
518 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
519 strlen(exp
->data
.cnst
->name
))->value
.lval
;
520 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
523 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
524 strlen(exp
->data
.cnst
->name
))->value
.dval
;
525 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
528 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%d)", exp
->data
.cnst
->type
->type
);
534 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
535 impl_val
*res
, struct psi_call_frame
*frame
)
538 struct psi_call_frame_symbol
*sym
;
539 struct psi_decl_type
*real
;
542 real
= psi_decl_type_get_real(exp
->data
.dvar
->arg
->type
);
543 size
= psi_decl_arg_get_size(exp
->data
.dvar
->arg
);
544 sym
= psi_call_frame_fetch_symbol(frame
, exp
->data
.dvar
);
545 ref
= deref_impl_val(sym
->ptr
, exp
->data
.dvar
);
547 memcpy(res
, ref
, size
);
552 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
553 impl_val
*res
, HashTable
*defs
)
555 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
563 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
, HashTable
*defs
)
567 *res
= exp
->data
.ival
;
568 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
571 *res
= exp
->data
.ival
;
572 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
575 *res
= exp
->data
.ival
;
576 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
579 *res
= exp
->data
.ival
;
580 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
583 *res
= exp
->data
.ival
;
584 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
587 *res
= exp
->data
.ival
;
588 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
591 *res
= exp
->data
.ival
;
592 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
595 *res
= exp
->data
.ival
;
596 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
600 *res
= exp
->data
.ival
;
601 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
605 case PSI_T_LONG_DOUBLE
:
606 *res
= exp
->data
.ival
;
607 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIldval
, res
->ldval
);
612 res
->i64
= exp
->data
.enm
->val
;
613 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
617 return psi_number_eval_constant(exp
, res
, frame
);
620 return psi_number_eval_decl_var(exp
, res
, frame
);
623 return psi_number_eval_define(exp
, res
, defs
);