num_exp: RPN calculator
authorMichael Wallner <mike@php.net>
Thu, 1 Dec 2016 11:57:45 +0000 (12:57 +0100)
committerMichael Wallner <mike@php.net>
Thu, 1 Dec 2016 11:57:45 +0000 (12:57 +0100)
18 files changed:
Makefile.frag
m4/posix/stdlib.m4
psi.d/stdlib.psi
src/calc.c
src/calc.h
src/parser.re
src/parser_def.h
src/parser_proc.h
src/parser_proc.y
src/plist.c
src/plist.h
src/token.h
src/types.h
src/types/decl_enum_item.c
src/types/num_exp.c
src/types/num_exp.h
src/types/number.c [new file with mode: 0644]
src/types/number.h [new file with mode: 0644]

index 81aa007..e904edf 100644 (file)
@@ -60,3 +60,16 @@ $(PHP_PSI_SRCDIR)/src/parser.c: $(PHP_PSI_SRCDIR)/src/parser.re
 
 $(PHP_PSI_SRCDIR)/src/types/decl.c: $(PHP_PSI_SRCDIR)/php_psi_macros.h $(PHP_PSI_SRCDIR)/php_psi_redirs.h
 $(PHP_PSI_SRCDIR)/src/context.c: $(PHP_PSI_SRCDIR)/php_psi_consts.h $(PHP_PSI_SRCDIR)/php_psi_decls.h $(PHP_PSI_SRCDIR)/php_psi_fn_decls.h $(PHP_PSI_SRCDIR)/php_psi_structs.h $(PHP_PSI_SRCDIR)/php_psi_types.h $(PHP_PSI_SRCDIR)/php_psi_unions.h $(PHP_PSI_SRCDIR)/php_psi_va_decls.h
+
+PHP_PSI_DEPEND = $(PHP_PSI_BUILDDIR)/Makefile.deps
+
+depend: psi-depend
+.PHONY: psi-depend
+psi-depend: $(PHP_PSI_DEPEND)
+
+$(PHP_PSI_DEPEND): $(PHP_PSI_SOURCES)
+       $(CC) -MM -MG $(CPPFLAGS) $(DEFS) $(INCLUDES) $^ \
+               | $(SED) -e 's/^\(.*\).o: /\1.lo: /' \
+               > $@
+
+-include $(PHP_PSI_DEPEND)
index c748eb5..a2a85be 100644 (file)
@@ -49,7 +49,7 @@ PSI_CHECK_STDLIB() {
        PSI_DECL(long nrand48, [(unsigned short xsubi@<:@3@:>@)])
        PSI_DECL(int posix_openpt, [(int flags)])
        PSI_DECL(char *ptsname, [(int fd)])
-       PSI_DECL(char *ptsname_r, [(int fd, char *buf, size_t buflen)])
+       PSI_DECL(int ptsname_r, [(int fd, char *buf, size_t buflen)])
        PSI_DECL(int putenv, [(char *var)])
        PSI_DECL(int rand, [()])
        PSI_DECL(int rand_r, [(unsigned *seed_p)])
index 6cf8e82..3545641 100644 (file)
@@ -27,10 +27,3 @@ function psi\strtold(string $str, string &$end = null) : float {
        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 8bffc02..f88ab30 100644 (file)
 #include "token.h"
 #include "calc.h"
 
-#define PSI_CALC_CAST_SET(in_type, in_val, out_val, out_var) \
+#define PSI_CALC_CAST_SET(in_type, in_val, op, 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; \
+case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
+case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
+case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
+case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
+case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
+case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
+case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
+case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
+case PSI_T_FLOAT:              (out_val)->out_var op (in_val)->fval;   break; \
+case PSI_T_DOUBLE:             (out_val)->out_var op (in_val)->dval;   break; \
+case PSI_T_LONG_DOUBLE:        (out_val)->out_var op (in_val)->ldval;  break; \
 default: \
        assert(0); \
 }
 
-#define PSI_CALC_CAST(in_type, in_val, out_type, out_val) \
+#define PSI_CALC_CAST(in_type, in_val, op, 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; \
+case PSI_T_INT8:               PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i8)             break; \
+case PSI_T_UINT8:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u8)             break; \
+case PSI_T_INT16:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i16)    break; \
+case PSI_T_UINT16:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u16)    break; \
+case PSI_T_INT32:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i32)    break; \
+case PSI_T_UINT32:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u32)    break; \
+case PSI_T_INT64:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i64)    break; \
+case PSI_T_UINT64:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u64)    break; \
+case PSI_T_FLOAT:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, fval)   break; \
+case PSI_T_DOUBLE:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, dval)   break; \
+case PSI_T_LONG_DOUBLE:        PSI_CALC_CAST_SET(in_type, in_val, op, out_val, ldval)  break; \
+default: \
+       assert(0); \
+}
+
+#define PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, out_var) \
+switch (in_type) { \
+case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
+case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
+case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
+case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
+case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
+case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
+case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
+case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
+default: \
+       assert(0); \
+}
+#define PSI_CALC_CAST_INT(in_type, in_val, op, out_type, out_val) \
+switch (out_type) { \
+case PSI_T_INT8:               PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i8)         break; \
+case PSI_T_UINT8:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u8)         break; \
+case PSI_T_INT16:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i16)        break; \
+case PSI_T_UINT16:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u16)        break; \
+case PSI_T_INT32:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i32)        break; \
+case PSI_T_UINT32:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u32)        break; \
+case PSI_T_INT64:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i64)        break; \
+case PSI_T_UINT64:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u64)        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)
+       PSI_CALC_CAST(in_type, in_val, =, out_type, out_val)
 }
 
 #if 0
@@ -268,28 +295,60 @@ PSI_CALC_FN(sub)
 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) \
+token_t psi_calc_mod(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_INT64, &i1);
+       PSI_CALC_CAST(t2, v2, =, PSI_T_INT64, &i2);
+
+       res->i64 = i1.i64 % i2.i64;
+
+       return PSI_T_INT64;
+}
+
+#define PSI_CALC_BIT_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); \
+       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)
+PSI_CALC_BIT_FN(bin_lshift)
 #undef PSI_CALC
 #define PSI_CALC(var1, var2) (var1) >> (var2)
-PSI_CALC_BIN_FN(bin_rshift)
+PSI_CALC_BIT_FN(bin_rshift)
 #undef PSI_CALC
 #define PSI_CALC(var1, var2) (var1) & (var2)
-PSI_CALC_BIN_FN(bin_and)
+PSI_CALC_BIT_FN(bin_and)
 #undef PSI_CALC
 #define PSI_CALC(var1, var2) (var1) ^ (var2)
-PSI_CALC_BIN_FN(bin_xor)
+PSI_CALC_BIT_FN(bin_xor)
 #undef PSI_CALC
 #define PSI_CALC(var1, var2) (var1) | (var2)
-PSI_CALC_BIN_FN(bin_or)
+PSI_CALC_BIT_FN(bin_or)
 #undef PSI_CALC
 
+token_t psi_calc_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       (void) t2;
+       (void) v2;
+
+       PSI_CALC_CAST(t1, v1, =!, t1, res);
+       return t1;
+}
+
+token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1;
+
+       (void) t2;
+       (void) v2;
+
+       PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1);
+       PSI_CALC_CAST_INT(t1, &i1, =~, t1, res);
+       return t1;
+}
index 58bab5d..d8f9e18 100644 (file)
 #define PRIdval "lf"
 #define PRIldval "Lf"
 
