$(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)
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)])
return to_float(strtold);
set $end = to_string(*endptr);
}
-
-extern double pow(double x, double y);
-function psi\pow2() : float {
- let x = 1 | 2;
- let y = 1 << 1;
- return to_float(pow);
-}
\ No newline at end of file
#include "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
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;
+}
#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);
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) {
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) {
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;
}
#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; \
"]" {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);}
}
})
-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*)
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*)
}
/*
- * 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;
}
/*
-#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
%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*}
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);
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"
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))
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;
}
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);
}
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));
}
}
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));
}
}
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));
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;
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"
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;
#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"
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);
{
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;
}
}
#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);
}
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;
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);
}
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;
}
+
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"
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,
return 0;
}
+
#endif
--- /dev/null
+/*******************************************************************************
+ 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;
+}
--- /dev/null
+/*******************************************************************************
+ 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