#include "php_psi_stdinc.h"
#include <assert.h>
+#include <math.h>
#include "data.h"
#include "calc.h"
#include "call.h"
#include "parser.h"
+#include "Zend/zend_constants.h"
+#include "Zend/zend_operators.h"
+
+
struct psi_number *psi_number_init(token_t t, void *num, unsigned flags)
{
struct psi_number *exp = calloc(1, sizeof(*exp));
exp->data.ival.u64 = *(uint64_t *) num;
break;
case PSI_T_FLOAT:
- exp->data.ival.dval = *(float *) num;
- exp->type = PSI_T_DOUBLE;
+ exp->data.ival.fval = *(float *) num;
break;
case PSI_T_DOUBLE:
exp->data.ival.dval = *(double *) num;
exp->data.ival.ldval = *(long double *) num;
break;
#endif
+ case PSI_T_NULL:
+ break;
case PSI_T_QUOTED_CHAR:
case PSI_T_NUMBER:
case PSI_T_NSNAME:
case PSI_T_FUNCTION:
exp->data.call = num;
break;
+ case PSI_T_SIZEOF:
+ exp->data.dtyp = num;
+ break;
default:
assert(0);
}
case PSI_T_UINT32:
case PSI_T_INT64:
case PSI_T_UINT64:
+ case PSI_T_FLOAT:
case PSI_T_DOUBLE:
#if HAVE_LONG_DOUBLE
case PSI_T_LONG_DOUBLE:
#endif
case PSI_T_ENUM:
case PSI_T_CONST:
+ case PSI_T_NULL:
break;
case PSI_T_NUMBER:
case PSI_T_NSNAME:
case PSI_T_FUNCTION:
num->data.call = psi_cpp_macro_call_copy(num->data.call);
break;
+ case PSI_T_SIZEOF:
+ num->data.dtyp = psi_decl_type_copy(num->data.dtyp);
+ break;
default:
assert(0);
}
case PSI_T_UINT32:
case PSI_T_INT64:
case PSI_T_UINT64:
+ case PSI_T_FLOAT:
case PSI_T_DOUBLE:
#if HAVE_LONG_DOUBLE
case PSI_T_LONG_DOUBLE:
#endif
case PSI_T_ENUM:
case PSI_T_CONST:
+ case PSI_T_NULL:
break;
case PSI_T_FUNCTION:
psi_cpp_macro_call_free(&exp->data.call);
case PSI_T_NAME:
psi_decl_var_free(&exp->data.dvar);
break;
+ case PSI_T_SIZEOF:
+ psi_decl_type_free(&exp->data.dtyp);
+ break;
default:
assert(0);
}
}
}
+struct psi_plist *psi_number_tokens(struct psi_number *exp,
+ struct psi_plist *list)
+{
+ struct psi_token *ntoken;
+ if (!list) {
+ list = psi_plist_init((psi_plist_dtor) psi_token_free);
+ }
+
+ switch (exp->type) {
+ case PSI_T_NAME:
+ /* decl_var */
+ ntoken = psi_token_copy(exp->data.dvar->token);
+
+ if (exp->data.dvar->pointer_level > 1 || !exp->data.dvar->array_size) {
+ struct psi_token *temp = ntoken;
+ unsigned pl = exp->data.dvar->pointer_level - !!exp->data.dvar->array_size;
+
+ while (pl--) {
+
+ ntoken = psi_token_init(PSI_T_POINTER, "*", 1, ntoken->col+ntoken->size, ntoken->line, ntoken->file);
+ list = psi_plist_add(list, &ntoken);
+ }
+ ntoken = temp;
+ }
+
+ list = psi_plist_add(list, &ntoken);
+
+ if (exp->data.dvar->array_size) {
+ char buf[0x20], *ptr;
+
+ ntoken = psi_token_init(PSI_T_LBRACKET, "[", 1, ntoken->col+ntoken->size, ntoken->line, ntoken->file);
+ list = psi_plist_add(list, &ntoken);
+ ptr = zend_print_ulong_to_buf(&buf[sizeof(buf) - 1], exp->data.dvar->array_size);
+
+ ntoken = psi_token_init(PSI_T_NUMBER, ptr, strlen(ptr), ntoken->col+ntoken->size, ntoken->line, ntoken->file);
+ list = psi_plist_add(list, &ntoken);
+ }
+ break;
+
+ case PSI_T_SIZEOF:
+ /* decl_type */
+ ntoken = psi_token_copy(exp->token);
+ list = psi_plist_add(list, &ntoken);
+ ntoken = psi_token_init(PSI_T_LPAREN, "(", 1, ntoken->col+ntoken->size, ntoken->line, ntoken->file);
+ list = psi_plist_add(list, &ntoken);
+ ntoken = psi_token_copy(exp->data.dtyp->token);
+ list = psi_plist_add(list, &ntoken);
+ ntoken = psi_token_init(PSI_T_RPAREN, ")", 1, ntoken->col+ntoken->size, ntoken->line, ntoken->file);
+ list = psi_plist_add(list, &ntoken);
+ break;
+
+ default:
+ ntoken = psi_token_copy(exp->token);
+ list = psi_plist_add(list, &ntoken);
+ break;
+ }
+
+ return list;
+}
+
void psi_number_dump(int fd, struct psi_number *exp)
{
switch (exp->type) {
case PSI_T_UINT64:
dprintf(fd, "%" PRIu64, exp->data.ival.u64);
break;
+ case PSI_T_FLOAT:
+ if (isinf(exp->data.ival.dval)) {
+ dprintf(fd, "\\INF");
+ } else if (isnan(exp->data.ival.dval)) {
+ dprintf(fd, "\\NAN");
+ } else {
+ dprintf(fd, "%" PRIfval, exp->data.ival.dval);
+ }
+ break;
case PSI_T_DOUBLE:
- dprintf(fd, "%F", exp->data.ival.dval);
+ if (isinf(exp->data.ival.dval)) {
+ dprintf(fd, "\\INF");
+ } else if (isnan(exp->data.ival.dval)) {
+ dprintf(fd, "\\NAN");
+ } else {
+ dprintf(fd, "%" PRIdval, exp->data.ival.dval);
+ }
break;
#if HAVE_LONG_DOUBLE
case PSI_T_LONG_DOUBLE:
- dprintf(fd, "%lF", exp->data.ival.ldval);
+ if (isinfl(exp->data.ival.ldval)) {
+ dprintf(fd, "\\INF");
+ } else if (isnanl(exp->data.ival.ldval)) {
+ dprintf(fd, "\\NAN");
+ } else {
+ dprintf(fd, "%" PRIldval, exp->data.ival.ldval);
+ }
break;
#endif
+ case PSI_T_NULL:
+ dprintf(fd, "NULL");
+ break;
case PSI_T_NUMBER:
case PSI_T_NSNAME:
case PSI_T_DEFINE:
case PSI_T_QUOTED_CHAR:
dprintf(fd, "%s", exp->data.numb);
break;
+ case PSI_T_FUNCTION:
+ psi_cpp_macro_call_dump(fd, exp->data.call);
+ break;
case PSI_T_CONST:
dprintf(fd, "%s", exp->data.cnst->name);
break;
case PSI_T_NAME:
psi_decl_var_dump(fd, exp->data.dvar);
break;
+ case PSI_T_SIZEOF:
+ dprintf(fd, "sizeof(");
+ psi_decl_type_dump(fd, exp->data.dtyp, 0);
+ dprintf(fd, ")");
+ break;
default:
assert(0);
}
}
-static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
- struct psi_decl_enum *enm)
+static inline bool psi_number_validate_enum(struct psi_data *data,
+ struct psi_number *exp, struct psi_validate_scope *scope)
{
- size_t i = 0;
- struct psi_decl_enum_item *itm;
+ if (scope && scope->current_enum) {
+ size_t i = 0;
+ struct psi_decl_enum_item *itm;
+ struct psi_decl_enum *enm;
- while (psi_plist_get(enm->items, i++, &itm)) {
- if (!strcmp(itm->name, exp->data.dvar->name)) {
- psi_decl_var_free(&exp->data.dvar);
- exp->type = PSI_T_ENUM;
- exp->data.enm = itm;
- return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
+ enm = scope->current_enum;
+
+ switch (exp->type) {
+ case PSI_T_NAME:
+ while (psi_plist_get(enm->items, i++, &itm)) {
+ if (!strcmp(itm->name, exp->data.dvar->name)) {
+ psi_decl_var_free(&exp->data.dvar);
+ exp->type = PSI_T_ENUM;
+ exp->data.enm = itm;
+ return psi_number_validate(data, exp, scope);
+ }
+ }
+ break;
+
+ case PSI_T_DEFINE:
+ while (psi_plist_get(enm->items, i++, &itm)) {
+ if (!strcmp(itm->name, exp->data.numb)) {
+ free(exp->data.numb);
+ exp->type = PSI_T_ENUM;
+ exp->data.enm = itm;
+ return psi_number_validate(data, exp, scope);
+ }
+ }
+ break;
+
+ default:
+ assert(0);
}
}
-
return false;
}
-static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
+static inline token_t validate_char(char *numb, impl_val *res, unsigned *lvl)
{
- impl_val tmp = {0};
- /* FIXME L */
- tmp.i8 = exp->data.numb[1 + (*exp->data.numb == 'L')];
- switch(tmp.i8) {
+ char *endptr;
+ token_t typ = PSI_T_INT8;
+
+ res->i8 = numb[0];
+ endptr = &numb[1];
+
+ switch(res->i8) {
case '\\':
- tmp.i8 = exp->data.numb[2 + (*exp->data.numb == 'L')];
- switch(tmp.i8) {
+ res->i8 = numb[1];
+ endptr = &numb[2];
+
+ switch(res->i8) {
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
+ res->i8 = strtol(&numb[1], &endptr, 8);
+ break;
+
case 'x':
- tmp.i8 = strtol(&exp->data.numb[3 + (*exp->data.numb == 'L')], NULL, 16);
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = tmp.i8;
- return true;
- case '\'':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\'';
- return true;
+ res->i8 = strtol(&numb[2], &endptr, 16);
+ break;
+
case 'a':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\a';
- return true;
+ res->i8 = '\a';
+ break;
case 'b':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\b';
- return true;
+ res->i8 = '\b';
+ break;
case 'f':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\f';
- return true;
+ res->i8 = '\f';
+ break;
case 'n':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\n';
- return true;
+ res->i8 = '\n';
+ break;
case 'r':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\r';
- return true;
+ res->i8 = '\r';
+ break;
case 't':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\t';
- return true;
+ res->i8 = '\t';
+ break;
case 'v':
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = '\v';
- return true;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
- tmp.i8 = strtol(&exp->data.numb[2 + (*exp->data.numb == 'L')], NULL, 8);
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = tmp.i8;
- return true;
+ res->i8 = '\v';
+ break;
default:
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = tmp.i8;
- return true;
+ break;
}
break;
default:
- free(exp->data.numb);
- exp->type = PSI_T_INT8;
- exp->data.ival.i8 = tmp.i8;
- return true;
+ break;
}
+
+ /* more to grok? */
+ if (*endptr) {
+ impl_val tmp_val = {0};
+ token_t tmp_typ = validate_char(endptr, &tmp_val, lvl);
+
+ if (!tmp_typ) {
+ return 0;
+ }
+
+ res->i32 = res->i8 << (8 * *lvl);
+ typ = psi_calc_add(PSI_T_INT32, res, tmp_typ, &tmp_val, res);
+ }
+
+ ++(*lvl);
+
+ return typ;
+}
+static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
+{
+ impl_val val = {0};
+ unsigned lvl = 1;
+ token_t typ = validate_char(exp->data.numb, &val, &lvl);
+
+ if (!typ) {
+ return false;
+ }
+
+ free(exp->data.numb);
+ exp->type = typ;
+ exp->data.ival = val;
+ return true;
}
static inline bool psi_number_validate_number(struct psi_data *data, struct psi_number *exp)
}
bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
- struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
- struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
+ struct psi_validate_scope *scope)
{
size_t i = 0;
struct psi_const *cnst;
struct psi_decl_enum *enm;
switch (exp->type) {
+ case PSI_T_NULL:
+ exp->type = PSI_T_UINT8;
+ /* no break */
case PSI_T_CONST:
case PSI_T_INT8:
case PSI_T_UINT8:
case PSI_T_UINT32:
case PSI_T_INT64:
case PSI_T_UINT64:
+ case PSI_T_FLOAT:
case PSI_T_DOUBLE:
#if HAVE_LONG_DOUBLE
case PSI_T_LONG_DOUBLE:
#endif
case PSI_T_ENUM:
- case PSI_T_DEFINE:
- case PSI_T_FUNCTION:
return true;
case PSI_T_NAME:
- if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
+ if (scope && scope->defs && zend_hash_str_exists(scope->defs, exp->data.dvar->name, strlen(exp->data.dvar->name))) {
+ return true;
+ }
+ if (scope && scope->current_enum && psi_number_validate_enum(data, exp, scope)) {
return true;
}
while (psi_plist_get(data->enums, i++, &enm)) {
- if (psi_number_validate_enum(data, exp, enm)) {
+ struct psi_validate_scope enum_scope = *scope;
+ enum_scope.current_enum = enm;
+ if (psi_number_validate_enum(data, exp, &enum_scope)) {
return true;
}
}
if (exp->data.dvar->arg) {
return true;
}
- if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
- current_let, current_set)) {
- return true;
- }
- if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
+ if (psi_decl_var_validate(data, exp->data.dvar, scope)) {
return true;
}
data->error(data, exp->token, PSI_WARNING,
exp->data.dvar->name);
return false;
+ case PSI_T_FUNCTION:
+ if (scope && scope->defs && zend_hash_str_exists(scope->defs, exp->data.numb, strlen(exp->data.numb))) {
+ return true;
+ }
+ return false;
+
+ case PSI_T_DEFINE:
+ if (scope && scope->defs && zend_hash_str_exists(scope->defs, exp->data.numb, strlen(exp->data.numb))) {
+ if (!scope->macro || strcmp(scope->macro->token->text, exp->data.numb)) {
+ return true;
+ }
+ /* #define foo foo */
+ }
+ while (psi_plist_get(data->enums, i++, &enm)) {
+ struct psi_validate_scope enum_scope = *scope;
+ enum_scope.current_enum = enm;
+ if (psi_number_validate_enum(data, exp, &enum_scope)) {
+ return true;
+ }
+ }
+ return false;
+
+ case PSI_T_SIZEOF:
+ if (psi_decl_type_validate(data, exp->data.dtyp, NULL, scope)) {
+ struct psi_decl_type *dtyp = exp->data.dtyp;
+
+ exp->type = PSI_T_UINT64;
+ exp->data.ival.u64 = psi_decl_type_get_size(dtyp, NULL);
+ psi_decl_type_free(&dtyp);
+ return true;
+ } else {
+ struct psi_decl_type *dtyp = exp->data.dtyp;
+
+ data->error(data, exp->token, PSI_WARNING,
+ "Cannot compute sizeof(%s) (%u)", dtyp->name, dtyp->type);
+
+ exp->type = PSI_T_UINT8;
+ exp->data.ival.u8 = 0;
+ psi_decl_type_free(&dtyp);
+ }
+ break;
+
case PSI_T_NSNAME:
+ {
+ zval *zc;
+
+ if (*exp->data.numb == '\\') {
+ zc = zend_get_constant_str(exp->data.numb + 1, strlen(exp->data.numb) - 1);
+ } else {
+ zc = zend_get_constant_str(exp->data.numb, strlen(exp->data.numb));
+ }
+
+ if (zc) {
+ switch (Z_TYPE_P(zc)) {
+ case IS_LONG:
+ free(exp->data.numb);
+ exp->type = PSI_T_INT64;
+ exp->data.ival.i64 = Z_LVAL_P(zc);
+ return true;
+
+ case IS_DOUBLE:
+ free(exp->data.numb);
+ exp->type = PSI_T_DOUBLE;
+ exp->data.ival.dval = Z_DVAL_P(zc);
+ return true;
+
+ default:
+ assert(0);
+ }
+ }
+ }
while (psi_plist_get(data->consts, i++, &cnst)) {
if (!strcmp(cnst->name, exp->data.numb)) {
free(exp->data.numb);
return false;
}
-#include "Zend/zend_constants.h"
-
static inline token_t psi_number_eval_constant(struct psi_number *exp,
impl_val *res, struct psi_call_frame *frame)
{
if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
return PSI_T_DOUBLE;
default:
- if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
+ if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%u)", exp->data.cnst->type->type);
return 0;
}
}
impl_val *ref;
struct psi_call_frame_symbol *sym;
struct psi_decl_type *real;
+ struct psi_decl_var *var;
size_t size;
- real = psi_decl_type_get_real(exp->data.dvar->arg->type);
- size = psi_decl_arg_get_size(exp->data.dvar->arg);
- sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
- ref = deref_impl_val(sym->ptr, exp->data.dvar);
+ var = exp->data.dvar;
+ real = psi_decl_type_get_real(var->arg->type);
+ size = psi_decl_arg_get_size(var->arg);
+ sym = psi_call_frame_fetch_symbol(frame, var);
+ ref = deref_impl_val(sym->ptr, var);
memcpy(res, ref, size);
+ if (var->arg->var->pointer_level > var->pointer_level) {
+ switch (SIZEOF_VOID_P) {
+ case 4:
+ return PSI_T_INT32;
+ case 8:
+ return PSI_T_INT64;
+ default:
+ assert(0);
+ }
+ }
return real->type;
}
static inline token_t psi_number_eval_define(struct psi_number *exp,
- impl_val *res, HashTable *defs)
+ impl_val *res, HashTable *defs, struct psi_num_exp *rec_guard)
{
- struct psi_cpp_macro_decl *macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
-
- assert(!macro);
+ if (defs) {
+ struct psi_cpp_macro_decl *macro;
+ macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
+ if (macro && macro->exp && macro->exp != rec_guard) {
+ return psi_num_exp_exec(macro->exp, res, NULL, defs);
+ }
+ }
res->u8 = 0;
return PSI_T_UINT8;
}
-token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame, HashTable *defs)
+token_t psi_number_eval(struct psi_number *exp, impl_val *res,
+ struct psi_call_frame *frame, HashTable *defs, struct psi_num_exp *rec_guard)
{
switch (exp->type) {
case PSI_T_INT8:
if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu64, res->u64);
return PSI_T_UINT64;
+ case PSI_T_FLOAT:
+ *res = exp->data.ival;
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
+ return exp->type;
+
case PSI_T_DOUBLE:
*res = exp->data.ival;
if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
#if HAVE_LONG_DOUBLE
case PSI_T_LONG_DOUBLE:
*res = exp->data.ival;
- if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIldval, res->ldval);
return exp->type;
#endif
if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
return PSI_T_INT64;
+ case PSI_T_NUMBER:
+ res->i64 = atol(exp->data.numb);
+ return PSI_T_INT64;
+
case PSI_T_CONST:
return psi_number_eval_constant(exp, res, frame);
return psi_number_eval_decl_var(exp, res, frame);
case PSI_T_DEFINE:
- return psi_number_eval_define(exp, res, defs);
+ return psi_number_eval_define(exp, res, defs, rec_guard);
case PSI_T_FUNCTION:
res->u8 = 0;