From: Michael Wallner Date: Thu, 1 Dec 2016 11:57:45 +0000 (+0100) Subject: num_exp: RPN calculator X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=3b0b651ea1b555d8d023e45b43e5eb93b23d00a1;p=m6w6%2Fext-psi num_exp: RPN calculator --- diff --git a/Makefile.frag b/Makefile.frag index 81aa007..e904edf 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -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) diff --git a/m4/posix/stdlib.m4 b/m4/posix/stdlib.m4 index c748eb5..a2a85be 100644 --- a/m4/posix/stdlib.m4 +++ b/m4/posix/stdlib.m4 @@ -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)]) diff --git a/psi.d/stdlib.psi b/psi.d/stdlib.psi index 6cf8e82..3545641 100644 --- a/psi.d/stdlib.psi +++ b/psi.d/stdlib.psi @@ -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 diff --git a/src/calc.c b/src/calc.c index 8bffc02..f88ab30 100644 --- a/src/calc.c +++ b/src/calc.c @@ -29,43 +29,70 @@ #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; +} diff --git a/src/calc.h b/src/calc.h index 58bab5d..d8f9e18 100644 --- a/src/calc.h +++ b/src/calc.h @@ -33,10 +33,16 @@ #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); diff --git a/src/parser.re b/src/parser.re index b64eacc..7ed6628 100644 --- a/src/parser.re +++ b/src/parser.re @@ -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);} diff --git a/src/parser_def.h b/src/parser_def.h index bfba94b..05489e7 100644 --- a/src/parser_def.h +++ b/src/parser_def.h @@ -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; } /* diff --git a/src/parser_proc.h b/src/parser_proc.h index 8d6d70c..ae6fe80 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -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 diff --git a/src/parser_proc.y b/src/parser_proc.y index cd14ad9..66d8844 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -14,22 +14,24 @@ %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*} @@ -99,6 +101,8 @@ %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); diff --git a/src/plist.c b/src/plist.c index d759b84..2c00c4a 100644 --- a/src/plist.c +++ b/src/plist.c @@ -23,12 +23,6 @@ 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; diff --git a/src/plist.h b/src/plist.h index 7c84a86..676ce41 100644 --- a/src/plist.h +++ b/src/plist.h @@ -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" diff --git a/src/token.h b/src/token.h index 68b8062..e660a0c 100644 --- a/src/token.h +++ b/src/token.h @@ -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; diff --git a/src/types.h b/src/types.h index 0c0ca49..17c0719 100644 --- a/src/types.h +++ b/src/types.h @@ -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" diff --git a/src/types/decl_enum_item.c b/src/types/decl_enum_item.c index 5f664b0..e39f0b0 100644 --- a/src/types/decl_enum_item.c +++ b/src/types/decl_enum_item.c @@ -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; } } diff --git a/src/types/num_exp.c b/src/types/num_exp.c index 88db742..65a3a5b 100644 --- a/src/types/num_exp.c +++ b/src/types/num_exp.c @@ -28,113 +28,167 @@ #include #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; } + diff --git a/src/types/num_exp.h b/src/types/num_exp.h index 8666cb8..ba44807 100644 --- a/src/types/num_exp.h +++ b/src/types/num_exp.h @@ -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 index 0000000..bed5a24 --- /dev/null +++ b/src/types/number.c @@ -0,0 +1,335 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 + +#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 index 0000000..e3d02e6 --- /dev/null +++ b/src/types/number.h @@ -0,0 +1,63 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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