+typedef token_t (*psi_calc)(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+
 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_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+
+token_t psi_calc_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_bin_not(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);
index b64eacc..7ed6628 100644 (file)
@@ -86,7 +86,7 @@ bool psi_parser_open_string(struct psi_parser *P, const char *string, size_t len
 
 static ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
 {
-       PSI_DEBUG_PRINT(P, "PSI> Fill: n=%zu (input.type=%d)\n", n, P->input.type);
+       PSI_DEBUG_PRINT(P, "PSI< Fill: n=%zu (input.type=%d)\n", n, P->input.type);
 
        /* init if n==0 */
        if (!n) {
@@ -109,7 +109,7 @@ static ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
                        break;
                }
 
-               PSI_DEBUG_PRINT(P, "PSI> Fill: cur=%p lim=%p eof=%p\n", P->cur, P->lim, P->eof);
+               PSI_DEBUG_PRINT(P, "PSI< Fill: cur=%p lim=%p eof=%p\n", P->cur, P->lim, P->eof);
        }
 
        switch (P->input.type) {
@@ -137,14 +137,14 @@ static ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
                        if (didread < available) {
                                P->eof = P->lim;
                        }
-                       PSI_DEBUG_PRINT(P, "PSI> Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
+                       PSI_DEBUG_PRINT(P, "PSI< Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
                                        consumed, reserved, available, didread);
                }
 #endif
                break;
        }
 
-       PSI_DEBUG_PRINT(P, "PSI> Fill: avail=%td\n", P->lim - P->cur);
+       PSI_DEBUG_PRINT(P, "PSI< Fill: avail=%td\n", P->lim - P->cur);
 
        return P->lim - P->cur;
 }
@@ -204,7 +204,7 @@ void psi_parser_free(struct psi_parser **P)
 
 #define RETURN(t) do { \
        P->num = t; \
-       PSI_DEBUG_PRINT(P, "PSI> TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
+       PSI_DEBUG_PRINT(P, "PSI< TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
                                P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF, \
                                P->file.fn, P->line, P->col); \
        return t; \
@@ -257,6 +257,9 @@ token_t psi_parser_scan(struct psi_parser *P)
                "]" {RETURN(PSI_T_RBRACKET);}
                "=" {RETURN(PSI_T_EQUALS);}
                "*" {RETURN(PSI_T_ASTERISK);}
+               "~" {RETURN(PSI_T_TILDE);}
+               "!" {RETURN(PSI_T_NOT);}
+               "%" {RETURN(PSI_T_MODULO);}
                "&" {RETURN(PSI_T_AMPERSAND);}
                "+" {RETURN(PSI_T_PLUS);}
                "-" {RETURN(PSI_T_MINUS);}
index bfba94b..05489e7 100644 (file)
@@ -79,24 +79,34 @@ 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 LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH AMPERSAND CARET PIPE.)
+DEF(%token_class, number_token NUMBER NSNAME.)
+DEF(%token_class, num_exp_binary_op_token PIPE CARET AMPERSAND LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH MODULO.)
+DEF(%token_class, num_exp_unary_op_token TILDE NOT PLUS MINUS.)
 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.)
 
+DEF(%nonassoc, NAME.)
+DEF(%right, NOT TILDE.)
+DEF(%left, PIPE.)
+DEF(%left, CARET.)
+DEF(%left, AMPERSAND.)
+DEF(%left, LSHIFT RSHIFT.)
+DEF(%left, PLUS MINUS.)
+DEF(%left, ASTERISK SLASH MODULO.)
+/*
+DEF(%left, ASTERISK SLASH MODULO.)
+DEF(%left, PLUS MINUS.)
+DEF(%left, LSHIFT RSHIFT.)
+DEF(%left, AMPERSAND.)
+DEF(%left, CARET.)
+DEF(%left, PIPE.)
+*/
+DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.)
+
 TOKEN_TYPE(decl_enum, struct psi_decl_enum *)
 TOKEN_DTOR(decl_enum, psi_decl_enum_free(&$$);)
 TOKEN_TYPE(decl_enum_items, struct psi_plist*)
@@ -166,6 +176,8 @@ TOKEN_TYPE(impl_stmts, struct psi_plist*)
 TOKEN_DTOR(impl_stmts, psi_plist_free($$);)
 TOKEN_TYPE(impl_stmt, struct psi_token**)
 TOKEN_DTOR(impl_stmt, psi_impl_stmt_free(&$$);)
+TOKEN_TYPE(number, struct psi_number*)
+TOKEN_DTOR(number, psi_number_free(&$$);)
 TOKEN_TYPE(num_exp, struct psi_num_exp*)
 TOKEN_DTOR(num_exp, psi_num_exp_free(&$$);)
 TOKEN_TYPE(let_stmt, struct psi_let_stmt*)
@@ -1401,40 +1413,62 @@ PARSE_TYPED(impl_stmt, i,
 }
 
 /*
- * num_exp: num_exp_token
+ * number: number_token
  */
