num_exp: bitwise ops and op precedence
authorMichael Wallner <mike@php.net>
Wed, 30 Nov 2016 09:20:28 +0000 (10:20 +0100)
committerMichael Wallner <mike@php.net>
Wed, 30 Nov 2016 09:20:28 +0000 (10:20 +0100)
16 files changed:
Makefile.frag
psi.d/glob.psi
psi.d/stdlib.psi
src/calc.c
src/calc.h
src/data.h
src/module.c
src/parser.re
src/parser_def.h
src/parser_proc.h
src/parser_proc.y
src/types/free_stmt.c
src/types/free_stmt.h
src/types/let_exp.c
src/types/num_exp.c
src/types/set_exp.c

index 5031513..81aa007 100644 (file)
@@ -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 $@
index f4a762a..5e6d215 100644 (file)
@@ -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);
 }
index bcc884d..6cf8e82 100644 (file)
@@ -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
index b1b3a74..8bffc02 100644 (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; \
 }
 
@@ -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
+
index d294cfb..58bab5d 100644 (file)
 #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
index 3c48716..5356a7e 100644 (file)
@@ -36,7 +36,7 @@
 #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)
index 28c0414..b253e0a 100644 (file)
@@ -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));
 
index ddeaacc..b64eacc 100644 (file)
@@ -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; }
index de5afe9..bfba94b 100644 (file)
@@ -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;
 }
 
 /*
index 8eba108..8d6d70c 100644 (file)
@@ -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
index f72be6e..cd14ad9 100644 (file)
 %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),
index 980b134..9b6544c 100644 (file)
@@ -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);
        }
index 1c88cfc..c0fb998 100644 (file)
@@ -32,6 +32,7 @@ struct psi_impl;
 struct psi_call_frame;
 
 struct psi_free_stmt {
+       struct psi_token *token;
        struct psi_plist *exps;
 };
 
index 1d8e2ec..a9de644 100644 (file)
@@ -26,6 +26,7 @@
 #include "php_psi_stdinc.h"
 #include "data.h"
 #include "call.h"
+#include "calc.h"
 
 #include <assert.h>
 
@@ -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:
index 7d752a3..88db742 100644 (file)
@@ -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;
 }
index ac55c3a..27ed030 100644 (file)
@@ -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);