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
, "%F", exp
->data
.ival
.dval
);
214 case PSI_T_LONG_DOUBLE
:
215 dprintf(fd
, "%lF", exp
->data
.ival
.ldval
);
221 case PSI_T_QUOTED_CHAR
:
222 dprintf(fd
, "%s", exp
->data
.numb
);
225 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
228 dprintf(fd
, "%s", exp
->data
.enm
->name
);
231 psi_decl_var_dump(fd
, exp
->data
.dvar
);
238 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
239 struct psi_decl_enum
*enm
)
242 struct psi_decl_enum_item
*itm
;
244 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
245 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
246 psi_decl_var_free(&exp
->data
.dvar
);
247 exp
->type
= PSI_T_ENUM
;
249 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
256 static inline bool psi_number_validate_char(struct psi_data
*data
, struct psi_number
*exp
)
260 tmp
.i8
= exp
->data
.numb
[1 + (*exp
->data
.numb
== 'L')];
263 tmp
.i8
= exp
->data
.numb
[2 + (*exp
->data
.numb
== 'L')];
266 tmp
.i8
= strtol(&exp
->data
.numb
[3 + (*exp
->data
.numb
== 'L')], NULL
, 16);
267 free(exp
->data
.numb
);
268 exp
->type
= PSI_T_INT8
;
269 exp
->data
.ival
.i8
= tmp
.i8
;
272 free(exp
->data
.numb
);
273 exp
->type
= PSI_T_INT8
;
274 exp
->data
.ival
.i8
= '\'';
277 free(exp
->data
.numb
);
278 exp
->type
= PSI_T_INT8
;
279 exp
->data
.ival
.i8
= '\a';
282 free(exp
->data
.numb
);
283 exp
->type
= PSI_T_INT8
;
284 exp
->data
.ival
.i8
= '\b';
287 free(exp
->data
.numb
);
288 exp
->type
= PSI_T_INT8
;
289 exp
->data
.ival
.i8
= '\f';
292 free(exp
->data
.numb
);
293 exp
->type
= PSI_T_INT8
;
294 exp
->data
.ival
.i8
= '\n';
297 free(exp
->data
.numb
);
298 exp
->type
= PSI_T_INT8
;
299 exp
->data
.ival
.i8
= '\r';
302 free(exp
->data
.numb
);
303 exp
->type
= PSI_T_INT8
;
304 exp
->data
.ival
.i8
= '\t';
307 free(exp
->data
.numb
);
308 exp
->type
= PSI_T_INT8
;
309 exp
->data
.ival
.i8
= '\v';
311 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
312 tmp
.i8
= strtol(&exp
->data
.numb
[2 + (*exp
->data
.numb
== 'L')], NULL
, 8);
313 free(exp
->data
.numb
);
314 exp
->type
= PSI_T_INT8
;
315 exp
->data
.ival
.i8
= tmp
.i8
;
318 free(exp
->data
.numb
);
319 exp
->type
= PSI_T_INT8
;
320 exp
->data
.ival
.i8
= tmp
.i8
;
325 free(exp
->data
.numb
);
326 exp
->type
= PSI_T_INT8
;
327 exp
->data
.ival
.i8
= tmp
.i8
;
332 static inline bool psi_number_validate_number(struct psi_data
*data
, struct psi_number
*exp
)
337 switch (exp
->flags
& 0x0f) {
339 switch (exp
->flags
& 0x0f00) {
342 tmp
.i64
= strtol(exp
->data
.numb
, NULL
, 0);
343 free(exp
->data
.numb
);
344 exp
->type
= PSI_T_INT64
;
345 exp
->data
.ival
.i64
= tmp
.i64
;
348 tmp
.i64
= strtoll(exp
->data
.numb
, NULL
, 0);
349 free(exp
->data
.numb
);
350 exp
->type
= PSI_T_INT64
;
351 exp
->data
.ival
.i64
= tmp
.i64
;
355 tmp
.u64
= strtoul(exp
->data
.numb
, NULL
, 0);
356 free(exp
->data
.numb
);
357 exp
->type
= PSI_T_UINT64
;
358 exp
->data
.ival
.u64
= tmp
.u64
;
361 tmp
.u64
= strtoull(exp
->data
.numb
, NULL
, 0);
362 free(exp
->data
.numb
);
363 exp
->type
= PSI_T_UINT64
;
364 exp
->data
.ival
.u64
= tmp
.u64
;
370 switch (exp
->flags
& 0x0ff00) {
373 tmp
.fval
= strtof(exp
->data
.numb
, NULL
);
374 free(exp
->data
.numb
);
375 exp
->type
= PSI_T_FLOAT
;
376 exp
->data
.ival
.fval
= tmp
.fval
;
381 tmp
.ldval
= strtold(exp
->data
.numb
, NULL
);
382 free(exp
->data
.numb
);
383 exp
->type
= PSI_T_LONG_DOUBLE
;
384 exp
->data
.ival
.ldval
= tmp
.ldval
;
389 tmp
.dval
= strtod(exp
->data
.numb
, NULL
);
390 free(exp
->data
.numb
);
391 exp
->type
= PSI_T_DOUBLE
;
392 exp
->data
.ival
.dval
= tmp
.dval
;
401 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 1)) {
403 free(exp
->data
.numb
);
404 exp
->type
= PSI_T_INT64
;
405 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
409 free(exp
->data
.numb
);
410 exp
->type
= PSI_T_DOUBLE
;
411 exp
->data
.ival
.dval
= tmp
.dval
;
415 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
419 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
420 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
421 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
424 struct psi_const
*cnst
;
425 struct psi_decl_enum
*enm
;
439 case PSI_T_LONG_DOUBLE
:
447 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
450 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
451 if (psi_number_validate_enum(data
, exp
, enm
)) {
455 if (exp
->data
.dvar
->arg
) {
458 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
? impl
->decl
: NULL
,
459 current_let
, current_set
)) {
462 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
, cb_decl
, NULL
, NULL
)) {
465 data
->error(data
, exp
->token
, PSI_WARNING
,
466 "Unknown variable '%s' in numeric expression",
467 exp
->data
.dvar
->name
);
471 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
472 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
473 free(exp
->data
.numb
);
474 exp
->type
= PSI_T_CONST
;
475 exp
->data
.cnst
= cnst
;
479 data
->error(data
, exp
->token
, PSI_WARNING
,
480 "Unknown constant '%s' in numeric expression",
485 return psi_number_validate_number(data
, exp
);
487 case PSI_T_QUOTED_CHAR
:
488 return psi_number_validate_char(data
, exp
);
497 #include "Zend/zend_constants.h"
499 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
500 impl_val
*res
, struct psi_call_frame
*frame
)
502 switch (exp
->data
.cnst
->type
->type
) {
504 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
505 strlen(exp
->data
.cnst
->name
))->value
.lval
;
506 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
509 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
510 strlen(exp
->data
.cnst
->name
))->value
.dval
;
511 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
514 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%d)", exp
->data
.cnst
->type
->type
);
520 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
521 impl_val
*res
, struct psi_call_frame
*frame
)
524 struct psi_call_frame_symbol
*sym
;
525 struct psi_decl_type
*real
;
528 real
= psi_decl_type_get_real(exp
->data
.dvar
->arg
->type
);
529 size
= psi_decl_arg_get_size(exp
->data
.dvar
->arg
);
530 sym
= psi_call_frame_fetch_symbol(frame
, exp
->data
.dvar
);
531 ref
= deref_impl_val(sym
->ptr
, exp
->data
.dvar
);
533 memcpy(res
, ref
, size
);
538 static inline token_t
psi_number_eval_define(struct psi_number
*exp
,
539 impl_val
*res
, HashTable
*defs
)
541 struct psi_cpp_macro_decl
*macro
= zend_hash_str_find_ptr(defs
, exp
->data
.numb
, strlen(exp
->data
.numb
));
549 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
, HashTable
*defs
)
553 *res
= exp
->data
.ival
;
554 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi8
, res
->i8
);
557 *res
= exp
->data
.ival
;
558 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu8
, res
->u8
);
561 *res
= exp
->data
.ival
;
562 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi16
, res
->i16
);
565 *res
= exp
->data
.ival
;
566 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu16
, res
->u16
);
569 *res
= exp
->data
.ival
;
570 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi32
, res
->i32
);
573 *res
= exp
->data
.ival
;
574 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu32
, res
->u32
);
577 *res
= exp
->data
.ival
;
578 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
581 *res
= exp
->data
.ival
;
582 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIu64
, res
->u64
);
586 *res
= exp
->data
.ival
;
587 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
591 case PSI_T_LONG_DOUBLE
:
592 *res
= exp
->data
.ival
;
593 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
598 res
->i64
= exp
->data
.enm
->val
;
599 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
603 return psi_number_eval_constant(exp
, res
, frame
);
606 return psi_number_eval_decl_var(exp
, res
, frame
);
609 return psi_number_eval_define(exp
, res
, defs
);