-PARSE_TYPED(num_exp, exp,
-               NAMED(num_exp_token, tok)) {
-       exp = psi_num_exp_init(tok->type, tok->text);
+PARSE_TYPED(number, exp,
+               NAMED(number_token, tok)) {
+       exp = psi_number_init(tok->type, tok->text);
        exp->token = tok;
 }
 
 /*
  * num_exp: decl_var
  */
-PARSE_TYPED(num_exp, exp,
+PARSE_TYPED(number, exp,
                TYPED(decl_var, var)) {
-       exp = psi_num_exp_init(PSI_T_NAME, var);
+       exp = psi_number_init(PSI_T_NAME, var);
        exp->token = psi_token_copy(var->token);
 }
 
 /*
- * num_exp: num_exp num_exp_op_token num_exp
+ * num_exp: num_exp
  */
 PARSE_TYPED(num_exp, exp,
-               TYPED(num_exp, exp1)
-               NAMED(num_exp_op_token, operator_)
-               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_);
+               TYPED(number, num)) {
+       exp = psi_num_exp_init_num(num);
+       exp->token = psi_token_copy(num->token);
+}
+
+/*
+ * num_exp: ( num_exp )
+ */
+PARSE_TYPED(num_exp, exp,
+               NAMED(LPAREN, L)
+               TYPED(num_exp, exp_)
+               TOKEN(RPAREN)) {
+       exp = psi_num_exp_init_unary(PSI_T_LPAREN, exp_);
+       exp->token = L;
+}
+
+/*
+ * num_exp: num_exp num_exp_binary_op_token num_exp
+ */
+PARSE_TYPED(num_exp, exp,
+               TYPED(num_exp, lhs_)
+               NAMED(num_exp_binary_op_token, OP)
+               TYPED(num_exp, rhs_)) {
+       exp = psi_num_exp_init_binary(OP->type, lhs_, rhs_);
+       exp->token = OP;
+}
+
+/*
+ * num_exp: num_exp_unary_op_token num_exp
+ */
+PARSE_TYPED(num_exp, exp,
+               NAMED(num_exp_unary_op_token, OP)
+               TYPED(num_exp, exp_)) {
+       exp = psi_num_exp_init_unary(OP->type, exp_);
+       exp->token = OP;
 }
 
 /*
index 8d6d70c..ae6fe80 100644 (file)
@@ -1,83 +1,86 @@
-#define PSI_T_NAME                             1
-#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
+#define PSI_T_BOOL                             1
+#define PSI_T_INT                              2
+#define PSI_T_FLOAT                            3
+#define PSI_T_STRING                           4
+#define PSI_T_DOUBLE                           5
+#define PSI_T_INT8                             6
+#define PSI_T_UINT8                            7
+#define PSI_T_INT16                            8
+#define PSI_T_UINT16                           9
+#define PSI_T_INT32                           10
+#define PSI_T_UINT32                          11
+#define PSI_T_INT64                           12
+#define PSI_T_UINT64                          13
+#define PSI_T_NAME                            14
+#define PSI_T_NULL                            15
+#define PSI_T_NUMBER                          16
+#define PSI_T_TRUE                            17
+#define PSI_T_FALSE                           18
+#define PSI_T_QUOTED_STRING                   19
+#define PSI_T_NSNAME                          20
+#define PSI_T_PIPE                            21
+#define PSI_T_CARET                           22
+#define PSI_T_AMPERSAND                       23
+#define PSI_T_LSHIFT                          24
+#define PSI_T_RSHIFT                          25
+#define PSI_T_PLUS                            26
+#define PSI_T_MINUS                           27
+#define PSI_T_ASTERISK                        28
+#define PSI_T_SLASH                           29
+#define PSI_T_MODULO                          30
+#define PSI_T_TILDE                           31
+#define PSI_T_NOT                             32
+#define PSI_T_ZVAL                            33
+#define PSI_T_OBJVAL                          34
+#define PSI_T_ARRVAL                          35
+#define PSI_T_PATHVAL                         36
+#define PSI_T_STRLEN                          37
+#define PSI_T_STRVAL                          38
+#define PSI_T_FLOATVAL                        39
+#define PSI_T_INTVAL                          40
+#define PSI_T_BOOLVAL                         41
+#define PSI_T_COUNT                           42
+#define PSI_T_TO_OBJECT                       43
+#define PSI_T_TO_ARRAY                        44
+#define PSI_T_TO_STRING                       45
+#define PSI_T_TO_INT                          46
+#define PSI_T_TO_FLOAT                        47
+#define PSI_T_TO_BOOL                         48
+#define PSI_T_VOID                            49
+#define PSI_T_MIXED                           50
+#define PSI_T_ARRAY                           51
+#define PSI_T_OBJECT                          52
+#define PSI_T_CALLABLE                        53
+#define PSI_T_TEMP                            54
+#define PSI_T_FREE                            55
+#define PSI_T_SET                             56
+#define PSI_T_LET                             57
+#define PSI_T_RETURN                          58
+#define PSI_T_CALLOC                          59
+#define PSI_T_CALLBACK                        60
+#define PSI_T_LIB                             61
+#define PSI_T_EOF                             62
+#define PSI_T_EOS                             63
+#define PSI_T_COLON                           64
+#define PSI_T_LPAREN                          65
+#define PSI_T_COMMA                           66
+#define PSI_T_RPAREN                          67
+#define PSI_T_ENUM                            68
+#define PSI_T_STRUCT                          69
+#define PSI_T_UNION                           70
+#define PSI_T_LBRACE                          71
+#define PSI_T_RBRACE                          72
+#define PSI_T_EQUALS                          73
+#define PSI_T_CONST                           74
+#define PSI_T_TYPEDEF                         75
+#define PSI_T_ELLIPSIS                        76
+#define PSI_T_LBRACKET                        77
+#define PSI_T_RBRACKET                        78
+#define PSI_T_CHAR                            79
+#define PSI_T_SHORT                           80
+#define PSI_T_LONG                            81
+#define PSI_T_UNSIGNED                        82
+#define PSI_T_SIGNED                          83
+#define PSI_T_STATIC                          84
+#define PSI_T_FUNCTION                        85
+#define PSI_T_DOLLAR_NAME                     86
index cd14ad9..66d8844 100644 (file)
 %default_destructor {(void)P;}
 %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 LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH AMPERSAND CARET PIPE.
+%token_class number_token NUMBER NSNAME.
+%token_class num_exp_binary_op_token PIPE CARET AMPERSAND LSHIFT RSHIFT PLUS MINUS ASTERISK SLASH MODULO.
+%token_class num_exp_unary_op_token TILDE NOT PLUS MINUS.
 %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.
+%nonassoc NAME.
+%right NOT TILDE.
+%left PIPE.
+%left CARET.
+%left AMPERSAND.
+%left LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left ASTERISK SLASH MODULO.
+%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.
 %type decl_enum {struct psi_decl_enum *}
 %destructor decl_enum {psi_decl_enum_free(&$$);}
 %type decl_enum_items {struct psi_plist*}
 %destructor impl_stmts {psi_plist_free($$);}
 %type impl_stmt {struct psi_token**}
 %destructor impl_stmt {psi_impl_stmt_free(&$$);}
+%type number {struct psi_number*}
+%destructor number {psi_number_free(&$$);}
 %type num_exp {struct psi_num_exp*}
 %destructor num_exp {psi_num_exp_free(&$$);}
 %type let_stmt {struct psi_let_stmt*}
@@ -699,25 +703,29 @@ impl_stmt(i) ::= set_stmt(s). {
 impl_stmt(i) ::= free_stmt(f). {
  i = (struct psi_token**) f;
 }
-num_exp(exp) ::= num_exp_token(tok). {
- exp = psi_num_exp_init(tok->type, tok->text);
+number(exp) ::= number_token(tok). {
+ exp = psi_number_init(tok->type, tok->text);
  exp->token = tok;
 }
-num_exp(exp) ::= decl_var(var). {
- exp = psi_num_exp_init(PSI_T_NAME, var);
+number(exp) ::= decl_var(var). {
+ exp = psi_number_init(PSI_T_NAME, var);
  exp->token = psi_token_copy(var->token);
 }
-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_);
+num_exp(exp) ::= number(num). {
+ exp = psi_num_exp_init_num(num);
+ exp->token = psi_token_copy(num->token);
+}
+num_exp(exp) ::= LPAREN(L) num_exp(exp_) RPAREN. {
+ exp = psi_num_exp_init_unary(PSI_T_LPAREN, exp_);
+ exp->token = L;
+}
+num_exp(exp) ::= num_exp(lhs_) num_exp_binary_op_token(OP) num_exp(rhs_). {
+ exp = psi_num_exp_init_binary(OP->type, lhs_, rhs_);
+ exp->token = OP;
+}
+num_exp(exp) ::= num_exp_unary_op_token(OP) num_exp(exp_). {
+ exp = psi_num_exp_init_unary(OP->type, exp_);
+ exp->token = OP;
 }
 let_exp(val) ::= NULL. {
  val = psi_let_exp_init(PSI_LET_NULL, NULL);
index d759b84..2c00c4a 100644 (file)
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
 #include "php_psi_stdinc.h"
 
 #include "plist.h"
@@ -37,7 +31,7 @@ struct psi_plist {
        size_t size;
        size_t count;
        void (*dtor)(void *);
-       void *list[1];
+       void *list[0];
 };
 
 #define PLIST_ELE(l, i) (((char *)(l)->list) + (l)->size * (i))
@@ -54,9 +48,14 @@ struct psi_plist *psi_plist_init(void (*dtor)(void *)) {
        return psi_plist_init_ex(0, dtor);
 }
 struct psi_plist *psi_plist_init_ex(size_t size, void (*dtor)(void *)) {
-       struct psi_plist *list = calloc(1, sizeof(*list));
+       struct psi_plist *list;
+
+       if (!size) {
+               size = sizeof(void*);
+       }
 
-       list->size = size ?: sizeof(void*);
+       list = calloc(1, sizeof(*list) + size);
+       list->size = size;
        list->dtor = dtor;
 
        return list;
@@ -76,8 +75,8 @@ size_t psi_plist_count(struct psi_plist *list) {
 }
 
 struct psi_plist *psi_plist_add(struct psi_plist *list, void *ptr) {
-       if (list->count) {
-               list = realloc(list, sizeof(*list) + list->count * list->size);
+       if (list && list->count) {
+               list = realloc(list, sizeof(*list) + list->size + list->count * list->size);
        }
        if (list) {
                PLIST_CPY(list, PLIST_ELE(list, list->count++), ptr);
@@ -94,7 +93,7 @@ bool psi_plist_get(struct psi_plist *list, size_t index, void *ptr) {
 }
 
 bool psi_plist_del(struct psi_plist *list, size_t index, void *ptr) {
-       if (list->count > index) {
+       if (list && list->count > index) {
                if (ptr) {
                        PLIST_CPY(list, ptr, PLIST_ELE(list, index));
                }
@@ -107,7 +106,7 @@ bool psi_plist_del(struct psi_plist *list, size_t index, void *ptr) {
 }
 
 bool psi_plist_shift(struct psi_plist *list, void *ptr) {
-       if (list->count) {
+       if (list && list->count) {
                if (ptr) {
                        PLIST_CPY(list, ptr, PLIST_ELE(list, 0));
                }
@@ -120,7 +119,7 @@ bool psi_plist_shift(struct psi_plist *list, void *ptr) {
 }
 
 bool psi_plist_pop(struct psi_plist *list, void *ptr) {
-       if (list->count) {
+       if (list && list->count) {
                --list->count;
                if (ptr) {
                        PLIST_CPY(list, ptr, PLIST_ELE(list, list->count));
@@ -130,6 +129,14 @@ bool psi_plist_pop(struct psi_plist *list, void *ptr) {
        return false;
 }
 
+bool psi_plist_top(struct psi_plist *list, void *ptr) {
+       if (list && list->count) {
+               PLIST_CPY(list, ptr, PLIST_ELE(list, list->count - 1));
+               return true;
+       }
+       return false;
+}
+
 
 static void swp_ptr(void *a, void *b) {
        void **_a = a, **_b = b, *_c;
index 7c84a86..676ce41 100644 (file)
@@ -41,6 +41,8 @@ bool psi_plist_get(struct psi_plist *list, size_t index, void *ptr);
 bool psi_plist_del(struct psi_plist *list, size_t index, void *ptr);
 bool psi_plist_shift(struct psi_plist *list, void *ptr);
 bool psi_plist_pop(struct psi_plist *list, void *ptr);
+bool psi_plist_top(struct psi_plist *list, void *ptr);
+#define psi_plist_bottom(l, p) psi_plist_get((l), 0, (p))
 
 #include "Zend/zend.h"
 #include "Zend/zend_sort.h"
index 68b8062..e660a0c 100644 (file)
@@ -51,6 +51,52 @@ static inline size_t psi_offset_padding(size_t diff, size_t alignment) {
 
 typedef int token_t;
 
+static inline int psi_num_exp_op_cmp(token_t op1, token_t op2)
+{
+       assert(!op1 || op1 == PSI_T_LPAREN || (op1 <= PSI_T_NOT && op1 >= PSI_T_PIPE));
+       assert(!op2 || op2 == PSI_T_LPAREN || (op2 <= PSI_T_NOT && op2 >= PSI_T_PIPE));
+
+       if (PSI_T_LPAREN == op2) {
+               return -1;
+       } else if (PSI_T_LPAREN == op1) {
+               return 1;
+       } else if (op1 == op2) {
+               return 0;
+       } else if (!op1) {
+               return 1;
+       } else if (!op2) {
+               return -1;
+       }
+
+       switch (op1) {
+       case PSI_T_PIPE:
+               return op2 > PSI_T_PIPE ? 1 : (op2 < PSI_T_PIPE ? -1 : 0);
+       case PSI_T_CARET:
+               return op2 > PSI_T_CARET ? 1 : (op2 < PSI_T_CARET ? -1 : 0);
+       case PSI_T_AMPERSAND:
+               return op2 > PSI_T_AMPERSAND ? 1 : (op2 < PSI_T_AMPERSAND ? -1 : 0);
+
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+               return op2 > PSI_T_RSHIFT ? 1 : (op2 < PSI_T_LSHIFT ? -1 : 0);
+
+       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:
+       case PSI_T_MODULO:
+               return op2 > PSI_T_MODULO ? 1 : (op2 < PSI_T_ASTERISK ? -1 : 0);
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+               return op2 > PSI_T_TILDE ? 1 : (op2 < PSI_T_NOT ? -1 : 0);
+       }
+
+       return 0;
+}
+
 static inline size_t psi_t_alignment(token_t t)
 {
 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
index 0c0ca49..17c0719 100644 (file)
@@ -42,6 +42,7 @@
 #include "types/const.h"
 #include "types/impl_arg.h"
 #include "types/impl_func.h"
+#include "types/number.h"
 #include "types/num_exp.h"
 #include "types/decl_enum_item.h"
 #include "types/decl_enum.h"
index 5f664b0..e39f0b0 100644 (file)
@@ -44,8 +44,22 @@ void psi_decl_enum_item_free(struct psi_decl_enum_item **i_ptr)
                if (i->token) {
                        free(i->token);
                }
-               if (i->num && i->num != &i->inc) {
-                       psi_num_exp_free(&i->num);
+               if (i->num) {
+                       if (i->num == &i->inc) {
+                               switch (i->inc.op) {
+                               case 0:
+                                       psi_number_free(&i->inc.data.n);
+                                       break;
+                               case PSI_T_PLUS:
+                                       psi_num_exp_free(&i->inc.data.b.lhs);
+                                       psi_num_exp_free(&i->inc.data.b.rhs);
+                                       break;
+                               default:
+                                       assert(0);
+                               }
+                       } else {
+                               psi_num_exp_free(&i->num);
+                       }
                }
                free(i->name);
                free(i);
@@ -66,14 +80,18 @@ bool psi_decl_enum_item_validate(struct psi_data *data,
 {
        if (!item->num) {
                if (seq) {
-                       item->inc.type = PSI_T_INT64;
-                       item->inc.data.ival.i64 = 1;
+                       int64_t one = 1;
+
                        item->inc.op = PSI_T_PLUS;
-                       item->inc.operand = item->prev->num ? : &item->prev->inc;
+                       item->inc.data.b.lhs = psi_num_exp_init_unary(PSI_T_LPAREN,
+                                       psi_num_exp_copy(item->prev->num));
+                       item->inc.data.b.rhs = psi_num_exp_init_num(
+                                                       psi_number_init(PSI_T_INT64, &one));
                        item->num = &item->inc;
                } else {
-                       item->inc.type = PSI_T_INT64;
-                       item->inc.data.ival.i64 = 0;
+                       int64_t nil = 0;
+
+                       item->inc.data.n = psi_number_init(PSI_T_INT64, &nil);
                        item->num = &item->inc;
                }
        }
index 88db742..65a3a5b 100644 (file)
 #include <assert.h>
 
 #include "data.h"
+#include "context.h"
 #include "call.h"
 #include "calc.h"
 
-struct psi_num_exp *psi_num_exp_init(token_t t, void *num)
+
+struct psi_num_exp *psi_num_exp_init_binary(token_t op,
+               struct psi_num_exp *lhs, struct psi_num_exp *rhs)
 {
        struct psi_num_exp *exp = calloc(1, sizeof(*exp));
 
-       switch (exp->type = t) {
-       case PSI_T_NUMBER:
-       case PSI_T_NSNAME:
-               exp->data.numb = strdup(num);
-               break;
-       case PSI_T_NAME:
-               exp->data.dvar = num;
-               break;
-       default:
-               assert(0);
-       }
+       exp->op = op;
+       exp->data.b.lhs = lhs;
+       exp->data.b.rhs = rhs;
 
        return exp;
 }
 
-struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
+struct psi_num_exp *psi_num_exp_init_unary(token_t op,
+               struct psi_num_exp *u)
 {
-       struct psi_num_exp *num = calloc(1, sizeof(*num));
+       struct psi_num_exp *exp = calloc(1, sizeof(*exp));
 
-       *num = *exp;
+       exp->op = op;
+       exp->data.u = u;
 
-       if (num->token) {
-               num->token = psi_token_copy(num->token);
-       }
-       if (num->operand) {
-               num->operand = psi_num_exp_copy(num->operand);
+       return exp;
+}
+
+struct psi_num_exp *psi_num_exp_init_num(struct psi_number *n)
+{
+       struct psi_num_exp *exp = calloc(1, sizeof(*exp));
+
+       exp->data.n = n;
+
+       return exp;
+}
+
+struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
+{
+       struct psi_num_exp *cpy;
+
+       if (!exp) {
+               return NULL;
        }
 
-       switch (num->type) {
-       case PSI_T_INT64:
-       case PSI_T_DOUBLE:
-       case PSI_T_ENUM:
-       case PSI_T_CONST:
+       cpy = malloc(sizeof(*cpy));
+       *cpy = *exp;
+
+       switch (exp->op) {
+       case 0:
+               cpy->data.n = psi_number_copy(exp->data.n);
                break;
-       case PSI_T_NUMBER:
-       case PSI_T_NSNAME:
-               num->data.numb = strdup(num->data.numb);
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       case PSI_T_LPAREN:
+               cpy->data.u = psi_num_exp_copy(exp->data.u);
                break;
-       case PSI_T_NAME:
-               num->data.dvar = psi_decl_var_copy(num->data.dvar);
+
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+       case PSI_T_MODULO:
+               cpy->data.b.lhs = psi_num_exp_copy(exp->data.b.lhs);
+               cpy->data.b.rhs = psi_num_exp_copy(exp->data.b.rhs);
                break;
+
        default:
                assert(0);
        }
-       return num;
+
+       if (exp->token) {
+               cpy->token = psi_token_copy(exp->token);
+       }
+
+       return cpy;
 }
 
-void psi_num_exp_free(struct psi_num_exp **exp_ptr)
+void psi_num_exp_free(struct psi_num_exp **c_ptr)
 {
-       if (*exp_ptr) {
-               struct psi_num_exp *exp = *exp_ptr;
+       if (*c_ptr) {
+               struct psi_num_exp *c = *c_ptr;
 
-               *exp_ptr = NULL;
-               if (exp->token) {
-                       free(exp->token);
-               }
-               switch (exp->type) {
-               case PSI_T_INT64:
-               case PSI_T_DOUBLE:
-               case PSI_T_ENUM:
-               case PSI_T_CONST:
+               *c_ptr = NULL;
+
+               switch (c->op) {
+               case 0:
+                       psi_number_free(&c->data.n);
                        break;
-               case PSI_T_NSNAME:
-               case PSI_T_NUMBER:
-                       free(exp->data.numb);
+               case PSI_T_NOT:
+               case PSI_T_TILDE:
+               case PSI_T_LPAREN:
+                       psi_num_exp_free(&c->data.u);
                        break;
-               case PSI_T_NAME:
-                       psi_decl_var_free(&exp->data.dvar);
+
+               case PSI_T_PIPE:
+               case PSI_T_CARET:
+               case PSI_T_AMPERSAND:
+               case PSI_T_LSHIFT:
+               case PSI_T_RSHIFT:
+               case PSI_T_PLUS:
+               case PSI_T_MINUS:
+               case PSI_T_ASTERISK:
+               case PSI_T_SLASH:
+               case PSI_T_MODULO:
+                       psi_num_exp_free(&c->data.b.lhs);
+                       psi_num_exp_free(&c->data.b.rhs);
                        break;
+
                default:
                        assert(0);
                }
-               if (exp->operand) {
-                       psi_num_exp_free(&exp->operand);
+
+               if (c->token) {
+                       free(c->token);
                }
-               free(exp);
+
+               free(c);
        }
 }
 
 static inline wint_t psi_num_exp_op_tok(token_t op)
 {
        switch (op) {
+       case PSI_T_NOT:
+               return L'!';
+       case PSI_T_TILDE:
+               return L'~';
+       case PSI_T_LPAREN:
+               return L'(';
+
+       case PSI_T_PIPE:
+               return L'|';
+       case PSI_T_CARET:
+               return L'^';
+       case PSI_T_AMPERSAND:
+               return L'&';
+
        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'|';
+       case PSI_T_MODULO:
+               return L'%';
+
        default:
                assert(0);
        }
@@ -143,68 +197,68 @@ static inline wint_t psi_num_exp_op_tok(token_t op)
 
 void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
 {
-       while (exp) {
-               switch (exp->type) {
-               case PSI_T_INT64:
-                       dprintf(fd, "%" PRId64, exp->data.ival.i64);
-                       break;
-               case PSI_T_DOUBLE:
-                       dprintf(fd, "%F", exp->data.ival.dval);
-                       break;
-               case PSI_T_NUMBER:
-               case PSI_T_NSNAME:
-                       dprintf(fd, "%s", exp->data.numb);
-                       break;
-               case PSI_T_CONST:
-                       dprintf(fd, "%s", exp->data.cnst->name);
-                       break;
-               case PSI_T_ENUM:
-                       dprintf(fd, "%s", exp->data.enm->name);
-                       break;
-               case PSI_T_NAME:
-                       psi_decl_var_dump(fd, exp->data.dvar);
-                       break;
-               default:
-                       assert(0);
-               }
+       switch (exp->op) {
+       case 0:
+               psi_number_dump(fd, exp->data.n);
+               break;
 
-               if (exp->operand) {
-                       dprintf(fd, " %c ", psi_num_exp_op_tok(exp->op));
-               }
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+               dprintf(fd, "%lc", psi_num_exp_op_tok(exp->op));
+               psi_num_exp_dump(fd, exp->data.u);
+               break;
 
-               exp = exp->operand;
-       }
-}
+       case PSI_T_LPAREN:
+               dprintf(fd, "(");
+               psi_num_exp_dump(fd, exp->data.u);
+               dprintf(fd, ")");
+               break;
 
-static inline bool psi_num_exp_validate_enum(struct psi_data *data, struct psi_num_exp *exp,
-               struct psi_decl_enum *enm)
-{
-       size_t i = 0;
-       struct psi_decl_enum_item *itm;
-
-       while (psi_plist_get(enm->items, i++, &itm)) {
-               if (!strcmp(itm->name, exp->data.dvar->name)) {
-                       psi_decl_var_free(&exp->data.dvar);
-                       exp->type = PSI_T_ENUM;
-                       exp->data.enm = itm;
-                       return psi_num_exp_validate(data, exp, NULL, NULL, NULL, NULL, enm);
-               }
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+               psi_num_exp_dump(fd, exp->data.b.lhs);
+               dprintf(fd, " %lc ", psi_num_exp_op_tok(exp->op));
+               psi_num_exp_dump(fd, exp->data.b.rhs);
+               break;
+
+       default:
+               assert(0);
        }
 
-       return false;
 }
 
 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
                struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
                struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
 {
-       size_t i = 0;
-       impl_val tmp = {0};
-       struct psi_const *cnst;
-       struct psi_decl_enum *enm;
-
-       if (exp->operand) {
+       if (exp->op) {
                switch (exp->op) {
+               case PSI_T_NOT:
+                       exp->calc = psi_calc_not;
+                       break;
+               case PSI_T_TILDE:
+                       exp->calc = psi_calc_bin_not;
+                       break;
+
+               case PSI_T_LPAREN:
+                       break;
+
+               case PSI_T_PIPE:
+                       exp->calc = psi_calc_bin_or;
+                       break;
+               case PSI_T_CARET:
+                       exp->calc = psi_calc_bin_xor;
+                       break;
+               case PSI_T_AMPERSAND:
+                       exp->calc = psi_calc_bin_and;
+                       break;
                case PSI_T_LSHIFT:
                        exp->calc = psi_calc_bin_lshift;
                        break;
@@ -223,88 +277,38 @@ 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;
+               case PSI_T_MODULO:
+                       exp->calc = psi_calc_mod;
                        break;
                default:
                        data->error(data, exp->token, PSI_WARNING,
                                        "Unknown numeric operator (%d)", exp->op);
                        return false;
                }
-               if (!psi_num_exp_validate(data, exp->operand, impl, cb_decl, current_let,
-                               current_set, current_enum)) {
-                       return false;
-               }
        }
 
-       switch (exp->type) {
-       case PSI_T_CONST:
-       case PSI_T_INT64:
-       case PSI_T_DOUBLE:
-       case PSI_T_ENUM:
-               return true;
+       switch (exp->op) {
+       case 0:
+               return psi_number_validate(data, exp->data.n, impl, cb_decl, current_let, current_set, current_enum);
 
-       case PSI_T_NAME:
-               if (current_enum && psi_num_exp_validate_enum(data, exp, current_enum)) {
-                       return true;
-               }
-               while (psi_plist_get(data->enums, i++, &enm)) {
-                       if (psi_num_exp_validate_enum(data, exp, enm)) {
-                               return true;
-                       }
-               }
-               if (exp->data.dvar->arg) {
-                       return true;
-               }
-               if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
-                               current_let, current_set)) {
-                       return true;
-               }
-               if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
-                       return true;
-               }
-               data->error(data, exp->token, PSI_WARNING,
-                               "Unknown variable '%s' in numeric expression",
-                               exp->data.dvar->name);
-               return false;
-
-       case PSI_T_NSNAME:
-               while (psi_plist_get(data->consts, i++, &cnst)) {
-                       if (!strcmp(cnst->name, exp->data.numb)) {
-                               free(exp->data.numb);
-                               exp->type = PSI_T_CONST;
-                               exp->data.cnst = cnst;
-                               return true;
-                       }
-               }
-               data->error(data, exp->token, PSI_WARNING,
-                               "Unknown constant '%s' in numeric expression",
-                               exp->data.numb);
-               return false;
-
-       case PSI_T_NUMBER:
-               switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) {
-               case IS_LONG:
-                       free(exp->data.numb);
-                       exp->type = PSI_T_INT64;
-                       exp->data.ival.i64 = tmp.zend.lval;
-                       return true;
-
-               case IS_DOUBLE:
-                       free(exp->data.numb);
-                       exp->type = PSI_T_DOUBLE;
-                       exp->data.ival.dval = tmp.dval;
-                       return true;
-               }
-               data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
-               return false;
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       case PSI_T_LPAREN:
+               return psi_num_exp_validate(data, exp->data.u, impl, cb_decl, current_let, current_set, current_enum);
+               break;
 
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+       case PSI_T_MODULO:
+               return psi_num_exp_validate(data, exp->data.b.lhs, impl, cb_decl, current_let, current_set, current_enum)
+                               && psi_num_exp_validate(data, exp->data.b.rhs, impl, cb_decl, current_let, current_set, current_enum);
        default:
                assert(0);
        }
@@ -312,182 +316,185 @@ bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
        return false;
 }
 
-#include "Zend/zend_constants.h"
-
-static inline token_t psi_num_exp_eval_constant(struct psi_num_exp *exp,
-               impl_val *res, struct psi_call_frame *frame)
-{
-       switch (exp->data.cnst->type->type) {
-       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 void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
+static inline void psi_impl_val_dump(token_t t, impl_val *res,
+               struct psi_call_frame *frame)
 {
        switch (t) {
        case PSI_T_INT8:
        case PSI_T_UINT8:
-               if (frame) PSI_DEBUG_PRINT(frame->context, "%" PRIi8, res->i8);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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)
+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);
-
-       return real->type;
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
+       psi_impl_val_dump(t, res, frame);
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
 }
 
-static inline token_t psi_num_exp_eval(struct psi_num_exp *exp, impl_val *res,
-               struct psi_call_frame *frame)
+static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
+               struct psi_plist **input_ptr, struct psi_call_frame *frame)
 {
-       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;
+       struct psi_plist *output = *output_ptr, *input = *input_ptr;
+       struct element {
+               token_t type;
+               union {
+                       impl_val value;
+                       psi_calc calc;
+               } data;
+       } entry;
+
+       switch (exp->op) {
+       case 0:
+               entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame);
+               output = psi_plist_add(output, &entry);
+               break;
 
-       case PSI_T_CONST:
-               return psi_num_exp_eval_constant(exp, res, frame);
+       case PSI_T_LPAREN:
+               entry.type = exp->op;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.u, &output, &input, frame);
+               while (psi_plist_pop(input, &entry)) {
+                       if (entry.type == PSI_T_LPAREN) {
+                               break;
+                       }
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
+               }
                break;
 
-       case PSI_T_NAME:
-               return psi_num_exp_eval_decl_var(exp, res, frame);
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+               while (psi_plist_top(input, &entry)) {
+                       /* bail out if exp->op >= entry.type */
+                       if (psi_num_exp_op_cmp(exp->op, entry.type) != 1) {
+                               break;
+                       }
+                       psi_plist_pop(input, NULL);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
+               }
+               entry.type = exp->op;
+               entry.data.calc = exp->calc;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.u, &output, &input, frame);
                break;
 
        default:
