Re: [PATCH] Allow constant expressions
| From: | Sterling Hughes | Date: | Tue, 08 Apr 2003 18:05:51 +0000 |
| Subject: | Re: [PATCH] Allow constant expressions | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-801@lists.php.net to get a copy of this message | ||
Ok, attached is the updated patch, the result of a conversation between
myself and Zeev.
*) Class constants are allowed to be operands to constants. However,
constants must exist within the current class only, and they must be
defined before usage, so for example:
class simple {
const second = 1;
const minute = 60 * second;
const hour = 60 * minute;
const day = 24 * hour;
}
Would work.
However:
class simple {
const minute = second * 60;
const second = 1;
}
Wouldn't, and neither would:
class simple {
const foo = "bar";
}
class simple1 {
const baz = "bar" . foo;
}
Currently, referencing the current class also doesn't work, ie,
class simple {
const bar = "baz";
const foo = simple::bar . "naz";
}
Although that could be added.
It is also important to note that const is now *fully* compile time,
therefore const cannot, for example, reference a define() which is
called above (because define() is runtime).
Also, this patch removes the ability to use operators in array
initialization, as a bunch of people seem to have found that behaviour
distasteful. Patch attached.
On Mon, 2003-04-07 at 22:43, Sterling Hughes wrote:
> I've updated my patch (attached), which allows for parentheses groupings
> such as :
>
> const foo = (1<<2) | (2 & 5);
>
> -Sterling
>
> On Mon, 2003-04-07 at 21:06, Sterling Hughes wrote:
> > Hi,
> >
> > The attached patch allows constant expressions within class variables
> > and constants. I came into this problem when I wanted the following
> > sequence:
> >
> > class foo {
> > const A = 1<<0;
> > const B = 1<<1;
> > const C = 1<<2;
> > }
> >
> > And the current parser doesn't allow such rules. I therefore added the
> > attached patch which allows operators to be used on constants within
> > these expressions (and also within array declarations). This is
> > achieved by folding statements such as '1<<0' into their equivalent
> > values at compile time. The following operators are supported: << >> |
> > & + - * / . % ^ ~ xor
> >
> > Please review it, and let me know if its ok to commit. :)
> >
> > -Sterling
--
"Nothing is particularly hard if you divide it into small jobs."
- Henry Ford
? constants.diff Index: zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.408 diff -u -r1.408 zend_compile.c --- zend_compile.c 3 Apr 2003 14:44:41 -0000 1.408 +++ zend_compile.c 8 Apr 2003 18:19:21 -0000 @@ -166,6 +166,42 @@ } +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) { + do_op = bitwise_not_function; + } 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 +2554,19 @@ *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, &zresult) != SUCCESS) { + 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) { Index: zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.235 diff -u -r1.235 zend_compile.h --- zend_compile.h 7 Apr 2003 21:48:17 -0000 1.235 +++ zend_compile.h 8 Apr 2003 18:19:22 -0000 @@ -274,6 +274,7 @@ /* 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); Index: zend_hash.c =================================================================== RCS file: /repository/ZendEngine2/zend_hash.c,v retrieving revision 1.99 diff -u -r1.99 zend_hash.c --- zend_hash.c 6 Feb 2003 00:14:49 -0000 1.99 +++ zend_hash.c 8 Apr 2003 18:19:25 -0000 @@ -1312,7 +1312,7 @@ } -#if ZEND_DEBUG +#if 1 void zend_hash_display_pListTail(HashTable *ht) { Bucket *p; Index: zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.110 diff -u -r1.110 zend_language_parser.y --- zend_language_parser.y 2 Apr 2003 16:51:49 -0000 1.110 +++ zend_language_parser.y 8 Apr 2003 18:19:27 -0000 @@ -328,12 +328,12 @@ namespace_var_declaration: T_VARIABLE { zend_do_declare_namespace_var(&$1, NULL TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); } ; 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 '=' static_scalar_expr { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar_expr { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } ; extends_from: @@ -375,8 +375,8 @@ declare_list: - T_STRING '=' static_scalar { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); } - | declare_list ',' T_STRING '=' static_scalar { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); } + T_STRING '=' static_scalar_expr { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); } + | declare_list ',' T_STRING '=' static_scalar_expr { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); } ; @@ -487,9 +487,9 @@ static_var_list: static_var_list ',' T_VARIABLE { zend_do_fetch_static_variable(&$3, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } - | static_var_list ',' T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); } + | static_var_list ',' T_VARIABLE '=' static_scalar_expr { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); } | T_VARIABLE { zend_do_fetch_static_variable(&$1, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); } ; @@ -539,14 +539,14 @@ class_variable_declaration: class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); } - | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } + | class_variable_declaration ',' T_VARIABLE '=' static_scalar_expr { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } | T_VARIABLE { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); } ; 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 '=' static_scalar_expr { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar_expr { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } ; echo_expr_list: @@ -700,15 +700,36 @@ ; +static_scalar_expr: /* compile-time evaluated scalar expressions */ + static_scalar { $$ = $1; } + | static_scalar_expr_list { $$ = $1; } +; + +static_scalar_expr_list: + static_scalar_expr T_SL static_scalar_expr { zend_do_fold_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr T_SR static_scalar_expr { zend_do_fold_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr T_LOGICAL_XOR static_scalar_expr { zend_do_fold_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '|' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '&' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '^' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '.' static_scalar_expr { zend_do_fold_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '+' static_scalar_expr { zend_do_fold_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '-' static_scalar_expr { zend_do_fold_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '*' static_scalar_expr { zend_do_fold_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '/' static_scalar_expr { zend_do_fold_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '%' static_scalar_expr { zend_do_fold_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '~' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_NOT, &$$, &$1, &$3 TSRMLS_CC); } + | '(' static_scalar_expr ')' { $$ = $2; } +; + static_scalar: /* compile-time evaluated scalars */ common_scalar { $$ = $1; } - | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); } + | T_STRING { zend_do_fold_constant(&$$, &$1 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); }
? constants.diff Index: zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.408 diff -u -r1.408 zend_compile.c --- zend_compile.c 3 Apr 2003 14:44:41 -0000 1.408 +++ zend_compile.c 8 Apr 2003 18:19:21 -0000 @@ -166,6 +166,42 @@ } +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) { + do_op = bitwise_not_function; + } 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 +2554,19 @@ *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, &zresult) != SUCCESS) { + 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) { Index: zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.235 diff -u -r1.235 zend_compile.h --- zend_compile.h 7 Apr 2003 21:48:17 -0000 1.235 +++ zend_compile.h 8 Apr 2003 18:19:22 -0000 @@ -274,6 +274,7 @@ /* 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); Index: zend_hash.c =================================================================== RCS file: /repository/ZendEngine2/zend_hash.c,v retrieving revision 1.99 diff -u -r1.99 zend_hash.c --- zend_hash.c 6 Feb 2003 00:14:49 -0000 1.99 +++ zend_hash.c 8 Apr 2003 18:19:25 -0000 @@ -1312,7 +1312,7 @@ } -#if ZEND_DEBUG +#if 1 void zend_hash_display_pListTail(HashTable *ht) { Bucket *p; Index: zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.110 diff -u -r1.110 zend_language_parser.y --- zend_language_parser.y 2 Apr 2003 16:51:49 -0000 1.110 +++ zend_language_parser.y 8 Apr 2003 18:19:27 -0000 @@ -328,12 +328,12 @@ namespace_var_declaration: T_VARIABLE { zend_do_declare_namespace_var(&$1, NULL TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); } ; 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 '=' static_scalar_expr { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar_expr { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } ; extends_from: @@ -375,8 +375,8 @@ declare_list: - T_STRING '=' static_scalar { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); } - | declare_list ',' T_STRING '=' static_scalar { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); } + T_STRING '=' static_scalar_expr { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); } + | declare_list ',' T_STRING '=' static_scalar_expr { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); } ; @@ -487,9 +487,9 @@ static_var_list: static_var_list ',' T_VARIABLE { zend_do_fetch_static_variable(&$3, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } - | static_var_list ',' T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); } + | static_var_list ',' T_VARIABLE '=' static_scalar_expr { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); } | T_VARIABLE { zend_do_fetch_static_variable(&$1, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); } ; @@ -539,14 +539,14 @@ class_variable_declaration: class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); } - | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } + | class_variable_declaration ',' T_VARIABLE '=' static_scalar_expr { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } | T_VARIABLE { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); } + | T_VARIABLE '=' static_scalar_expr { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); } ; 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 '=' static_scalar_expr { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar_expr { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } ; echo_expr_list: @@ -700,15 +700,36 @@ ; +static_scalar_expr: /* compile-time evaluated scalar expressions */ + static_scalar { $$ = $1; } + | static_scalar_expr_list { $$ = $1; } +; + +static_scalar_expr_list: + static_scalar_expr T_SL static_scalar_expr { zend_do_fold_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr T_SR static_scalar_expr { zend_do_fold_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr T_LOGICAL_XOR static_scalar_expr { zend_do_fold_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '|' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '&' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '^' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '.' static_scalar_expr { zend_do_fold_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '+' static_scalar_expr { zend_do_fold_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '-' static_scalar_expr { zend_do_fold_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '*' static_scalar_expr { zend_do_fold_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '/' static_scalar_expr { zend_do_fold_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '%' static_scalar_expr { zend_do_fold_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | static_scalar_expr '~' static_scalar_expr { zend_do_fold_binary_op(ZEND_BW_NOT, &$$, &$1, &$3 TSRMLS_CC); } + | '(' static_scalar_expr ')' { $$ = $2; } +; + static_scalar: /* compile-time evaluated scalars */ common_scalar { $$ = $1; } - | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); } + | T_STRING { zend_do_fold_constant(&$$, &$1 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); }