cat $(PHP_PSI_SRCDIR)/src/parser_proc.inc >$@
$(CPP) -P -DGENERATE $< >>$@
$(PHP_PSI_SRCDIR)/src/parser_proc.c: $(PHP_PSI_SRCDIR)/src/parser_proc.y $(LEMON)
- $(LEMON) -c $<
+ $(LEMON) $<
$(PHP_PSI_SRCDIR)/src/parser.re: $(PHP_PSI_SRCDIR)/src/parser_proc.h
touch $@
to_int(gl_flags),
to_array(*gl_pathv, gl_pathc + gl_offs, to_string(*gl_pathv))
);
- free globfree(buf);
}
let endptr = &NULL;
return to_float(strtold);
set $end = to_string(*endptr);
+}
+
+extern double pow(double x, double y);
+function psi\pow2() : float {
+ let x = 1 | 2;
+ let y = 1 << 1;
+ return to_float(pow);
}
\ No newline at end of file
*******************************************************************************/
#include "php_psi_stdinc.h"
+#include <assert.h>
#include "token.h"
#include "calc.h"
-#define PRIfval "f"
-#define PRIdval "lf"
-#define PRIldval "Lf"
+#define PSI_CALC_CAST_SET(in_type, in_val, out_val, out_var) \
+switch (in_type) { \
+case PSI_T_INT8: (out_val)->out_var = (in_val)->i8; break; \
+case PSI_T_UINT8: (out_val)->out_var = (in_val)->u8; break; \
+case PSI_T_INT16: (out_val)->out_var = (in_val)->i16; break; \
+case PSI_T_UINT16: (out_val)->out_var = (in_val)->u16; break; \
+case PSI_T_INT32: (out_val)->out_var = (in_val)->i32; break; \
+case PSI_T_UINT32: (out_val)->out_var = (in_val)->u32; break; \
+case PSI_T_INT64: (out_val)->out_var = (in_val)->i64; break; \
+case PSI_T_UINT64: (out_val)->out_var = (in_val)->u64; break; \
+case PSI_T_FLOAT: (out_val)->out_var = (in_val)->fval; break; \
+case PSI_T_DOUBLE: (out_val)->out_var = (in_val)->dval; break; \
+case PSI_T_LONG_DOUBLE: (out_val)->out_var = (in_val)->ldval; break; \
+default: \
+ assert(0); \
+}
+
+#define PSI_CALC_CAST(in_type, in_val, out_type, out_val) \
+switch (out_type) { \
+case PSI_T_INT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, i8) break; \
+case PSI_T_UINT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, u8) break; \
+case PSI_T_INT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, i16) break; \
+case PSI_T_UINT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, u16) break; \
+case PSI_T_INT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, i32) break; \
+case PSI_T_UINT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, u32) break; \
+case PSI_T_INT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, i64) break; \
+case PSI_T_UINT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, u64) break; \
+case PSI_T_FLOAT: PSI_CALC_CAST_SET(in_type, in_val, out_val, fval) break; \
+case PSI_T_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, dval) break; \
+case PSI_T_LONG_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, ldval) break; \
+default: \
+ assert(0); \
+}
+
+void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
+{
+ PSI_CALC_CAST(in_type, in_val, out_type, out_val)
+}
+#if 0
#define PSI_CALC_OP(var) do { \
const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
res->var = PSI_CALC(v1->var, v2->var); \
res->vres = PSI_CALC(v1->var1, v2->var2); \
if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
} while(0)
+#else
+#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)
+#endif
#ifdef HAVE_LONG_DOUBLE
# define PSI_CALC_NO_LD
break; \
} \
} \
- ZEND_ASSERT(0); \
+ assert(0); \
return 0; \
}
#undef PSI_CALC
#define PSI_CALC(var1, var2) (var1) / (var2)
PSI_CALC_FN(div)
+#undef PSI_CALC
+
+#define PSI_CALC_BIN_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
+{ \
+ impl_val i1, i2; \
+ PSI_CALC_CAST(t1, v1, PSI_T_UINT64, &i1); \
+ PSI_CALC_CAST(t2, v2, PSI_T_UINT64, &i2); \
+ res->u64 = PSI_CALC(i1.u64, i2.u64); \
+ return PSI_T_UINT64; \
+}
+
+#define PSI_CALC(var1, var2) (var1) << (var2)
+PSI_CALC_BIN_FN(bin_lshift)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) >> (var2)
+PSI_CALC_BIN_FN(bin_rshift)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) & (var2)
+PSI_CALC_BIN_FN(bin_and)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) ^ (var2)
+PSI_CALC_BIN_FN(bin_xor)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) | (var2)
+PSI_CALC_BIN_FN(bin_or)
+#undef PSI_CALC
+
#include "token.h"
#include "impl_val.h"
+#define PRIfval "f"
+#define PRIdval "lf"
+#define PRIldval "Lf"
+
token_t psi_calc_add(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
token_t psi_calc_sub(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
token_t psi_calc_mul(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
token_t psi_calc_div(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_lshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_rshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_xor(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+
+void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val);
+
#endif
#include <stdarg.h>
#define PSI_DEBUG_PRINT(ctx, msg, ...) do { \
- if (PSI_DATA(ctx)->flags & PSI_DEBUG) { \
+ if ((ctx) && (PSI_DATA(ctx)->flags & PSI_DEBUG)) { \
fprintf(stderr, msg, __VA_ARGS__); \
} \
} while(0)
ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
ZEND_ARG_INFO(0, file)
+ ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
static PHP_FUNCTION(psi_validate)
{
zend_string *file;
struct psi_parser P;
struct psi_data D = {0};
+ zend_long flags = 0;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &file, &flags)) {
return;
}
- if (!psi_parser_init(&P, psi_error_wrapper, 0)) {
+ if (!psi_parser_init(&P, psi_error_wrapper, flags)) {
RETURN_FALSE;
}
if (!psi_parser_open_file(&P, file->val)) {
zend_string *string;
struct psi_parser P;
struct psi_data D = {0};
+ zend_long flags = 0;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &string)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &string, &flags)) {
return;
}
- if (!psi_parser_init(&P, psi_error_wrapper, 0)) {
+ if (!psi_parser_init(&P, psi_error_wrapper, flags)) {
RETURN_FALSE;
}
if (!psi_parser_open_string(&P, string->val, string->len)) {
zend_class_entry ce = {0};
unsigned flags = 0;
- if (psi_check_env("PSI_DEBUG")) {
- flags |= PSI_DEBUG;
- }
- if (psi_check_env("PSI_SILENT")) {
- flags |= PSI_SILENT;
- }
-
REGISTER_INI_ENTRIES();
+ zend_register_long_constant(ZEND_STRL("PSI_DEBUG"), PSI_DEBUG, CONST_CS|CONST_PERSISTENT, module_number);
+ zend_register_long_constant(ZEND_STRL("PSI_SILENT"), PSI_SILENT, CONST_CS|CONST_PERSISTENT, module_number);
+
INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
psi_class_entry->create_object = psi_object_init;
return FAILURE;
}
+ if (psi_check_env("PSI_DEBUG")) {
+ flags |= PSI_DEBUG;
+ }
+ if (psi_check_env("PSI_SILENT")) {
+ flags |= PSI_SILENT;
+ }
+
PSI_G(context) = psi_context_init(NULL, ops, psi_error_wrapper, flags);
psi_context_build(PSI_G(context), PSI_G(directory));
"+" {RETURN(PSI_T_PLUS);}
"-" {RETURN(PSI_T_MINUS);}
"/" {RETURN(PSI_T_SLASH);}
+ "|" {RETURN(PSI_T_PIPE);}
+ "^" {RETURN(PSI_T_CARET);}
+ "<<" {RETURN(PSI_T_LSHIFT);}
+ ">>" {RETURN(PSI_T_RSHIFT);}
"..." {RETURN(PSI_T_ELLIPSIS);}
[\r\n] { NEWLINE(nextline); }
[\t ]+ { continue; }
})
DEF(%nonassoc, NAME.)
+DEF(%left, LSHIFT RSHIFT.)
DEF(%left, PLUS MINUS.)
DEF(%left, ASTERISK SLASH.)
DEF(%nonassoc, AMPERSAND.)
+DEF(%nonassoc, CARET.)
+DEF(%nonassoc, PIPE.)
DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.)
DEF(%token_class, const_type_token BOOL INT FLOAT STRING.)
DEF(%token_class, decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.)
DEF(%token_class, impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.)
DEF(%token_class, num_exp_token NUMBER NSNAME.)
-DEF(%token_class, num_exp_op_token PLUS MINUS ASTERISK SLASH.)
+DEF(%token_class, num_exp_op_token LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH AMPERSAND CARET PIPE.)
DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT.)
DEF(%token_class, set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.)
DEF(%token_class, impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.)
* num_exp: num_exp num_exp_op_token num_exp
*/
PARSE_TYPED(num_exp, exp,
- TYPED(num_exp, exp_)
+ TYPED(num_exp, exp1)
NAMED(num_exp_op_token, operator_)
- TYPED(num_exp, operand_)) {
- exp_->op = operator_->type;
- exp_->operand = operand_;
- exp = exp_;
+ TYPED(num_exp, exp2)) {
+ exp = exp1;
+ do {
+ struct psi_num_exp *op = exp1;
+ while (op->operand) {
+ op = op->operand;
+ }
+ op->op = operator_->type;
+ op->operand = exp2;
+ } while(0);
free(operator_);
}
* free_stmt: FREE free_exps ;
*/
PARSE_TYPED(free_stmt, free,
- TOKEN(FREE)
+ NAMED(FREE, T)
TYPED(free_exps, calls)
TOKEN(EOS)) {
free = psi_free_stmt_init(calls);
+ free->token = T;
}
/*
#define PSI_T_NAME 1
-#define PSI_T_PLUS 2
-#define PSI_T_MINUS 3
-#define PSI_T_ASTERISK 4
-#define PSI_T_SLASH 5
-#define PSI_T_AMPERSAND 6
-#define PSI_T_TEMP 7
-#define PSI_T_FREE 8
-#define PSI_T_SET 9
-#define PSI_T_LET 10
-#define PSI_T_RETURN 11
-#define PSI_T_CALLOC 12
-#define PSI_T_CALLBACK 13
-#define PSI_T_ZVAL 14
-#define PSI_T_LIB 15
-#define PSI_T_STRING 16
-#define PSI_T_COUNT 17
-#define PSI_T_BOOL 18
-#define PSI_T_INT 19
-#define PSI_T_FLOAT 20
-#define PSI_T_DOUBLE 21
-#define PSI_T_INT8 22
-#define PSI_T_UINT8 23
-#define PSI_T_INT16 24
-#define PSI_T_UINT16 25
-#define PSI_T_INT32 26
-#define PSI_T_UINT32 27
-#define PSI_T_INT64 28
-#define PSI_T_UINT64 29
-#define PSI_T_NULL 30
-#define PSI_T_NUMBER 31
-#define PSI_T_TRUE 32
-#define PSI_T_FALSE 33
-#define PSI_T_QUOTED_STRING 34
-#define PSI_T_NSNAME 35
-#define PSI_T_OBJVAL 36
-#define PSI_T_ARRVAL 37
-#define PSI_T_PATHVAL 38
-#define PSI_T_STRLEN 39
-#define PSI_T_STRVAL 40
-#define PSI_T_FLOATVAL 41
-#define PSI_T_INTVAL 42
-#define PSI_T_BOOLVAL 43
-#define PSI_T_TO_OBJECT 44
-#define PSI_T_TO_ARRAY 45
-#define PSI_T_TO_STRING 46
-#define PSI_T_TO_INT 47
-#define PSI_T_TO_FLOAT 48
-#define PSI_T_TO_BOOL 49
-#define PSI_T_VOID 50
-#define PSI_T_MIXED 51
-#define PSI_T_ARRAY 52
-#define PSI_T_OBJECT 53
-#define PSI_T_CALLABLE 54
-#define PSI_T_EOF 55
-#define PSI_T_EOS 56
-#define PSI_T_COLON 57
-#define PSI_T_LPAREN 58
-#define PSI_T_COMMA 59
-#define PSI_T_RPAREN 60
-#define PSI_T_ENUM 61
-#define PSI_T_STRUCT 62
-#define PSI_T_UNION 63
-#define PSI_T_LBRACE 64
-#define PSI_T_RBRACE 65
-#define PSI_T_EQUALS 66
-#define PSI_T_CONST 67
-#define PSI_T_TYPEDEF 68
-#define PSI_T_ELLIPSIS 69
-#define PSI_T_LBRACKET 70
-#define PSI_T_RBRACKET 71
-#define PSI_T_CHAR 72
-#define PSI_T_SHORT 73
-#define PSI_T_LONG 74
-#define PSI_T_UNSIGNED 75
-#define PSI_T_SIGNED 76
-#define PSI_T_STATIC 77
-#define PSI_T_FUNCTION 78
-#define PSI_T_DOLLAR_NAME 79
+#define PSI_T_LSHIFT 2
+#define PSI_T_RSHIFT 3
+#define PSI_T_PLUS 4
+#define PSI_T_MINUS 5
+#define PSI_T_ASTERISK 6
+#define PSI_T_SLASH 7
+#define PSI_T_AMPERSAND 8
+#define PSI_T_CARET 9
+#define PSI_T_PIPE 10
+#define PSI_T_TEMP 11
+#define PSI_T_FREE 12
+#define PSI_T_SET 13
+#define PSI_T_LET 14
+#define PSI_T_RETURN 15
+#define PSI_T_CALLOC 16
+#define PSI_T_CALLBACK 17
+#define PSI_T_ZVAL 18
+#define PSI_T_LIB 19
+#define PSI_T_STRING 20
+#define PSI_T_COUNT 21
+#define PSI_T_BOOL 22
+#define PSI_T_INT 23
+#define PSI_T_FLOAT 24
+#define PSI_T_DOUBLE 25
+#define PSI_T_INT8 26
+#define PSI_T_UINT8 27
+#define PSI_T_INT16 28
+#define PSI_T_UINT16 29
+#define PSI_T_INT32 30
+#define PSI_T_UINT32 31
+#define PSI_T_INT64 32
+#define PSI_T_UINT64 33
+#define PSI_T_NULL 34
+#define PSI_T_NUMBER 35
+#define PSI_T_TRUE 36
+#define PSI_T_FALSE 37
+#define PSI_T_QUOTED_STRING 38
+#define PSI_T_NSNAME 39
+#define PSI_T_OBJVAL 40
+#define PSI_T_ARRVAL 41
+#define PSI_T_PATHVAL 42
+#define PSI_T_STRLEN 43
+#define PSI_T_STRVAL 44
+#define PSI_T_FLOATVAL 45
+#define PSI_T_INTVAL 46
+#define PSI_T_BOOLVAL 47
+#define PSI_T_TO_OBJECT 48
+#define PSI_T_TO_ARRAY 49
+#define PSI_T_TO_STRING 50
+#define PSI_T_TO_INT 51
+#define PSI_T_TO_FLOAT 52
+#define PSI_T_TO_BOOL 53
+#define PSI_T_VOID 54
+#define PSI_T_MIXED 55
+#define PSI_T_ARRAY 56
+#define PSI_T_OBJECT 57
+#define PSI_T_CALLABLE 58
+#define PSI_T_EOF 59
+#define PSI_T_EOS 60
+#define PSI_T_COLON 61
+#define PSI_T_LPAREN 62
+#define PSI_T_COMMA 63
+#define PSI_T_RPAREN 64
+#define PSI_T_ENUM 65
+#define PSI_T_STRUCT 66
+#define PSI_T_UNION 67
+#define PSI_T_LBRACE 68
+#define PSI_T_RBRACE 69
+#define PSI_T_EQUALS 70
+#define PSI_T_CONST 71
+#define PSI_T_TYPEDEF 72
+#define PSI_T_ELLIPSIS 73
+#define PSI_T_LBRACKET 74
+#define PSI_T_RBRACKET 75
+#define PSI_T_CHAR 76
+#define PSI_T_SHORT 77
+#define PSI_T_LONG 78
+#define PSI_T_UNSIGNED 79
+#define PSI_T_SIGNED 80
+#define PSI_T_STATIC 81
+#define PSI_T_FUNCTION 82
+#define PSI_T_DOLLAR_NAME 83
%extra_argument {struct psi_parser *P}
%syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->file.fn, P->line, "PSI syntax error: Unexpected end of input"); } }
%nonassoc NAME.
+%left LSHIFT RSHIFT.
%left PLUS MINUS.
%left ASTERISK SLASH.
%nonassoc AMPERSAND.
+%nonassoc CARET.
+%nonassoc PIPE.
%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.
%token_class const_type_token BOOL INT FLOAT STRING.
%token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.
%token_class impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.
%token_class num_exp_token NUMBER NSNAME.
-%token_class num_exp_op_token PLUS MINUS ASTERISK SLASH.
+%token_class num_exp_op_token LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH AMPERSAND CARET PIPE.
%token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT.
%token_class set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.
%token_class impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.
exp = psi_num_exp_init(PSI_T_NAME, var);
exp->token = psi_token_copy(var->token);
}
-num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). {
- exp_->op = operator_->type;
- exp_->operand = operand_;
- exp = exp_;
+num_exp(exp) ::= num_exp(exp1) num_exp_op_token(operator_) num_exp(exp2). {
+ exp = exp1;
+ do {
+ struct psi_num_exp *op = exp1;
+ while (op->operand) {
+ op = op->operand;
+ }
+ op->op = operator_->type;
+ op->operand = exp2;
+ } while(0);
free(operator_);
}
let_exp(val) ::= NULL. {
ret = psi_return_stmt_init(psi_set_exp_init(PSI_SET_FUNC, func));
ret->token = T;
}
-free_stmt(free) ::= FREE free_exps(calls) EOS. {
+free_stmt(free) ::= FREE(T) free_exps(calls) EOS. {
free = psi_free_stmt_init(calls);
+ free->token = T;
}
free_exps(calls) ::= free_exp(call). {
calls = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_free_exp_free),
struct psi_free_stmt *f = *f_ptr;
*f_ptr = NULL;
+ if (f->token) {
+ free(f->token);
+ }
psi_plist_free(f->exps);
free(f);
}
struct psi_call_frame;
struct psi_free_stmt {
+ struct psi_token *token;
struct psi_plist *exps;
};
#include "php_psi_stdinc.h"
#include "data.h"
#include "call.h"
+#include "calc.h"
#include <assert.h>
break;
case PSI_LET_NUMEXP:
- frame_sym->temp_val.zend.lval = psi_long_num_exp(val->data.num, frame);
+ {
+ impl_val res;
+ token_t val_type = psi_decl_type_get_real(val->var->arg->type)->type;
+ token_t res_type = psi_num_exp_exec(val->data.num, &res, frame);
+
+ if (val_type == res_type) {
+ frame_sym->temp_val = res;
+ } else {
+ psi_calc_cast(res_type, &res, val_type, &frame_sym->temp_val);
+ }
+ }
break;
case PSI_LET_CALLBACK:
}
}
+static inline wint_t psi_num_exp_op_tok(token_t op)
+{
+ switch (op) {
+ case PSI_T_LSHIFT:
+ return L'«';
+ case PSI_T_RSHIFT:
+ return L'»';
+ case PSI_T_PLUS:
+ return L'+';
+ case PSI_T_MINUS:
+ return L'-';
+ case PSI_T_ASTERISK:
+ return L'*';
+ case PSI_T_SLASH:
+ return L'/';
+ case PSI_T_AMPERSAND:
+ return L'&';
+ case PSI_T_CARET:
+ return L'^';
+ case PSI_T_PIPE:
+ return L'|';
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
{
while (exp) {
}
if (exp->operand) {
- char op;
-
- switch (exp->op) {
- case PSI_T_PLUS:
- op = '+';
- break;
- case PSI_T_MINUS:
- op = '-';
- break;
- case PSI_T_ASTERISK:
- op = '*';
- break;
- case PSI_T_SLASH:
- op = '/';
- break;
- default:
- assert(0);
- }
- dprintf(fd, " %c ", op);
+ dprintf(fd, " %c ", psi_num_exp_op_tok(exp->op));
}
exp = exp->operand;
if (exp->operand) {
switch (exp->op) {
+ case PSI_T_LSHIFT:
+ exp->calc = psi_calc_bin_lshift;
+ break;
+ case PSI_T_RSHIFT:
+ exp->calc = psi_calc_bin_rshift;
+ break;
case PSI_T_PLUS:
exp->calc = psi_calc_add;
break;
case PSI_T_SLASH:
exp->calc = psi_calc_div;
break;
+ case PSI_T_AMPERSAND:
+ exp->calc = psi_calc_bin_and;
+ break;
+ case PSI_T_CARET:
+ exp->calc = psi_calc_bin_xor;
+ break;
+ case PSI_T_PIPE:
+ exp->calc = psi_calc_bin_or;
+ break;
default:
data->error(data, exp->token, PSI_WARNING,
"Unknown numeric operator (%d)", exp->op);
case PSI_T_INT:
res->i64 = zend_get_constant_str(exp->data.cnst->name,
strlen(exp->data.cnst->name))->value.lval;
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi64, res->i64);
return PSI_T_INT64;
case PSI_T_FLOAT:
res->dval = zend_get_constant_str(exp->data.cnst->name,
strlen(exp->data.cnst->name))->value.dval;
+ 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);
return 0;
}
}
-static inline token_t psi_num_exp_eval_decl_var(struct psi_num_exp *exp,
- impl_val *res, struct psi_call_frame *frame)
+static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
{
- impl_val *ref;
- struct psi_call_frame_symbol *sym;
- struct psi_decl_type *real;
- 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);
-
- memcpy(res, ref, size);
-
- switch (real->type) {
+ switch (t) {
case PSI_T_INT8:
case PSI_T_UINT8:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi8, res->i8);
+ break;
case PSI_T_INT16:
case PSI_T_UINT16:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi16, res->i16);
+ break;
case PSI_T_INT32:
case PSI_T_UINT32:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi32, res->i32);
+ break;
case PSI_T_INT64:
case PSI_T_UINT64:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi64, res->i64);
+ break;
case PSI_T_FLOAT:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIfval, res->fval);
+ break;
case PSI_T_DOUBLE:
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIdval, res->dval);
break;
default:
assert(0);
}
+}
+
+static inline token_t psi_num_exp_eval_decl_var(struct psi_num_exp *exp,
+ impl_val *res, struct psi_call_frame *frame)
+{
+ impl_val *ref;
+ struct psi_call_frame_symbol *sym;
+ struct psi_decl_type *real;
+ 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);
+
+ memcpy(res, ref, size);
return real->type;
}
{
switch (exp->type) {
case PSI_T_INT64:
+ *res = exp->data.ival;
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi64, res->i64);
+ return PSI_T_INT64;
+
case PSI_T_DOUBLE:
*res = exp->data.ival;
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIdval, res->dval);
return exp->type;
case PSI_T_ENUM:
res->i64 = exp->data.enm->val;
+ if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi64, res->i64);
return PSI_T_INT64;
case PSI_T_CONST:
return 0;
}
+#include "context.h"
+
+static inline int psi_num_exp_op_cmp(token_t op1, token_t op2)
+{
+ assert(op1 >= PSI_T_LSHIFT && op2 <= PSI_T_PIPE);
+ assert(op2 >= PSI_T_LSHIFT && op2 <= PSI_T_PIPE);
+
+ switch (op1) {
+ case PSI_T_LSHIFT:
+ case PSI_T_RSHIFT:
+ return op2 > PSI_T_RSHIFT;
+
+ case PSI_T_PLUS:
+ case PSI_T_MINUS:
+ return op2 > PSI_T_MINUS ? 1 : (op2 < PSI_T_PLUS ? -1 : 0);
+
+ case PSI_T_ASTERISK:
+ case PSI_T_SLASH:
+ return op2 > PSI_T_SLASH ? 1 : (op2 < PSI_T_ASTERISK ? -1 : 0);
+
+ case PSI_T_AMPERSAND:
+ case PSI_T_CARET:
+ case PSI_T_PIPE:
+ return -1 * (op2 < PSI_T_AMPERSAND);
+ }
+
+ return 0;
+}
+
token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
struct psi_call_frame *frame)
{
impl_val num = {0};
- token_t num_type = psi_num_exp_eval(exp, &num, frame);
+ token_t num_type;
+
+ num_type = psi_num_exp_eval(exp, &num, frame);
- /* FIXME operator precedence */
if (exp->operand) {
- impl_val tmp = {0};
- token_t tmp_type = psi_num_exp_exec(exp->operand, &tmp, frame);
+ impl_val rhs;
+ token_t rhs_type, res_type;
+
+ /* only if there's a following op, and we have a higher precedence */
+ if (exp->operand->operand &&
+ psi_num_exp_op_cmp(exp->op, exp->operand->op) < 0) {
+ impl_val tmp, lhs;
+ token_t tmp_type, lhs_type;
- return exp->calc(num_type, &num, tmp_type, &tmp, res);
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %lc ", psi_num_exp_op_tok(exp->op));
+
+ tmp_type = psi_num_exp_eval(exp->operand, &tmp, frame);
+ lhs_type = exp->calc(num_type, &num, tmp_type, &tmp, &lhs);
+
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %c ", '=');
+ psi_num_exp_verify_result(lhs_type, &lhs, frame);
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %c", '\n');
+
+ rhs_type = psi_num_exp_exec(exp->operand->operand, &rhs, frame);
+ res_type = exp->operand->calc(lhs_type, &lhs, rhs_type, &rhs, res);
+ } else {
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %lc ", psi_num_exp_op_tok(exp->op));
+
+ rhs_type = psi_num_exp_exec(exp->operand, &rhs, frame);
+ res_type = exp->calc(num_type, &num, rhs_type, &rhs, res);
+ }
+
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %c ", '=');
+ psi_num_exp_verify_result(res_type, res, frame);
+ if (frame) PSI_DEBUG_PRINT(frame->context, " %c", '\n');
+
+ return res_type;
}
*res = num;
+
return num_type;
}
#include "php_psi_stdinc.h"
#include "data.h"
#include "call.h"
+#include "calc.h"
#include "marshal.h"
struct psi_set_exp *psi_set_exp_init(enum psi_set_exp_kind kind, void *data)
val->data.func->handler(zv, val, iv, frame);
break;
case PSI_SET_NUMEXP:
- psi_num_exp_exec(val->data.num, iv, frame);
- psi_set_to_int(zv, val, iv, frame);
+ switch (psi_num_exp_exec(val->data.num, iv, frame)) {
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ case PSI_T_LONG_DOUBLE:
+ psi_set_to_float(zv, val, iv, frame);
+ break;
+ default:
+ psi_set_to_int(zv, val, iv, frame);
+ break;
+ }
break;
default:
assert(0);