-               assert(0);
-       }
-       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);
+               psi_num_exp_reduce(exp->data.b.lhs, &output, &input, frame);
+               while (psi_plist_top(input, &entry)) {
+                       /* bail out if exp->op > entry.type */
+                       if (psi_num_exp_op_cmp(exp->op, entry.type) == -1) {
+                               break;
+                       }
+                       psi_plist_pop(input, NULL);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
+               }
+               entry.type = exp->op;
+               entry.data.calc = exp->calc;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.b.rhs, &output, &input, frame);
+               break;
        }
 
-       return 0;
+       *output_ptr = output;
+       *input_ptr = input;
 }
 
 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;
-
-       num_type = psi_num_exp_eval(exp, &num, frame);
-
-       if (exp->operand) {
-               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;
-
-                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc ", psi_num_exp_op_tok(exp->op));
+       struct psi_plist *output, *input;
+       struct element {
+               token_t type;
+               union {
+                       impl_val value;
+                       psi_calc calc;
+               } data;
+       } entry, lhs, rhs;
+
+       output = psi_plist_init_ex(sizeof(entry), NULL);
+       input = psi_plist_init_ex(sizeof(entry), NULL);
+
+       psi_num_exp_reduce(exp, &output, &input, frame);
+
+       while (psi_plist_pop(input, &entry)) {
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+               output = psi_plist_add(output, &entry);
+       }
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
 
-                       tmp_type = psi_num_exp_eval(exp->operand, &tmp, frame);
-                       lhs_type = exp->calc(num_type, &num, tmp_type, &tmp, &lhs);
+       while (psi_plist_shift(output, &entry)) {
+               switch (entry.type) {
+               default:
+                       input = psi_plist_add(input, &entry);
+                       break;
 
-                       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');
+               case PSI_T_NOT:
+               case PSI_T_TILDE:
+                       psi_plist_pop(input, &rhs);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+                       psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
 
-                       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));
+                       entry.type = entry.data.calc(rhs.type, &rhs.data.value, 0, NULL, &entry.data.value);
+                       input = psi_plist_add(input, &entry);
+                       psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
+                       break;
 
-                       rhs_type = psi_num_exp_exec(exp->operand, &rhs, frame);
-                       res_type = exp->calc(num_type, &num, rhs_type, &rhs, res);
+               case PSI_T_PIPE:
+               case PSI_T_CARET:
+               case PSI_T_AMPERSAND:
+               case PSI_T_LSHIFT:
+               case PSI_T_RSHIFT:
+               case PSI_T_MINUS:
+               case PSI_T_PLUS:
+               case PSI_T_ASTERISK:
+               case PSI_T_SLASH:
+               case PSI_T_MODULO:
+                       psi_plist_pop(input, &rhs);
+                       psi_plist_pop(input, &lhs);
+
+                       psi_impl_val_dump(lhs.type, &lhs.data.value, frame);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
+                       psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
+
+                       entry.type = entry.data.calc(
+                                       lhs.type, &lhs.data.value,
+                                       rhs.type, &rhs.data.value,
+                                       &entry.data.value);
+                       input = psi_plist_add(input, &entry);
+                       psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
+                       break;
                }
 
