From 0191ba5de11dd838f26d95bb39c5a47782a157c3 Mon Sep 17 00:00:00 2001 From: Sterling Hughes Date: Thu, 10 Apr 2003 15:43:47 +0000 Subject: [PATCH] allow expressions within constants, so the following is possible class foo { const a = 1<<0; const b = 1<<1; const c = a | b; } this makes const a compile-time expression. all other operators are unaffected. --- Zend/zend_compile.c | 54 +++++++++++++++++++++++++++++++++++++ Zend/zend_compile.h | 1 + Zend/zend_language_parser.y | 42 ++++++++++++++++++++++++----- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ec2d09bad7a..b05af5b53d7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -166,6 +166,43 @@ static zend_uint get_temporary_variable(zend_op_array *op_array) } +void zend_do_fold_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC) +{ + int (*do_op)(zval *, zval *, zval *); + zend_op *opline; + + if (op == ZEND_SL) { + do_op = shift_left_function; + } else if (op == ZEND_SR) { + do_op = shift_right_function; + } else if (op == ZEND_BW_OR) { + do_op = bitwise_or_function; + } else if (op == ZEND_BW_AND) { + do_op = bitwise_and_function; + } else if (op == ZEND_BW_XOR) { + do_op = bitwise_xor_function; + } else if (op == ZEND_CONCAT) { + do_op = concat_function; + } else if (op == ZEND_ADD) { + do_op = add_function; + } else if (op == ZEND_SUB) { + do_op = sub_function; + } else if (op == ZEND_MUL) { + do_op = mul_function; + } else if (op == ZEND_DIV) { + do_op = div_function; + } else if (op == ZEND_MOD) { + do_op = mod_function; + } else if (op == ZEND_BW_NOT) { + bitwise_not_function(&result->u.constant, &op1->u.constant); + return; + } else if (op == ZEND_BOOL_XOR) { + do_op = boolean_xor_function; + } + + do_op(&result->u.constant, &op1->u.constant, &op2->u.constant); +} + void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -2518,6 +2555,23 @@ void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_lis *result = CG(active_op_array)->opcodes[new_token->u.opline_num].op1; } +void zend_do_fold_constant(znode *result, znode *constant_name TSRMLS_DC) +{ + zval **zresult; + + if (zend_hash_find(&CG(active_class_entry)->constants_table, constant_name->u.constant.value.str.val, + constant_name->u.constant.value.str.len+1, (void **) &zresult) != SUCCESS) { + if (zend_get_constant(constant_name->u.constant.value.str.val, constant_name->u.constant.value.str.len, &result->u.constant)) { + return; + } else { + zend_error(E_COMPILE_ERROR, "Cannot find %s constant in class %s\n", + constant_name->u.constant.value.str.val, CG(active_class_entry)->name); + } + } + + result->u.constant = **zresult; + zval_copy_ctor(&result->u.constant); +} void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 1d735d3c06f..f1cfe53515d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -274,6 +274,7 @@ int zend_get_zendleng(TSRMLS_D); /* parser-driven code generators */ +void zend_do_fold_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC); void zend_do_binary_assign_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index bdc00084880..1b2d116cbbb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -332,8 +332,8 @@ namespace_var_declaration: ; namespace_const_declaration: - namespace_const_declaration ',' T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } - | T_CONST T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } + namespace_const_declaration ',' T_STRING '=' const_scalar_expr { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' const_scalar_expr { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } ; extends_from: @@ -545,8 +545,8 @@ class_variable_declaration: ; class_constant_declaration: - class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } - | T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } + class_constant_declaration ',' T_STRING '=' const_scalar_expr { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' const_scalar_expr { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } ; echo_expr_list: @@ -700,16 +700,46 @@ common_scalar: ; +const_scalar_expr: /* compile-time evaluated scalar expressions */ + const_scalar { $$ = $1; } + | const_scalar_expr_list { $$ = $1; } +; + +const_scalar_expr_list: + const_scalar_expr T_SL const_scalar_expr { zend_do_fold_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr T_SR const_scalar_expr { zend_do_fold_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr T_LOGICAL_XOR const_scalar_expr { zend_do_fold_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '|' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '&' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '^' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '.' const_scalar_expr { zend_do_fold_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '+' const_scalar_expr { zend_do_fold_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '-' const_scalar_expr { zend_do_fold_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '*' const_scalar_expr { zend_do_fold_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '/' const_scalar_expr { zend_do_fold_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '%' const_scalar_expr { zend_do_fold_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | const_scalar_expr '~' const_scalar_expr { zend_do_fold_binary_op(ZEND_BW_NOT, &$$, &$1, &$3 TSRMLS_CC); } + | '(' const_scalar_expr ')' { $$ = $2; } +; + +const_scalar: + common_scalar { $$ = $1; } + | T_STRING { zend_do_fold_constant(&$$, &$1 TSRMLS_CC); } + | '+' const_scalar { $$ = $2; } + | '-' const_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } + | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } + | class_or_namespace_constant { /* FIXME */ } +; + static_scalar: /* compile-time evaluated scalars */ common_scalar { $$ = $1; } | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); } | '+' static_scalar { $$ = $2; } - | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } + | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } | class_or_namespace_constant { /* FIXME */ } ; - scalar: T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT TSRMLS_CC); } | T_STRING_VARNAME { $$ = $1; }