void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
+static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *val) {
+ switch (exp->t) {
+ case PSI_T_NUMBER:
+ switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) val, (double *) val, 0)) {
+ case IS_LONG:
+ return PSI_T_INT64;
+ case IS_DOUBLE:
+ return PSI_T_DOUBLE;
+ }
+ break;
+
+ case PSI_T_NSNAME:
+ switch (exp->u.cnst->type->type) {
+ case PSI_T_INT:
+ val->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
+ return PSI_T_INT64;
+ case PSI_T_FLOAT:
+ val->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
+ return PSI_T_DOUBLE;
+ default:
+ return 0;
+ }
+ break;
+
+ case PSI_T_NAME:
+ switch (real_decl_type(exp->u.dvar->arg->type)->type) {
+ case PSI_T_INT8:
+ case PSI_T_UINT8:
+ case PSI_T_INT16:
+ case PSI_T_UINT16:
+ case PSI_T_INT32:
+ case PSI_T_UINT32:
+ case PSI_T_INT64:
+ case PSI_T_UINT64:
+ memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val));
+ return real_decl_type(exp->u.dvar->arg->type)->type;
+
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val));
+ return real_decl_type(exp->u.dvar->arg->type)->type;
+
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ break;
+
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return 0;
+}
+
+static inline int psi_calc_num_exp(num_exp *exp, impl_val *val) {
+ impl_val num = {0};
+ int num_type = psi_calc_num_exp_value(exp, &num);
+
+ if (exp->operand) {
+ impl_val tmp = {0};
+ int tmp_type = psi_calc_num_exp(exp->operand, &tmp);
+
+ return exp->calculator(num_type, &num, tmp_type, &tmp, val);
+ }
+
+ memcpy(val, &num, sizeof(*val));
+ return num_type;
+}
+
+static inline zend_long psi_long_num_exp(num_exp *exp) {
+ impl_val val = {0};
+
+ switch (psi_calc_num_exp(exp, &val)) {
+ case PSI_T_UINT8: val.u16 = val.u8;
+ case PSI_T_UINT16: val.u32 = val.u16;
+ case PSI_T_UINT32: val.u64 = val.u32;
+ case PSI_T_UINT64: return val.u64;
+ case PSI_T_INT8: val.i16 = val.i8;
+ case PSI_T_INT16: val.i32 = val.i16;
+ case PSI_T_INT32: val.i64 = val.i32;
+ case PSI_T_INT64: return val.i64;
+ case PSI_T_FLOAT: val.dval = val.fval;
+ case PSI_T_DOUBLE: return val.dval;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+}
+
ZEND_BEGIN_MODULE_GLOBALS(psi)
char *engine;
char *directory;
// extern int stat(char *path, struct stat *buf);
function psi\stat(string $path, array &$buf = NULL) : int {
let path = strval($path);
- let buf = calloc(1, struct stat);
+ let buf = calloc(1, psi\SIZEOF_STRUCT_STAT);
return to_int(stat);
set $buf = to_array(*buf,
to_int(st_dev),
// extern int gettimeofday(struct timeval *tp, struct timezone *tz);
function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
- let tp = calloc(1, struct timeval);
- let tz = calloc(1, struct timezone);
+ let tp = calloc(1, psi\SIZEOF_STRUCT_TIMEVAL);
+ let tz = calloc(1, psi\SIZEOF_STRUCT_TIMEZONE);
return to_int(gettimeofday);
set $tv = to_array(*tp,
to_int(tv_sec),
// extern char *asctime_r(struct tm *tm, char *buf);
function psi\asctime_r(array $tm = NULL) : string {
let tm = arrval($tm);
- let buf = calloc(32, char);
+ let buf = calloc(32, psi\SIZEOF_CHAR);
return to_string(asctime_r);
}
// extern struct tm *gmtime_r(time_t *t, struct tm *buf);
function psi\gmtime_r(int $ts) : array {
let t = &intval($ts);
- let buf = calloc(1, struct tm);
+ let buf = calloc(1, psi\SIZEOF_STRUCT_TM);
return to_array(*gmtime_r,
to_int(tm_sec),
to_int(tm_min),
// extern int nanosleep(struct timespec *rqts, struct timespec *rmts);
function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
let rqts = arrval($rq);
- let rmts = calloc(1, struct timespec);
+ let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC);
return to_int(nanosleep);
set $rm = to_array(*rmts,
to_int(tv_sec),
// extern clock_t times(struct tms *buf);
function psi\times(array &$tms = NULL) : int {
- let buf = calloc(1, struct tms);
+ let buf = calloc(1, psi\SIZEOF_STRUCT_TMS);
return to_int(times);
set $tms = to_array(*buf,
to_int(tms_utime),
function psi\uname(array &$u = NULL) : int {
- let name = calloc(1, struct utsname);
+ let name = calloc(1, psi\SIZEOF_STRUCT_UTSNAME);
return to_int(uname);
set $u = to_array(*name,
to_string(sysname),
return 1;
}
+static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) {
+ size_t i;
+
+ for (i = 0; i < consts->count; ++i) {
+ constant *cnst = consts->list[i];
+
+ if (!strcmp(cnst->name, exp->u.numb)) {
+ free(exp->u.numb);
+ return exp->u.cnst = cnst;
+ }
+ }
+
+ return NULL;
+}
+static inline int validate_num_exp(PSI_Data *data, impl *impl, num_exp *exp) {
+ switch (exp->t) {
+ case PSI_T_NAME:
+ if (!locate_decl_var_arg(exp->u.dvar, impl->decl->args)) {
+ data->error(PSI_WARNING, "Unknown variable '%s' in numeric expression"
+ " of implementation '%s'", exp->u.dvar->name, impl->func->name);
+ return 0;
+ }
+ return 1;
+ case PSI_T_NSNAME:
+ if (!locate_num_exp_constant(exp, data->consts)) {
+ data->error(PSI_WARNING, "Unknown constant '%s' in numeric expression"
+ " of implementation '%s'", exp->u.numb, impl->func->name);
+ return 0;
+ }
+ return 1;
+ case PSI_T_NUMBER:
+ return 1;
+ default:
+ return 0;
+ }
+}
static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
size_t i, j;
/* we can have multiple let stmts */
int check = 0;
if (let->val && let->val->func && let->val->func->alloc) {
- if (!validate_decl_type(data, let->val->func->alloc->type)) {
- data->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement",
- let->val->func->alloc->type->name);
+ if (!validate_num_exp(data, impl, let->val->func->alloc->nmemb)) {
+ return 0;
+ }
+ if (!validate_num_exp(data, impl, let->val->func->alloc->size)) {
return 0;
}
}
dprintf(fd, ");\n");
}
}
+static inline void dump_num_exp(int fd, num_exp *exp) {
+ switch (exp->t) {
+ case PSI_T_NUMBER:
+ dprintf(fd, "%s", exp->u.numb);
+ break;
+ case PSI_T_NAME:
+ dump_decl_var(fd, exp->u.dvar);
+ break;
+ case PSI_T_NSNAME:
+ dprintf(fd, "%s", exp->u.cnst->name);
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+}
void PSI_ContextDump(PSI_Context *C, int fd)
{
size_t i, j, k, l;
if (let->val->func) {
dprintf(fd, "%s(", let->val->func->name);
if (let->val->func->alloc) {
- dprintf(fd, "%zu, ", let->val->func->alloc->n);
- dump_decl_type(fd, let->val->func->alloc->type);
+ dump_num_exp(fd, let->val->func->alloc->nmemb);
+ dprintf(fd, ", ");
+ dump_num_exp(fd, let->val->func->alloc->size);
} else {
dprintf(fd, "$%s", let->val->var->name);
}
#include "php_ini.h"
#include "ext/standard/info.h"
#include "zend_exceptions.h"
+#include "zend_constants.h"
+#include "zend_operators.h"
#include "php_psi.h"
#include "parser.h"
static inline void *psi_do_calloc(let_calloc *alloc)
{
- decl_type *type = real_decl_type(alloc->type);
- size_t size;
-
- if (type->type == PSI_T_STRUCT) {
- /* psi_do_clean expects at least one NULL pointer after the struct */
- size = type->strct->size + sizeof(void *);
- } else {
- size = psi_t_size(type->type);
- }
-
- return ecalloc(alloc->n, size);
+ zend_long n = psi_long_num_exp(alloc->nmemb), s = psi_long_num_exp(alloc->size);
+ void *mem = safe_emalloc(n, s, sizeof(void *));
+ memset(mem, 0, n * s + sizeof(void *));
+ return mem;
}
static inline void *psi_do_let(decl_arg *darg)
}
}
+
+#define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
+#define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
+
+int psi_calc_plus(unsigned char t1, impl_val *v1, unsigned char t2, impl_val *v2, impl_val *res)
+{
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) + (var2)
+ if (t1 == t2) {
+ switch (t1) {
+ case PSI_T_FLOAT: PSI_CALC_OP(fval); break;
+ case PSI_T_DOUBLE: PSI_CALC_OP(dval); break;
+ case PSI_T_INT8: PSI_CALC_OP(i8); break;
+ case PSI_T_UINT8: PSI_CALC_OP(u8); break;
+ case PSI_T_INT16: PSI_CALC_OP(i16); break;
+ case PSI_T_UINT16: PSI_CALC_OP(u16); break;
+ case PSI_T_INT32: PSI_CALC_OP(i32); break;
+ case PSI_T_UINT32: PSI_CALC_OP(u32); break;
+ case PSI_T_INT64: PSI_CALC_OP(i64); break;
+ case PSI_T_UINT64: PSI_CALC_OP(u64); break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return t1;
+ } else if (t1 == PSI_T_DOUBLE) {
+ switch (t2) {
+ case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break;
+ case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break;
+ case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break;
+ case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break;
+ case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break;
+ case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break;
+ case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break;
+ case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break;
+ case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return t1;
+ } else if (t2 == PSI_T_DOUBLE) {
+ switch (t1) {
+ case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break;
+ case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break;
+ case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break;
+ case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break;
+ case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break;
+ case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break;
+ case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break;
+ case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break;
+ case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return t2;
+ } else if (t1 == PSI_T_FLOAT) {
+ switch (t2) {
+ case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2;
+ case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break;
+ case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break;
+ case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break;
+ case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break;
+ case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break;
+ case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break;
+ case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break;
+ case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return t1;
+ } else if (t2 == PSI_T_FLOAT) {
+ switch (t1) {
+ case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1;
+ case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break;
+ case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break;
+ case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break;
+ case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break;
+ case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break;
+ case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break;
+ case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break;
+ case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return t2;
+ } else {
+ int64_t sval1 = v1->i64, sval2 = v2->i64;
+ uint64_t uval1 = v1->u64, uval2 = v2->u64;
+
+ switch (t1) {
+ case PSI_T_INT8: sval1 >>= 8;
+ case PSI_T_INT16: sval1 >>= 8;
+ case PSI_T_INT32: sval1 >>= 8;
+ case PSI_T_INT64:
+ switch (t2) {
+ case PSI_T_INT8: sval2 >>= 8;
+ case PSI_T_INT16: sval2 >>= 8;
+ case PSI_T_INT32: sval2 >>= 8;
+ case PSI_T_INT64:
+ res->i64 = PSI_CALC(sval1 , sval2);
+ return PSI_T_INT64;
+ case PSI_T_UINT8: uval2 >>= 8;
+ case PSI_T_UINT16: uval2 >>= 8;
+ case PSI_T_UINT32: uval2 >>= 8;
+ case PSI_T_UINT64:
+ res->i64 = PSI_CALC(sval1, uval2);
+ return PSI_T_INT64;
+ }
+ break;
+ case PSI_T_UINT8: uval1 >>= 8;
+ case PSI_T_UINT16: uval1 >>= 8;
+ case PSI_T_UINT32: uval1 >>= 8;
+ case PSI_T_UINT64:
+ switch (t2) {
+ case PSI_T_INT8: sval2 >>= 8;
+ case PSI_T_INT16: sval2 >>= 8;
+ case PSI_T_INT32: sval2 >>= 8;
+ case PSI_T_INT64:
+ res->i64 = PSI_CALC(uval1, sval2);
+ return PSI_T_INT64;
+ case PSI_T_UINT8: uval2 >>= 8;
+ case PSI_T_UINT16: uval2 >>= 8;
+ case PSI_T_UINT32: uval2 >>= 8;
+ case PSI_T_UINT64:
+ res->u64 = PSI_CALC(uval1, uval2);
+ return PSI_T_UINT64;
+ }
+ break;
+ }
+ }
+ ZEND_ASSERT(0);
+ return 0;
+}
+
void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
{
impl_val ret_val;
token_t t;
union {
char *numb;
- char *cnst;
+ constant *cnst;
decl_var *dvar;
} u;
token_t operator;
+ int (*calculator)(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
struct num_exp *operand;
} num_exp;
num_exp *exp = calloc(1, sizeof(*exp));
switch (exp->t = t) {
case PSI_T_NUMBER:
- exp->u.numb = strdup(num);
- break;
case PSI_T_NSNAME:
- exp->u.cnst = strdup(num);
+ exp->u.numb = strdup(num);
break;
case PSI_T_NAME:
exp->u.dvar = num;
free(exp->u.numb);
break;
case PSI_T_NSNAME:
- free(exp->u.cnst);
break;
case PSI_T_NAME:
free_decl_var(exp->u.dvar);
}
%nonassoc NAME.
-%left PLUS MINUS SLASH ASTERISK.
+%left PLUS MINUS.
+%left SLASH ASTERISK.
%fallback NAME FREE SET LET RETURN LIB INT UNSIGNED.
file ::= blocks.