-               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;
+               if (!psi_plist_count(output)) {
+                       break;
+               }
        }
 
-       *res = num;
-
-       return num_type;
+       *res = entry.data.value;
+       return entry.type;
 }
+
index 8666cb8..ba44807 100644 (file)
@@ -23,8 +23,8 @@
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/
 
-#ifndef PSI_TYPES_NUM_EXP
-#define PSI_TYPES_NUM_EXP
+#ifndef PSI_TYPES_NUM_EXP_H
+#define PSI_TYPES_NUM_EXP_H
 
 #include "token.h"
 #include "Zend/zend_types.h"
@@ -40,24 +40,27 @@ struct psi_call_frame;
 
 struct psi_num_exp {
        struct psi_token *token;
-       token_t type;
+       token_t op;
        union {
-               char *numb;
-               impl_val ival;
-               struct psi_const *cnst;
-               struct psi_decl_var *dvar;
-               struct psi_decl_enum_item *enm;
+               struct {
+                       struct psi_num_exp *lhs;
+                       struct psi_num_exp *rhs;
+               } b;
+               struct psi_num_exp *u;
+               struct psi_number *n;
        } data;
-       token_t op;
-       struct psi_num_exp *operand;
        token_t (*calc)(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
 };
 
-struct psi_num_exp *psi_num_exp_init(token_t t, void *num);
+struct psi_num_exp *psi_num_exp_init_binary(token_t op,
+               struct psi_num_exp *lhs, struct psi_num_exp *rhs);
+struct psi_num_exp *psi_num_exp_init_unary(token_t op,
+               struct psi_num_exp *u);
+struct psi_num_exp *psi_num_exp_init_num(struct psi_number *n);
+void psi_num_exp_free(struct psi_num_exp **c_ptr);
+
 struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp);
