From: Michael Wallner Date: Wed, 30 Nov 2016 09:20:28 +0000 (+0100) Subject: num_exp: bitwise ops and op precedence X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=7df12c88a4e14611a2585d6e7c994c59e8d7485a num_exp: bitwise ops and op precedence --- diff --git a/Makefile.frag b/Makefile.frag index 5031513..81aa007 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -51,7 +51,7 @@ $(PHP_PSI_SRCDIR)/src/parser_proc.y: $(PHP_PSI_SRCDIR)/src/parser_def.h $(PHP_PS 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 $@ diff --git a/psi.d/glob.psi b/psi.d/glob.psi index f4a762a..5e6d215 100644 --- a/psi.d/glob.psi +++ b/psi.d/glob.psi @@ -22,5 +22,4 @@ function psi\glob(string $pattern, int $flags, array &$glob = NULL, callable $er to_int(gl_flags), to_array(*gl_pathv, gl_pathc + gl_offs, to_string(*gl_pathv)) ); - free globfree(buf); } diff --git a/psi.d/stdlib.psi b/psi.d/stdlib.psi index bcc884d..6cf8e82 100644 --- a/psi.d/stdlib.psi +++ b/psi.d/stdlib.psi @@ -26,4 +26,11 @@ function psi\strtold(string $str, string &$end = null) : float { 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 diff --git a/src/calc.c b/src/calc.c index b1b3a74..8bffc02 100644 --- a/src/calc.c +++ b/src/calc.c @@ -24,14 +24,51 @@ *******************************************************************************/ #include "php_psi_stdinc.h" +#include #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); \ @@ -42,6 +79,10 @@ 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 @@ -209,7 +250,7 @@ break; \ } \ } \ - ZEND_ASSERT(0); \ + assert(0); \ return 0; \ } @@ -225,3 +266,30 @@ PSI_CALC_FN(sub) #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 + diff --git a/src/calc.h b/src/calc.h index d294cfb..58bab5d 100644 --- a/src/calc.h +++ b/src/calc.h @@ -29,9 +29,21 @@ #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 diff --git a/src/data.h b/src/data.h index 3c48716..5356a7e 100644 --- a/src/data.h +++ b/src/data.h @@ -36,7 +36,7 @@ #include #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) diff --git a/src/module.c b/src/module.c index 28c0414..b253e0a 100644 --- a/src/module.c +++ b/src/module.c @@ -122,18 +122,20 @@ static PHP_FUNCTION(psi_dump) 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)) { @@ -164,12 +166,13 @@ static PHP_FUNCTION(psi_validate_string) 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)) { @@ -198,15 +201,11 @@ static PHP_MINIT_FUNCTION(psi) 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; @@ -230,6 +229,13 @@ static PHP_MINIT_FUNCTION(psi) 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)); diff --git a/src/parser.re b/src/parser.re index ddeaacc..b64eacc 100644 --- a/src/parser.re +++ b/src/parser.re @@ -261,6 +261,10 @@ token_t psi_parser_scan(struct psi_parser *P) "+" {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; } diff --git a/src/parser_def.h b/src/parser_def.h index de5afe9..bfba94b 100644 --- a/src/parser_def.h +++ b/src/parser_def.h @@ -80,16 +80,19 @@ DEF(%syntax_error, { }) 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.) @@ -1419,12 +1422,18 @@ PARSE_TYPED(num_exp, exp, * 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_); } @@ -1782,10 +1791,11 @@ PARSE_TYPED(return_stmt, ret, * 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; } /* diff --git a/src/parser_proc.h b/src/parser_proc.h index 8eba108..8d6d70c 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -1,79 +1,83 @@ #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 diff --git a/src/parser_proc.y b/src/parser_proc.y index f72be6e..cd14ad9 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -15,15 +15,18 @@ %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. @@ -704,10 +707,16 @@ num_exp(exp) ::= decl_var(var). { 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. { @@ -835,8 +844,9 @@ return_stmt(ret) ::= RETURN(T) set_func(func) EOS. { 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), diff --git a/src/types/free_stmt.c b/src/types/free_stmt.c index 980b134..9b6544c 100644 --- a/src/types/free_stmt.c +++ b/src/types/free_stmt.c @@ -39,6 +39,9 @@ void psi_free_stmt_free(struct psi_free_stmt **f_ptr) struct psi_free_stmt *f = *f_ptr; *f_ptr = NULL; + if (f->token) { + free(f->token); + } psi_plist_free(f->exps); free(f); } diff --git a/src/types/free_stmt.h b/src/types/free_stmt.h index 1c88cfc..c0fb998 100644 --- a/src/types/free_stmt.h +++ b/src/types/free_stmt.h @@ -32,6 +32,7 @@ struct psi_impl; struct psi_call_frame; struct psi_free_stmt { + struct psi_token *token; struct psi_plist *exps; }; diff --git a/src/types/let_exp.c b/src/types/let_exp.c index 1d8e2ec..a9de644 100644 --- a/src/types/let_exp.c +++ b/src/types/let_exp.c @@ -26,6 +26,7 @@ #include "php_psi_stdinc.h" #include "data.h" #include "call.h" +#include "calc.h" #include @@ -258,7 +259,17 @@ void *psi_let_exp_exec(struct psi_let_exp *val, struct psi_decl_arg *darg, 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: diff --git a/src/types/num_exp.c b/src/types/num_exp.c index 7d752a3..88db742 100644 --- a/src/types/num_exp.c +++ b/src/types/num_exp.c @@ -114,6 +114,33 @@ void psi_num_exp_free(struct psi_num_exp **exp_ptr) } } +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) { @@ -142,25 +169,7 @@ void psi_num_exp_dump(int fd, struct psi_num_exp *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; @@ -196,6 +205,12 @@ bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp, 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; @@ -208,6 +223,15 @@ bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp, 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); @@ -297,46 +321,63 @@ static inline token_t psi_num_exp_eval_constant(struct psi_num_exp *exp, 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; } @@ -346,12 +387,18 @@ static inline token_t psi_num_exp_eval(struct psi_num_exp *exp, impl_val *res, { 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: @@ -368,20 +415,79 @@ static inline token_t psi_num_exp_eval(struct psi_num_exp *exp, impl_val *res, 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; } diff --git a/src/types/set_exp.c b/src/types/set_exp.c index ac55c3a..27ed030 100644 --- a/src/types/set_exp.c +++ b/src/types/set_exp.c @@ -26,6 +26,7 @@ #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) @@ -74,8 +75,16 @@ void psi_set_exp_exec_ex(struct psi_set_exp *val, zval *zv, impl_val *iv, 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);