-void psi_num_exp_free(struct psi_num_exp **exp_ptr);
 void psi_num_exp_dump(int fd, struct psi_num_exp *exp);
-
 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
                struct psi_impl *impl, struct psi_decl *cb_decl,
                struct psi_let_exp *current_let, struct psi_set_exp *current_set,
@@ -87,4 +90,5 @@ static inline zend_long psi_long_num_exp(struct psi_num_exp *exp, struct psi_cal
        return 0;
 }
 
+
 #endif
diff --git a/src/types/number.c b/src/types/number.c
new file mode 100644 (file)
index 0000000..bed5a24
--- /dev/null
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+
+#include <assert.h>
+
+#include "data.h"
+#include "calc.h"
+#include "call.h"
+
+
+struct psi_number *psi_number_init(token_t t, void *num)
+{
+       struct psi_number *exp = calloc(1, sizeof(*exp));
+
+       switch (exp->type = t) {
+       case PSI_T_INT8:
+               exp->data.ival.i64 = *(int8_t *) num;
+               break;
+       case PSI_T_UINT8:
+               exp->data.ival.i64 = *(uint8_t *) num;
+               break;
+       case PSI_T_INT16:
+               exp->data.ival.i64 = *(int16_t *) num;
+               break;
+       case PSI_T_UINT16:
+               exp->data.ival.i64 = *(uint16_t *) num;
+               break;
+       case PSI_T_INT32:
+               exp->data.ival.i64 = *(int32_t *) num;
+               break;
+       case PSI_T_UINT32:
+               exp->data.ival.i64 = *(uint32_t *) num;
+               break;
+       case PSI_T_INT64:
+               exp->data.ival.i64 = *(int64_t *) num;
+               break;
+       case PSI_T_UINT64:
+               exp->data.ival.i64 = *(uint64_t *) num;
+               break;
+       case PSI_T_FLOAT:
+               exp->data.ival.dval = *(float *) num;
+               break;
+       case PSI_T_DOUBLE:
+               exp->data.ival.dval = *(double *) num;
+               break;
+       case PSI_T_NUMBER:
+       case PSI_T_NSNAME:
+               exp->data.numb = strdup(num);
+               break;
+       case PSI_T_NAME:
+               exp->data.dvar = num;
+               break;
+       default:
+               assert(0);
+       }
+
+       return exp;
+}
+
+struct psi_number *psi_number_copy(struct psi_number *exp)
+{
+       struct psi_number *num = calloc(1, sizeof(*num));
+
+       *num = *exp;
+
+       if (num->token) {
+               num->token = psi_token_copy(num->token);
+       }
+       switch (num->type) {
+       case PSI_T_INT64:
+       case PSI_T_DOUBLE:
+       case PSI_T_ENUM:
+       case PSI_T_CONST:
+               break;
+       case PSI_T_NUMBER:
+       case PSI_T_NSNAME:
+               num->data.numb = strdup(num->data.numb);
+               break;
+       case PSI_T_NAME:
+               num->data.dvar = psi_decl_var_copy(num->data.dvar);
+               break;
+       default:
+               assert(0);
+       }
+       return num;
+}
+
+void psi_number_free(struct psi_number **exp_ptr)
+{
+       if (*exp_ptr) {
+               struct psi_number *exp = *exp_ptr;
+
+               *exp_ptr = NULL;
+               if (exp->token) {
+                       free(exp->token);
+               }
+               switch (exp->type) {
+               case PSI_T_INT64:
+               case PSI_T_DOUBLE:
+               case PSI_T_ENUM:
+               case PSI_T_CONST:
+                       break;
+               case PSI_T_NSNAME:
+               case PSI_T_NUMBER:
+                       free(exp->data.numb);
+                       break;
+               case PSI_T_NAME:
+                       psi_decl_var_free(&exp->data.dvar);
+                       break;
+               default:
+                       assert(0);
+               }
+               free(exp);
+       }
+}
+
+void psi_number_dump(int fd, struct psi_number *exp)
+{
+       switch (exp->type) {
+       case PSI_T_INT64:
+               dprintf(fd, "%" PRId64, exp->data.ival.i64);
+               break;
+       case PSI_T_DOUBLE:
+               dprintf(fd, "%F", exp->data.ival.dval);
+               break;
+       case PSI_T_NUMBER:
+       case PSI_T_NSNAME:
+               dprintf(fd, "%s", exp->data.numb);
+               break;
+       case PSI_T_CONST:
+               dprintf(fd, "%s", exp->data.cnst->name);
+               break;
+       case PSI_T_ENUM:
+               dprintf(fd, "%s", exp->data.enm->name);
+               break;
+       case PSI_T_NAME:
+               psi_decl_var_dump(fd, exp->data.dvar);
+               break;
+       default:
+               assert(0);
+       }
+}
+
+static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
+               struct psi_decl_enum *enm)
+{
+       size_t i = 0;
+       struct psi_decl_enum_item *itm;
+
+       while (psi_plist_get(enm->items, i++, &itm)) {
+               if (!strcmp(itm->name, exp->data.dvar->name)) {
+                       psi_decl_var_free(&exp->data.dvar);
+                       exp->type = PSI_T_ENUM;
+                       exp->data.enm = itm;
+                       return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
+               }
+       }
+
+       return false;
+}
+
+bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
+               struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
+               struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
+{
+       size_t i = 0;
+       impl_val tmp = {0};
+       struct psi_const *cnst;
+       struct psi_decl_enum *enm;
+
+       switch (exp->type) {
+       case PSI_T_CONST:
+       case PSI_T_INT64:
+       case PSI_T_DOUBLE:
+       case PSI_T_ENUM:
+               return true;
+
+       case PSI_T_NAME:
+               if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
+                       return true;
+               }
+               while (psi_plist_get(data->enums, i++, &enm)) {
+                       if (psi_number_validate_enum(data, exp, enm)) {
+                               return true;
+                       }
+               }
+               if (exp->data.dvar->arg) {
+                       return true;
+               }
+               if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
+                               current_let, current_set)) {
+                       return true;
+               }
+               if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
+                       return true;
+               }
+               data->error(data, exp->token, PSI_WARNING,
+                               "Unknown variable '%s' in numeric expression",
+                               exp->data.dvar->name);
+               return false;
+
+       case PSI_T_NSNAME:
+               while (psi_plist_get(data->consts, i++, &cnst)) {
+                       if (!strcmp(cnst->name, exp->data.numb)) {
+                               free(exp->data.numb);
+                               exp->type = PSI_T_CONST;
+                               exp->data.cnst = cnst;
+                               return true;
+                       }
+               }
+               data->error(data, exp->token, PSI_WARNING,
+                               "Unknown constant '%s' in numeric expression",
+                               exp->data.numb);
+               return false;
+
+       case PSI_T_NUMBER:
+               switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) {
+               case IS_LONG:
+                       free(exp->data.numb);
+                       exp->type = PSI_T_INT64;
+                       exp->data.ival.i64 = tmp.zend.lval;
+                       return true;
+
+               case IS_DOUBLE:
+                       free(exp->data.numb);
+                       exp->type = PSI_T_DOUBLE;
+                       exp->data.ival.dval = tmp.dval;
+                       return true;
+               }
+               data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
+               return false;
+
+       default:
+               assert(0);
+       }
+
+       return false;
+}
+
+#include "Zend/zend_constants.h"
+
+static inline token_t psi_number_eval_constant(struct psi_number *exp,
+               impl_val *res, struct psi_call_frame *frame)
+{
+       switch (exp->data.cnst->type->type) {
+       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_number_eval_decl_var(struct psi_number *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;
+}
+
+token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame)
+{
+       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 psi_number_eval_constant(exp, res, frame);
+               break;
+
+       case PSI_T_NAME:
+               return psi_number_eval_decl_var(exp, res, frame);
+               break;
+
+       default:
+               assert(0);
+       }
+       return 0;
+}
diff --git a/src/types/number.h b/src/types/number.h
new file mode 100644 (file)
index 0000000..e3d02e6
--- /dev/null
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_TYPES_NUMBER_H
+#define PSI_TYPES_NUMBER_H
+
+
+struct psi_data;
+struct psi_token;
+struct psi_impl;
+struct psi_const;
+struct psi_decl_enum_item;
+struct psi_let_exp;
+struct psi_set_exp;
+struct psi_call_frame;
+
+struct psi_number {
+       struct psi_token *token;
+       token_t type;
+       union {
+               char *numb;
+               impl_val ival;
+               struct psi_const *cnst;
+               struct psi_decl_var *dvar;
+               struct psi_decl_enum_item *enm;
+       } data;
+};
+
+struct psi_number *psi_number_init(token_t t, void *num);
+struct psi_number *psi_number_copy(struct psi_number *exp);
+void psi_number_free(struct psi_number **exp_ptr);
+void psi_number_dump(int fd, struct psi_number *exp);
+
+bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
+               struct psi_impl *impl, struct psi_decl *cb_decl,
+               struct psi_let_exp *current_let, struct psi_set_exp *current_set,
+               struct psi_decl_enum *current_enum);
+
+token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame);
+
+#endif