]> granicus.if.org Git - php/commitdiff
AST stage 1.9
authorNikita Popov <nikic@php.net>
Sat, 14 Jun 2014 16:30:18 +0000 (18:30 +0200)
committerNikita Popov <nikic@php.net>
Thu, 19 Jun 2014 11:48:35 +0000 (13:48 +0200)
Expressions (mostly) use the AST

Zend/tests/bug30080.phpt
Zend/tests/bug55007.phpt
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y

index bd8401e1bed69c9afddb7d3ac0365b2bfcdf8c47..8cac75ab8d2475745d11d9132b71315afe2c7031 100644 (file)
@@ -10,9 +10,9 @@ class foo {
 
 new foo(array(new stdClass)); 
 ?>
---EXPECT--
+--EXPECTF--
 array(1) {
   [0]=>
-  object(stdClass)#2 (0) {
+  object(stdClass)#%d (0) {
   }
 }
index 12fbf120a88d43ad11ebf3542d5e0f22598d2150..425ce8f296c64cbf868b7e0ecc9a000799eed062 100644 (file)
@@ -4,7 +4,7 @@ Bug #55007 (compiler fail after previous fail)
 <?php
 
 function __autoload($classname) {
-  if ('CompileErrorClass'==$classname) eval('class CompileErrorClass { function foo() { $a[] } }');
+  if ('CompileErrorClass'==$classname) eval('class CompileErrorClass { function foo() { $a[]; } }');
   if ('MyErrorHandler'==$classname) eval('class MyErrorHandler { function __construct() { print "My error handler runs.\n"; } }');
 }
 
index 08fecd132adf68cf4c2d1d0afe4c9bc8447ce005..c89b82c84e8736668c7d6dcbe89761ffc88fcfcf 100644 (file)
@@ -55,6 +55,22 @@ typedef enum _zend_ast_kind {
 
        ZEND_AST_NAME,
        ZEND_AST_NAME_FQ,
+
+       ZEND_AST_AND,
+       ZEND_AST_OR,
+
+       ZEND_AST_GREATER,
+       ZEND_AST_GREATER_EQUAL,
+
+       ZEND_AST_CAST_NULL,
+       ZEND_AST_CAST_BOOL,
+       ZEND_AST_CAST_INT,
+       ZEND_AST_CAST_DOUBLE,
+       ZEND_AST_CAST_STRING,
+       ZEND_AST_CAST_ARRAY,
+       ZEND_AST_CAST_OBJECT,
+
+       ZEND_AST_CONDITIONAL,
 } zend_ast_kind;
 
 struct _zend_ast {
@@ -113,4 +129,7 @@ static inline zend_ast *zend_ast_create_var(zval *name) {
 #define AST_ZNODE(znode) zend_ast_create_znode((znode))
 #define AST_ZVAL(znode) zend_ast_create_constant(&(znode)->u.constant)
 
+#define AC(znode) AST_COMPILE(&znode, znode.u.ast)
+#define AZ(znode) ((znode).u.ast = AST_ZNODE(&znode))
+
 #endif
index 536b90421455db19d0d44ce3f5e1f6b6b91fae92..2e6976322589524af056617ef326661daf9d9507 100644 (file)
@@ -7654,6 +7654,25 @@ static zend_op *emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2
        return opline;
 }
 
+static zend_op *emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) {
+       zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+       opline->opcode = opcode;
+
+       SET_NODE(opline->op1, op1);
+
+       if (op2 == NULL) {
+               SET_UNUSED(opline->op2);
+       } else {
+               SET_NODE(opline->op2, op2);
+       }
+
+       opline->result_type = IS_TMP_VAR;
+       opline->result.var = get_temporary_variable(CG(active_op_array));
+       GET_NODE(result, opline->result);
+
+       return opline;
+}
+
 static zend_bool zend_is_variable(zend_ast *ast) {
        return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP
                || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL
@@ -7666,6 +7685,52 @@ static zend_bool zend_is_call(zend_ast *ast) {
                || ast->kind == ZEND_AST_STATIC_CALL;
 }
 
+static zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) {
+       zval *name;
+       int fetch_type;
+       if (name_ast->kind != ZEND_CONST) {
+               return 0;
+       }
+
+       name = zend_ast_get_zval(name_ast);
+       fetch_type = zend_get_class_fetch_type(Z_STRVAL_P(name), Z_STRLEN_P(name));
+       return fetch_type == ZEND_FETCH_CLASS_DEFAULT;
+}
+
+static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast TSRMLS_DC) {
+       znode name_node;
+       zend_op *opline;
+
+       zend_compile_expr(&name_node, name_ast TSRMLS_CC);
+
+       if (name_node.op_type == IS_CONST) {
+               zval *name = &name_node.u.constant;
+               int fetch_type = zend_get_class_fetch_type(Z_STRVAL_P(name), Z_STRLEN_P(name));
+
+               opline = emit_op(result, ZEND_FETCH_CLASS, NULL, NULL TSRMLS_CC);
+               opline->extended_value = fetch_type;
+
+               switch (fetch_type) {
+                       case ZEND_FETCH_CLASS_SELF:
+                       case ZEND_FETCH_CLASS_PARENT:
+                       case ZEND_FETCH_CLASS_STATIC:
+                               zval_ptr_dtor(name);
+                               break;
+                       default:
+                               zend_resolve_class_name(&name_node TSRMLS_CC);
+                               opline->op2_type = IS_CONST;
+                               opline->op2.constant =
+                                       zend_add_class_name_literal(CG(active_op_array), name TSRMLS_CC);
+                               break;
+               }
+       } else {
+               opline = emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node TSRMLS_CC);
+               opline->extended_value = ZEND_FETCH_CLASS_DEFAULT;
+       }
+
+       return opline;
+}
+
 static int zend_try_compile_cv(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_ast *name_ast = ast->child[0];
        if (name_ast->kind == ZEND_CONST) {
@@ -7824,18 +7889,14 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, int type TSRMLS_DC)
        zend_ast *class_ast = ast->child[0];
        zend_ast *prop_ast = ast->child[1];
 
-       znode class_name_node, class_node, prop_node;
+       znode class_node, prop_node;
        zend_op *opline;
 
-       zend_compile_expr(&class_name_node, class_ast TSRMLS_CC);
-       if (class_name_node.op_type == IS_CONST &&
-               ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(
-                       Z_STRVAL(class_name_node.u.constant), Z_STRLEN(class_name_node.u.constant))
-       ) {
-               zend_resolve_class_name(&class_name_node TSRMLS_CC);
-               class_node = class_name_node;
+       if (zend_is_const_default_class_ref(class_ast)) {
+               zend_compile_expr(&class_node, class_ast TSRMLS_CC);
+               zend_resolve_class_name(&class_node TSRMLS_CC);
        } else {
-               zend_do_fetch_class(&class_node, &class_name_node TSRMLS_CC);
+               zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
        }
 
        zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
@@ -7914,13 +7975,13 @@ void zend_ensure_writable_variable(const zend_ast *ast) {
        }
 }
 
-/* Detected $a[b]... = $a pattern */
-zend_bool zend_is_dim_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast TSRMLS_DC) {
+/* Detects $a... = $a pattern */
+zend_bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast TSRMLS_DC) {
        if (expr_ast->kind != ZEND_AST_VAR || expr_ast->child[0]->kind != ZEND_CONST) {
                return 0;
        }
 
-       while (zend_is_variable(var_ast) && !var_ast->kind == ZEND_AST_VAR) {
+       while (zend_is_variable(var_ast) && var_ast->kind != ZEND_AST_VAR) {
                var_ast = var_ast->child[0];
        }
 
@@ -7951,12 +8012,11 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) {
 
        zend_ensure_writable_variable(var_ast);
 
-       // TODO.AST handle $a[b] = $a
-       //if (zend_is_dim_assign_to_self(var_ast, expr_ast TSRMLS_CC)) {
-               //zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R TSRMLS_CC);
-       //} else {
+       if (zend_is_assign_to_self(var_ast, expr_ast TSRMLS_CC)) {
+               zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R TSRMLS_CC);
+       } else {
                zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
-       //}
+       }
 
        switch (var_ast->kind) {
                case ZEND_AST_VAR:
@@ -8030,11 +8090,9 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) {
 
        if (zend_is_call(source_ast)) {
                opline->extended_value = ZEND_RETURNS_FUNCTION;
-       }
-       // TODO.AST
-       /*if (rvar->EA & ZEND_PARSED_NEW) {
+       } else if (source_ast->kind == ZEND_NEW) {
                opline->extended_value = ZEND_RETURNS_NEW;
-       }*/
+       }
 }
 
 void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) {
@@ -8349,20 +8407,16 @@ void zend_compile_static_call(znode *result, zend_ast *ast, int type TSRMLS_DC)
        zend_ast *method_ast = ast->child[1];
        zend_ast *params_ast = ast->child[2];
 
-       znode class_name_node, class_node, method_node;
+       znode class_node, method_node;
        zend_op *opline;
        zend_ulong extended_value = 0;
 
-       zend_compile_expr(&class_name_node, class_ast TSRMLS_CC);
-       if (class_name_node.op_type == IS_CONST &&
-               ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(
-                       Z_STRVAL(class_name_node.u.constant), Z_STRLEN(class_name_node.u.constant))
-       ) {
-               zend_resolve_class_name(&class_name_node TSRMLS_CC);
-               class_node = class_name_node;
+       if (zend_is_const_default_class_ref(class_ast)) {
+               zend_compile_expr(&class_node, class_ast TSRMLS_CC);
+               zend_resolve_class_name(&class_node TSRMLS_CC);
        } else {
-               zend_do_fetch_class(&class_node, &class_name_node TSRMLS_CC);
-               extended_value = class_node.EA;
+               opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
+               extended_value = opline->extended_value;
        }
 
        zend_compile_expr(&method_node, method_ast TSRMLS_CC);
@@ -8406,6 +8460,37 @@ void zend_compile_static_call(znode *result, zend_ast *ast, int type TSRMLS_DC)
        zend_compile_call_common(result, params_ast, NULL TSRMLS_CC);
 }
 
+void zend_compile_new(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *class_ast = ast->child[0];
+       zend_ast *params_ast = ast->child[1];
+
+       znode class_node, ctor_result;
+       zend_op *opline;
+       zend_uint opnum;
+
+       zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
+
+       opnum = get_next_op_number(CG(active_op_array));
+       opline = emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC);
+       opline->extended_value = CG(context).nested_calls;
+
+       zend_compile_call_common(&ctor_result, params_ast, NULL TSRMLS_CC);
+       zend_do_free(&ctor_result TSRMLS_CC);
+
+       /* New jumps over ctor call if ctor does not exist */
+       opline = &CG(active_op_array)->opcodes[opnum];
+       opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+void zend_compile_clone(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *obj_ast = ast->child[0];
+
+       znode obj_node;
+       zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
+
+       emit_op(result, ZEND_CLONE, &obj_node, NULL TSRMLS_CC);
+}
+
 void zend_compile_global_var(zend_ast *ast TSRMLS_DC) {
        zend_ast *var_ast = ast->child[0];
 
@@ -8458,6 +8543,307 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
        }
 }
 
+void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *left_ast = ast->child[0];
+       zend_ast *right_ast = ast->child[1];
+
+       znode left_node, right_node;
+       zend_compile_expr(&left_node, left_ast TSRMLS_CC);
+       zend_compile_expr(&right_node, right_ast TSRMLS_CC);
+
+       emit_op_tmp(result, ast->kind, &left_node, &right_node TSRMLS_CC);
+}
+
+/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
+ * evaluation order. */
+void zend_compile_greater(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *left_ast = ast->child[0];
+       zend_ast *right_ast = ast->child[1];
+       znode left_node, right_node;
+
+       ZEND_ASSERT(ast->kind == ZEND_AST_GREATER || ast->kind == ZEND_AST_GREATER_EQUAL);
+
+       zend_compile_expr(&left_node, left_ast TSRMLS_CC);
+       zend_compile_expr(&right_node, right_ast TSRMLS_CC);
+
+       emit_op_tmp(result, ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL,
+               &right_node, &left_node TSRMLS_CC);
+}
+
+void zend_compile_unary_op(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+
+       znode expr_node;
+       zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+       emit_op_tmp(result, ast->kind, &expr_node, NULL TSRMLS_CC);
+}
+
+void zend_compile_unary_pm(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+       znode zero_node, expr_node;
+
+       ZEND_ASSERT(ast->kind == ZEND_UNARY_PLUS || ast->kind == ZEND_UNARY_MINUS);
+
+       zero_node.op_type = IS_CONST;
+       ZVAL_LONG(&zero_node.u.constant, 0);
+
+       zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+       emit_op_tmp(result, ast->kind == ZEND_UNARY_PLUS ? ZEND_ADD : ZEND_SUB,
+               &zero_node, &expr_node TSRMLS_CC);
+}
+
+void zend_compile_short_circuiting(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *left_ast = ast->child[0];
+       zend_ast *right_ast = ast->child[1];
+
+       znode left_node, right_node;
+       zend_op *opline_jmpz, *opline_bool;
+       zend_uint opnum_jmpz;
+
+       ZEND_ASSERT(ast->kind == ZEND_AST_AND || ast->kind == ZEND_AST_OR);
+
+       zend_compile_expr(&left_node, left_ast TSRMLS_CC);
+
+       opnum_jmpz = get_next_op_number(CG(active_op_array));
+       opline_jmpz = emit_op(NULL, ast->kind == ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX,
+               &left_node, NULL TSRMLS_CC);
+
+       if (left_node.op_type == IS_TMP_VAR) {
+               SET_NODE(opline_jmpz->result, &left_node);
+       } else {
+               opline_jmpz->result.var = get_temporary_variable(CG(active_op_array));
+               opline_jmpz->result_type = IS_TMP_VAR;
+       }
+       GET_NODE(result, opline_jmpz->result);
+
+       zend_compile_expr(&right_node, right_ast TSRMLS_CC);
+
+       opline_bool = emit_op(NULL, ZEND_BOOL, &right_node, NULL TSRMLS_CC);
+       SET_NODE(opline_bool->result, result);
+
+       opline_jmpz = &CG(active_op_array)->opcodes[opnum_jmpz];
+       opline_jmpz->op2.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+void zend_compile_post_incdec(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *var_ast = ast->child[0];
+
+       znode var_node;
+       zend_op *opline;
+
+       ZEND_ASSERT(ast->kind == ZEND_POST_INC || ast->kind == ZEND_POST_DEC);
+
+       if (var_ast->kind == ZEND_AST_PROP) {
+               opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_RW TSRMLS_CC);
+               opline->opcode = ast->kind == ZEND_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ;
+               opline->result_type = IS_TMP_VAR;
+               opline->result.var = get_temporary_variable(CG(active_op_array));
+               GET_NODE(result, opline->result);
+       } else {
+               zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
+               emit_op_tmp(result, ast->kind, &var_node, NULL TSRMLS_CC);
+       }
+}
+
+void zend_compile_pre_incdec(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *var_ast = ast->child[0];
+
+       znode var_node;
+       zend_op *opline;
+
+       ZEND_ASSERT(ast->kind == ZEND_PRE_INC || ast->kind == ZEND_PRE_DEC);
+
+       if (var_ast->kind == ZEND_AST_PROP) {
+               opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW TSRMLS_CC);
+               opline->opcode = ast->kind == ZEND_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ;
+       } else {
+               zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
+               emit_op(result, ast->kind, &var_node, NULL TSRMLS_CC);
+       }
+}
+
+void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+       znode expr_node;
+       zend_op *opline;
+
+       zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+       opline = emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
+       switch (ast->kind) {
+               case ZEND_AST_CAST_NULL:   opline->extended_value = IS_NULL; break;
+               case ZEND_AST_CAST_BOOL:   opline->extended_value = _IS_BOOL; break;
+               case ZEND_AST_CAST_INT:    opline->extended_value = IS_LONG; break;
+               case ZEND_AST_CAST_DOUBLE: opline->extended_value = IS_DOUBLE; break;
+               case ZEND_AST_CAST_STRING: opline->extended_value = IS_STRING; break;
+               case ZEND_AST_CAST_ARRAY:  opline->extended_value = IS_ARRAY; break;
+               case ZEND_AST_CAST_OBJECT: opline->extended_value = IS_OBJECT; break;
+               EMPTY_SWITCH_DEFAULT_CASE()
+       }
+}
+
+static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *cond_ast = ast->child[0];
+       zend_ast *false_ast = ast->child[2];
+
+       znode cond_node, false_node;
+       zend_op *opline_jmp_set, *opline_qm_assign;
+       zend_uint opnum_jmp_set;
+
+       ZEND_ASSERT(ast->child[1] == NULL);
+
+       zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
+
+       opnum_jmp_set = get_next_op_number(CG(active_op_array));
+       emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL TSRMLS_CC);
+
+       zend_compile_expr(&false_node, false_ast TSRMLS_CC);
+
+       opline_jmp_set = &CG(active_op_array)->opcodes[opnum_jmp_set];
+       opline_jmp_set->op2.opline_num = get_next_op_number(CG(active_op_array)) + 1;
+       if (cond_node.op_type == IS_VAR || cond_node.op_type == IS_CV
+               || false_node.op_type == IS_VAR || false_node.op_type == IS_CV
+       ) {
+               opline_jmp_set->opcode = ZEND_JMP_SET_VAR;
+               opline_jmp_set->result_type = IS_VAR;
+               GET_NODE(result, opline_jmp_set->result);
+
+               opline_qm_assign = emit_op(NULL, ZEND_QM_ASSIGN_VAR, &false_node, NULL TSRMLS_CC);
+       } else {
+               opline_qm_assign = emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC);
+       }
+       SET_NODE(opline_qm_assign->result, result);
+}
+
+void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *cond_ast = ast->child[0];
+       zend_ast *true_ast = ast->child[1];
+       zend_ast *false_ast = ast->child[2];
+
+       znode cond_node, true_node, false_node;
+       zend_op *opline_jmpz, *opline_jmp, *opline_qm_assign1, *opline_qm_assign2;
+       zend_uint opnum_jmpz, opnum_jmp, opnum_qm_assign1;
+
+       if (!true_ast) {
+               zend_compile_shorthand_conditional(result, ast TSRMLS_CC);
+               return;
+       }
+       
+       zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
+
+       opnum_jmpz = get_next_op_number(CG(active_op_array));
+       emit_op(NULL, ZEND_JMPZ, &cond_node, NULL TSRMLS_CC);
+
+       zend_compile_expr(&true_node, true_ast TSRMLS_CC);
+
+       opnum_qm_assign1 = get_next_op_number(CG(active_op_array));
+       emit_op(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC);
+
+       opnum_jmp = get_next_op_number(CG(active_op_array));
+       emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC);
+
+       opline_jmpz = &CG(active_op_array)->opcodes[opnum_jmpz];
+       opline_jmpz->op2.opline_num = get_next_op_number(CG(active_op_array));
+
+       zend_compile_expr(&false_node, false_ast TSRMLS_CC);
+
+       opline_qm_assign1 = &CG(active_op_array)->opcodes[opnum_qm_assign1];
+       if (true_node.op_type == IS_VAR || true_node.op_type == IS_CV
+               || false_node.op_type == IS_VAR || false_node.op_type == IS_CV
+       ) {
+               opline_qm_assign1->opcode = ZEND_QM_ASSIGN_VAR;
+               opline_qm_assign1->result_type = IS_VAR;
+               GET_NODE(result, opline_qm_assign1->result);
+       }
+
+       opline_qm_assign2 = emit_op(NULL, opline_qm_assign1->opcode, &false_node, NULL TSRMLS_CC);
+       SET_NODE(opline_qm_assign2->result, result);
+
+       opline_jmp = &CG(active_op_array)->opcodes[opnum_jmp];
+       opline_jmp->op1.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+void zend_compile_print(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+
+       znode expr_node;
+       zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+       emit_op_tmp(result, ZEND_PRINT, &expr_node, NULL TSRMLS_CC);
+}
+
+void zend_compile_exit(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+
+       if (expr_ast) {
+               znode expr_node;
+               zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+               emit_op(NULL, ZEND_EXIT, &expr_node, NULL TSRMLS_CC);
+       } else {
+               emit_op(NULL, ZEND_EXIT, NULL, NULL TSRMLS_CC);
+       }
+
+       result->op_type = IS_CONST;
+       ZVAL_BOOL(&result->u.constant, 1);
+}
+
+void zend_compile_yield(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *value_ast = ast->child[0];
+       zend_ast *key_ast = ast->child[1];
+
+       znode value_node, key_node;
+       znode *value_node_ptr = NULL, *key_node_ptr = NULL;
+       zend_op *opline;
+       zend_bool returns_by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+
+       if (!CG(active_op_array)->function_name) {
+               zend_error_noreturn(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
+       }
+
+       CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
+
+       if (key_ast) {
+               zend_compile_expr(&key_node, key_ast TSRMLS_CC);
+               key_node_ptr = &key_node;
+       }
+
+       if (value_ast) {
+               if (returns_by_ref && zend_is_variable(value_ast) && !zend_is_call(value_ast)) {
+                       zend_compile_var(&value_node, value_ast, BP_VAR_REF TSRMLS_CC);
+               } else {
+                       zend_compile_expr(&value_node, value_ast TSRMLS_CC);
+               }
+               value_node_ptr = &value_node;
+       }
+
+       opline = emit_op(result, ZEND_YIELD, value_node_ptr, key_node_ptr TSRMLS_CC);
+
+       if (value_ast && returns_by_ref && zend_is_call(value_ast)) {
+               opline->extended_value = ZEND_RETURNS_FUNCTION;
+       }
+}
+
+void zend_compile_instanceof(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *obj_ast = ast->child[0];
+       zend_ast *class_ast = ast->child[1];
+
+       znode obj_node, class_node;
+       zend_op *opline;
+
+       zend_compile_expr(&obj_node, obj_ast TSRMLS_CC);
+       if (obj_node.op_type == IS_CONST) {
+               zend_error_noreturn(E_COMPILE_ERROR,
+                       "instanceof expects an object instance, constant given");
+       }
+
+       opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
+       opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD;
+
+       emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC);
+}
+
 void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
        switch (ast->kind) {
                case ZEND_AST_GLOBAL:
@@ -8494,6 +8880,12 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                case ZEND_AST_ASSIGN_REF:
                        zend_compile_assign_ref(result, ast TSRMLS_CC);
                        return;
+               case ZEND_NEW:
+                       zend_compile_new(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_CLONE:
+                       zend_compile_clone(result, ast TSRMLS_CC);
+                       return;
                case ZEND_ASSIGN_ADD:
                case ZEND_ASSIGN_SUB:
                case ZEND_ASSIGN_MUL:
@@ -8508,6 +8900,75 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                case ZEND_ASSIGN_SR:
                        zend_compile_compound_assign(result, ast TSRMLS_CC);
                        return;
+               case ZEND_BOOL_XOR:
+               case ZEND_BW_OR:
+               case ZEND_BW_AND:
+               case ZEND_BW_XOR:
+               case ZEND_CONCAT:
+               case ZEND_ADD:
+               case ZEND_SUB:
+               case ZEND_MUL:
+               case ZEND_POW:
+               case ZEND_DIV:
+               case ZEND_MOD:
+               case ZEND_SL:
+               case ZEND_SR:
+               case ZEND_IS_IDENTICAL:
+               case ZEND_IS_NOT_IDENTICAL:
+               case ZEND_IS_EQUAL:
+               case ZEND_IS_NOT_EQUAL:
+               case ZEND_IS_SMALLER:
+               case ZEND_IS_SMALLER_OR_EQUAL:
+                       zend_compile_binary_op(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_GREATER:
+               case ZEND_AST_GREATER_EQUAL:
+                       zend_compile_greater(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_BOOL_NOT:
+               case ZEND_BW_NOT:
+                       zend_compile_unary_op(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_UNARY_PLUS:
+               case ZEND_UNARY_MINUS:
+                       zend_compile_unary_pm(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_AND:
+               case ZEND_AST_OR:
+                       zend_compile_short_circuiting(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_POST_INC:
+               case ZEND_POST_DEC:
+                       zend_compile_post_incdec(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_PRE_INC:
+               case ZEND_PRE_DEC:
+                       zend_compile_pre_incdec(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_CAST_NULL:
+               case ZEND_AST_CAST_BOOL:
+               case ZEND_AST_CAST_INT:
+               case ZEND_AST_CAST_DOUBLE:
+               case ZEND_AST_CAST_STRING:
+               case ZEND_AST_CAST_ARRAY:
+               case ZEND_AST_CAST_OBJECT:
+                       zend_compile_cast(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_CONDITIONAL:
+                       zend_compile_conditional(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_PRINT:
+                       zend_compile_print(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_EXIT:
+                       zend_compile_exit(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_YIELD:
+                       zend_compile_yield(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_INSTANCEOF:
+                       zend_compile_instanceof(result, ast TSRMLS_CC);
+                       return;
                default:
                        ZEND_ASSERT(0 /* not supported */);
        }
index 7fb428f15a6571bfb6d038cb4554542fc33adbbe..f814288ccdfee0dcbc3dd0c825ce3e45c5337fd6 100644 (file)
@@ -99,6 +99,7 @@ static inline znode *zend_ast_get_znode(zend_ast *ast) {
        return &((zend_ast_znode *) ast)->node;
 }
 
+void zend_ensure_writable_variable(const zend_ast *ast);
 void zend_compile_stmt(zend_ast *ast TSRMLS_DC);
 void zend_compile_expr(znode *node, zend_ast *ast TSRMLS_DC);
 void zend_compile_var(znode *node, zend_ast *ast, int type TSRMLS_DC);
index 77508e048ec4648859c70fcdc0dda5c7352f89b9..b086c478242eabcfad474a60bfd1059031c9ccba 100644 (file)
@@ -326,25 +326,25 @@ unticked_statement:
                        for_statement { zend_do_for_end(&$7 TSRMLS_CC); }
        |       T_SWITCH parenthesis_expr       { zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); }
        |       T_BREAK ';'                             { zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); }
-       |       T_BREAK expr ';'                { zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
+       |       T_BREAK expr ';'                { AC($2); zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
        |       T_CONTINUE ';'                  { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
-       |       T_CONTINUE expr ';'             { zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); }
+       |       T_CONTINUE expr ';'             { AC($2); zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); }
        |       T_RETURN ';'                                            { zend_do_return(NULL, 0 TSRMLS_CC); }
-       |       T_RETURN expr_without_variable ';'      { zend_do_return(&$2, 0 TSRMLS_CC); }
+       |       T_RETURN expr_without_variable ';'      { AC($2); zend_do_return(&$2, 0 TSRMLS_CC); }
        |       T_RETURN variable ';'                           { zend_do_return(&$2, 1 TSRMLS_CC); }
-       |       yield_expr ';' { zend_do_free(&$1 TSRMLS_CC); }
+       |       yield_expr ';' { AC($1); zend_do_free(&$1 TSRMLS_CC); }
        |       T_GLOBAL global_var_list ';'
        |       T_STATIC static_var_list ';'
        |       T_ECHO echo_expr_list ';'
        |       T_INLINE_HTML                   { zend_do_echo(&$1 TSRMLS_CC); }
-       |       expr ';'                                { zend_do_free(&$1 TSRMLS_CC); }
+       |       expr ';'                                { AC($1); zend_do_free(&$1 TSRMLS_CC); }
        |       T_UNSET '(' unset_variables ')' ';'
        |       T_FOREACH '(' variable T_AS
                { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 1 TSRMLS_CC); }
                foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
                foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
        |       T_FOREACH '(' expr_without_variable T_AS
-               { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); }
+               { AC($3); zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); }
                foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
                foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
        |       T_DECLARE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
@@ -352,7 +352,7 @@ unticked_statement:
        |       T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
                catch_statement { zend_do_bind_catch(&$1, &$6 TSRMLS_CC); }
                finally_statement { zend_do_end_finally(&$1, &$6, &$8 TSRMLS_CC); }
-       |       T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
+       |       T_THROW expr ';' { AC($2); zend_do_throw(&$2 TSRMLS_CC); }
        |       T_GOTO T_STRING ';' { zend_do_goto(&$2 TSRMLS_CC); }
 ;
 
@@ -509,7 +509,7 @@ switch_case_list:
 
 case_list:
                /* empty */     { $$.op_type = IS_UNUSED; }
-       |       case_list T_CASE expr case_separator { zend_do_extended_info(TSRMLS_C);  zend_do_case_before_statement(&$1, &$2, &$3 TSRMLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 TSRMLS_CC); $$.op_type = IS_CONST; }
+       |       case_list T_CASE expr case_separator { AC($3); zend_do_extended_info(TSRMLS_C);  zend_do_case_before_statement(&$1, &$2, &$3 TSRMLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 TSRMLS_CC); $$.op_type = IS_CONST; }
        |       case_list T_DEFAULT case_separator { zend_do_extended_info(TSRMLS_C);  zend_do_default_before_statement(&$1, &$2 TSRMLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 TSRMLS_CC); $$.op_type = IS_CONST; }
 ;
 
@@ -577,47 +577,27 @@ optional_class_type:
        |       fully_qualified_class_name                      { $$ = $1; }
 ;
 
-
 function_call_parameter_list:
-               '(' ')' { Z_LVAL($$.u.constant) = 0; }
-       |       '(' non_empty_function_call_parameter_list ')'  { $$ = $2; }
-       |       '(' yield_expr ')'      { zend_do_pass_param(&$2, ZEND_SEND_VAL TSRMLS_CC); }
-;
-
-
-non_empty_function_call_parameter_list:
-               function_call_parameter
-       |       non_empty_function_call_parameter_list ',' function_call_parameter
-;
-
-function_call_parameter:
-               expr_without_variable   { zend_do_pass_param(&$1, ZEND_SEND_VAL TSRMLS_CC); }
-       |       variable                                { zend_do_pass_param(&$1, ZEND_SEND_VAR TSRMLS_CC); }
-       |       '&' w_variable                  { zend_do_pass_param(&$2, ZEND_SEND_REF TSRMLS_CC); }
-       |       T_ELLIPSIS expr                 { zend_do_unpack_params(&$2 TSRMLS_CC); }
-;
-
-function_call_parameter_list_ast:
                '(' ')' { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_PARAMS); }
-       |       '(' non_empty_function_call_parameter_list_ast ')'      { $$.u.ast = $2.u.ast; }
+       |       '(' non_empty_function_call_parameter_list ')' { $$.u.ast = $2.u.ast; }
        |       '(' yield_expr ')'
                        { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_PARAMS);
-                         zend_ast_dynamic_add(&$$.u.ast, AST_ZNODE(&$2)); }
+                         zend_ast_dynamic_add(&$$.u.ast, $2.u.ast); }
 ;
 
-non_empty_function_call_parameter_list_ast:
-               function_call_parameter_ast
+non_empty_function_call_parameter_list:
+               function_call_parameter
                        { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_PARAMS);
                          zend_ast_dynamic_add(&$$.u.ast, $1.u.ast); }
-       |       non_empty_function_call_parameter_list_ast ',' function_call_parameter_ast
+       |       non_empty_function_call_parameter_list ',' function_call_parameter
                        { zend_ast_dynamic_add(&$1.u.ast, $3.u.ast); $$.u.ast = $1.u.ast; }
 ;
 
-function_call_parameter_ast:
-               expr_without_variable   { $$.u.ast = AST_ZNODE(&$1); }
+function_call_parameter:
+               expr_without_variable   { $$.u.ast = $1.u.ast; }
        |       variable                                { $$.u.ast = $1.u.ast; }
        |       '&' w_variable                  { /* ERROR */ ZEND_ASSERT(0); }
-       |       T_ELLIPSIS expr                 { $$.u.ast = zend_ast_create_unary(ZEND_AST_UNPACK, AST_ZNODE(&$2)); }
+       |       T_ELLIPSIS expr                 { $$.u.ast = zend_ast_create_unary(ZEND_AST_UNPACK, $2.u.ast); }
 ;
 
 global_var_list:
@@ -754,8 +734,8 @@ class_constant_declaration:
 ;
 
 echo_expr_list:
-               echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
-       |       expr                                    { zend_do_echo(&$1 TSRMLS_CC); }
+               echo_expr_list ',' expr { AC($3); zend_do_echo(&$3 TSRMLS_CC); }
+       |       expr                                    { AC($1); zend_do_echo(&$1 TSRMLS_CC); }
 ;
 
 
@@ -765,130 +745,132 @@ for_expr:
 ;
 
 non_empty_for_expr:
-               non_empty_for_expr ','  { zend_do_free(&$1 TSRMLS_CC); } expr { $$ = $4; }
-       |       expr                                    { $$ = $1; }
+               non_empty_for_expr ','  { zend_do_free(&$1 TSRMLS_CC); } expr { AC($4); $$ = $4; }
+       |       expr                                    { AC($1); $$ = $1; }
 ;
 
 new_expr:
-               T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+               T_NEW class_name_reference ctor_arguments
+                       { $$.u.ast = zend_ast_create_binary(ZEND_NEW, $2.u.ast, $3.u.ast); }
 ;
 
 expr_without_variable:
                T_LIST '(' assignment_list ')' '=' expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN, $3.u.ast, AST_ZNODE(&$6));
-                         AST_COMPILE(&$$, $$.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN, $3.u.ast, $6.u.ast); }
        |       variable '=' expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $$.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN, $1.u.ast, $3.u.ast); }
        |       variable '=' '&' variable
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN_REF, $1.u.ast, $4.u.ast);
-                         AST_COMPILE(&$$, $$.u.ast); }
-       |       variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated");  zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); }
-       |       T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN_REF, $1.u.ast, $4.u.ast); }
+       |       variable '=' '&' T_NEW class_name_reference ctor_arguments
+                       { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated");
+                         $$.u.ast = zend_ast_create_binary(ZEND_AST_ASSIGN_REF, $1.u.ast,
+                             zend_ast_create_binary(ZEND_NEW, $5.u.ast, $6.u.ast)); }
+       |       T_CLONE expr { $$.u.ast = zend_ast_create_unary(ZEND_CLONE, $2.u.ast); }
        |       variable T_PLUS_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_ADD, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_ADD, $1.u.ast, $3.u.ast); }
        |       variable T_MINUS_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SUB, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SUB, $1.u.ast, $3.u.ast); }
        |       variable T_MUL_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MUL, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MUL, $1.u.ast, $3.u.ast); }
        |       variable T_POW_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_POW, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_POW, $1.u.ast, $3.u.ast); }
        |       variable T_DIV_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_DIV, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_DIV, $1.u.ast, $3.u.ast); }
        |       variable T_CONCAT_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_CONCAT, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_CONCAT, $1.u.ast, $3.u.ast); }
        |       variable T_MOD_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MOD, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MOD, $1.u.ast, $3.u.ast); }
        |       variable T_AND_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_AND, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_AND, $1.u.ast, $3.u.ast); }
        |       variable T_OR_EQUAL expr 
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_OR, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_OR, $1.u.ast, $3.u.ast); }
        |       variable T_XOR_EQUAL expr 
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_XOR, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_XOR, $1.u.ast, $3.u.ast); }
        |       variable T_SL_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SL, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SL, $1.u.ast, $3.u.ast); }
        |       variable T_SR_EQUAL expr
-                       { $2.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SR, $1.u.ast, AST_ZNODE(&$3));
-                         AST_COMPILE(&$$, $2.u.ast); }
-       |       rw_variable T_INC { zend_do_post_incdec(&$$, &$1, ZEND_POST_INC TSRMLS_CC); }
-       |       T_INC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC TSRMLS_CC); }
-       |       rw_variable T_DEC { zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC TSRMLS_CC); }
-       |       T_DEC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_DEC TSRMLS_CC); }
-       |       expr T_BOOLEAN_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
-       |       expr T_BOOLEAN_AND { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
-       |       expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
-       |       expr T_LOGICAL_AND { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
-       |       expr T_LOGICAL_XOR expr { zend_do_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '|' expr   { zend_do_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '&' expr   { zend_do_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '^' expr   { zend_do_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '.' expr   { zend_do_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '+' expr   { zend_do_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '-' expr   { zend_do_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '*' expr   { zend_do_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_POW expr { zend_do_binary_op(ZEND_POW, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '/' expr   { zend_do_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '%' expr   { zend_do_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_SL expr  { zend_do_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_SR expr  { zend_do_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); }
-       |       '+' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; zend_do_binary_op(ZEND_ADD, &$$, &$1, &$2 TSRMLS_CC); } }
-       |       '-' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; zend_do_binary_op(ZEND_SUB, &$$, &$1, &$2 TSRMLS_CC); } }
-       |       '!' expr { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$2 TSRMLS_CC); }
-       |       '~' expr { zend_do_unary_op(ZEND_BW_NOT, &$$, &$2 TSRMLS_CC); }
-       |       expr T_IS_IDENTICAL expr                { zend_do_binary_op(ZEND_IS_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_IS_NOT_IDENTICAL expr    { zend_do_binary_op(ZEND_IS_NOT_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_IS_EQUAL expr                    { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_IS_NOT_EQUAL expr                { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '<' expr                                   { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }
-       |       expr '>' expr                                   { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }
-       |       expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); }
-       |       expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); }
-       |       parenthesis_expr        { $$ = $1; }
-       |       new_expr                { $$ = $1; }
-       |       expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); }
-               expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); }
-               expr     { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); }
-       |       expr '?' ':' { zend_do_jmp_set(&$1, &$2, &$3 TSRMLS_CC); }
-               expr     { zend_do_jmp_set_else(&$$, &$5, &$2, &$3 TSRMLS_CC); }
-       |       internal_functions_in_yacc { $$ = $1; }
-       |       T_INT_CAST expr         { zend_do_cast(&$$, &$2, IS_LONG TSRMLS_CC); }
-       |       T_DOUBLE_CAST expr      { zend_do_cast(&$$, &$2, IS_DOUBLE TSRMLS_CC); }
-       |       T_STRING_CAST expr      { zend_do_cast(&$$, &$2, IS_STRING TSRMLS_CC); }
-       |       T_ARRAY_CAST expr       { zend_do_cast(&$$, &$2, IS_ARRAY TSRMLS_CC); }
-       |       T_OBJECT_CAST expr      { zend_do_cast(&$$, &$2, IS_OBJECT TSRMLS_CC); }
-       |       T_BOOL_CAST expr        { zend_do_cast(&$$, &$2, _IS_BOOL TSRMLS_CC); }
-       |       T_UNSET_CAST expr       { zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC); }
-       |       T_EXIT exit_expr        { zend_do_exit(&$$, &$2 TSRMLS_CC); }
-       |       '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; }
-       |       scalar                          { $$ = $1; }
-       |       '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
-       |       T_PRINT expr  { zend_do_print(&$$, &$2 TSRMLS_CC); }
-       |       T_YIELD { zend_do_yield(&$$, NULL, NULL, 0 TSRMLS_CC); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SR, $1.u.ast, $3.u.ast); }
+       |       variable T_INC { $$.u.ast = zend_ast_create_unary(ZEND_POST_INC, $1.u.ast); }
+       |       T_INC variable { $$.u.ast = zend_ast_create_unary(ZEND_PRE_INC, $2.u.ast); }
+       |       variable T_DEC { $$.u.ast = zend_ast_create_unary(ZEND_POST_DEC, $1.u.ast); }
+       |       T_DEC variable { $$.u.ast = zend_ast_create_unary(ZEND_PRE_DEC, $2.u.ast); }
+       |       expr T_BOOLEAN_OR expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_OR, $1.u.ast, $3.u.ast); }
+       |       expr T_BOOLEAN_AND expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
+       |       expr T_LOGICAL_OR expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_OR, $1.u.ast, $3.u.ast); }
+       |       expr T_LOGICAL_AND expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
+       |       expr T_LOGICAL_XOR expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_BOOL_XOR, $1.u.ast, $3.u.ast); }
+       |       expr '|' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_OR, $1.u.ast, $3.u.ast); }
+       |       expr '&' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_AND, $1.u.ast, $3.u.ast); }
+       |       expr '^' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_XOR, $1.u.ast, $3.u.ast); }
+       |       expr '.' expr   { $$.u.ast = zend_ast_create_binary(ZEND_CONCAT, $1.u.ast, $3.u.ast); }
+       |       expr '+' expr   { $$.u.ast = zend_ast_create_binary(ZEND_ADD, $1.u.ast, $3.u.ast); }
+       |       expr '-' expr   { $$.u.ast = zend_ast_create_binary(ZEND_SUB, $1.u.ast, $3.u.ast); }
+       |       expr '*' expr   { $$.u.ast = zend_ast_create_binary(ZEND_MUL, $1.u.ast, $3.u.ast); }
+       |       expr T_POW expr { $$.u.ast = zend_ast_create_binary(ZEND_POW, $1.u.ast, $3.u.ast); }
+       |       expr '/' expr   { $$.u.ast = zend_ast_create_binary(ZEND_DIV, $1.u.ast, $3.u.ast); }
+       |       expr '%' expr   { $$.u.ast = zend_ast_create_binary(ZEND_MOD, $1.u.ast, $3.u.ast); }
+       |       expr T_SL expr  { $$.u.ast = zend_ast_create_binary(ZEND_SL, $1.u.ast, $3.u.ast); }
+       |       expr T_SR expr  { $$.u.ast = zend_ast_create_binary(ZEND_SR, $1.u.ast, $3.u.ast); }
+       |       '+' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_PLUS, $2.u.ast); }
+       |       '-' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_MINUS, $2.u.ast); }
+       |       '!' expr { $$.u.ast = zend_ast_create_unary(ZEND_BOOL_NOT, $2.u.ast); }
+       |       '~' expr { $$.u.ast = zend_ast_create_unary(ZEND_BW_NOT, $2.u.ast); }
+       |       expr T_IS_IDENTICAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); }
+       |       expr T_IS_NOT_IDENTICAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); }
+       |       expr T_IS_EQUAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); }
+       |       expr T_IS_NOT_EQUAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); }
+       |       expr '<' expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); }
+       |       expr T_IS_SMALLER_OR_EQUAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); }
+       |       expr '>' expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER, $1.u.ast, $3.u.ast); }
+       |       expr T_IS_GREATER_OR_EQUAL expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER_EQUAL, $1.u.ast, $3.u.ast); }
+       |       expr T_INSTANCEOF class_name_reference
+                       { $$.u.ast = zend_ast_create_binary(ZEND_INSTANCEOF, $1.u.ast, $3.u.ast); }
+       |       parenthesis_expr        { $$.u.ast = AST_ZNODE(&$1); }
+       |       new_expr { $$.u.ast = $1.u.ast; }
+       |       expr '?' expr ':' expr
+                       { $$.u.ast = zend_ast_create_ternary(
+                             ZEND_AST_CONDITIONAL, $1.u.ast, $3.u.ast, $5.u.ast); }
+       |       expr '?' ':' expr
+                       { $$.u.ast = zend_ast_create_ternary(ZEND_AST_CONDITIONAL, $1.u.ast, NULL, $4.u.ast); }
+       |       internal_functions_in_yacc { $$.u.ast = AST_ZNODE(&$1); }
+       |       T_INT_CAST expr         { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_INT, $2.u.ast); }
+       |       T_DOUBLE_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_DOUBLE, $2.u.ast); }
+       |       T_STRING_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_STRING, $2.u.ast); }
+       |       T_ARRAY_CAST expr       { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_ARRAY, $2.u.ast); }
+       |       T_OBJECT_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_OBJECT, $2.u.ast); }
+       |       T_BOOL_CAST expr        { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_BOOL, $2.u.ast); }
+       |       T_UNSET_CAST expr       { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_NULL, $2.u.ast); }
+       |       T_EXIT exit_expr        { $$.u.ast = zend_ast_create_unary(ZEND_EXIT, $2.u.ast); }
+       |       '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { AC($3); zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
+       |       scalar                          { $$.u.ast = AST_ZNODE(&$1); }
+       |       '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); AZ($$); }
+       |       T_PRINT expr { $$.u.ast = zend_ast_create_unary(ZEND_PRINT, $2.u.ast); }
+       |       T_YIELD { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, NULL, NULL); }
        |       function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
                '(' parameter_list ')' lexical_vars
-               '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; }
+               '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
        |       T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); }
                '(' parameter_list ')' lexical_vars
-               '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; }
+               '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; AZ($$); }
 ;
 
 yield_expr:
-               T_YIELD expr_without_variable { zend_do_yield(&$$, &$2, NULL, 0 TSRMLS_CC); }
-       |       T_YIELD variable { zend_do_yield(&$$, &$2, NULL, 1 TSRMLS_CC); }
-       |       T_YIELD expr T_DOUBLE_ARROW expr_without_variable { zend_do_yield(&$$, &$4, &$2, 0 TSRMLS_CC); }
-       |       T_YIELD expr T_DOUBLE_ARROW variable { zend_do_yield(&$$, &$4, &$2, 1 TSRMLS_CC); }
+               T_YIELD expr { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $2.u.ast, NULL); }
+       |       T_YIELD expr T_DOUBLE_ARROW expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $4.u.ast, $2.u.ast); }
 ;
 
 function:
@@ -908,24 +890,24 @@ lexical_var_list:
 ;
 
 function_call:
-               namespace_name function_call_parameter_list_ast
+               namespace_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
                                  zend_ast_create_unary(ZEND_AST_NAME, AST_ZVAL(&$1)), $2.u.ast); }
-       |       T_NAMESPACE T_NS_SEPARATOR namespace_name function_call_parameter_list_ast
+       |       T_NAMESPACE T_NS_SEPARATOR namespace_name function_call_parameter_list
                        { ZVAL_EMPTY_STRING(&$1.u.constant);
                          zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC);
                          $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
                                  zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$1)), $4.u.ast); }
-       |       T_NS_SEPARATOR namespace_name function_call_parameter_list_ast
+       |       T_NS_SEPARATOR namespace_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
                                  zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$2)), $3.u.ast); }
-       |       class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list_ast
+       |       class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
                              AST_ZVAL(&$1), $3.u.ast, $4.u.ast); }
-       |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list_ast
+       |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
                              AST_ZNODE(&$1), $3.u.ast, $4.u.ast); }
-       |       callable_expr function_call_parameter_list_ast
+       |       callable_expr function_call_parameter_list
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, $1.u.ast, $2.u.ast); }
 ;
 
@@ -945,14 +927,14 @@ fully_qualified_class_name:
 
 
 class_name_reference:
-               class_name              { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
-       |       new_variable    { AST_COMPILE_VAR(&$1, $1.u.ast, BP_VAR_R); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
+               class_name              { $$.u.ast = AST_ZVAL(&$1); }
+       |       new_variable    { $$.u.ast = $1.u.ast; }
 ;
 
 exit_expr:
-               /* empty */     { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
-       |       '(' ')'         { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
-       |       parenthesis_expr        { $$ = $1; }
+               /* empty */                     { $$.u.ast = NULL; }
+       |       '(' ')'                         { $$.u.ast = NULL; }
+       |       parenthesis_expr        { $$.u.ast = AST_ZNODE(&$1); }
 ;
 
 backticks_expr:
@@ -963,8 +945,8 @@ backticks_expr:
 
 
 ctor_arguments:
-               /* empty */     { Z_LVAL($$.u.constant) = 0; }
-       |       function_call_parameter_list    { $$ = $1; }
+               /* empty */     { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_PARAMS); }
+       |       function_call_parameter_list { $$.u.ast = $1.u.ast; }
 ;
 
 
@@ -1083,28 +1065,17 @@ non_empty_static_array_pair_list:
 ;
 
 expr:
-               r_variable                                      { $$ = $1; }
-       |       expr_without_variable           { $$ = $1; }
+               variable                                        { $$.u.ast = $1.u.ast; }
+       |       expr_without_variable           { $$.u.ast = $1.u.ast; }
 ;
 
 parenthesis_expr:
-               '(' expr ')'            { $$ = $2; }
-       |       '(' yield_expr ')'      { $$ = $2; }
-;
-
-
-r_variable:
-       variable { zend_compile_var(&$$, $1.u.ast, BP_VAR_R TSRMLS_CC); zend_ast_destroy($1.u.ast); }
+               '(' expr ')'            { AST_COMPILE(&$$, $2.u.ast); }
+       |       '(' yield_expr ')'      { AST_COMPILE(&$$, $2.u.ast); }
 ;
 
 w_variable:
-       variable        { zend_compile_var(&$$, $1.u.ast, BP_VAR_W TSRMLS_CC); zend_ast_destroy($1.u.ast);
-                                 zend_check_writable_variable(&$1); }
-;
-
-rw_variable:
-       variable        { zend_compile_var(&$$, $1.u.ast, BP_VAR_RW TSRMLS_CC); zend_ast_destroy($1.u.ast);
-                                 zend_check_writable_variable(&$$); }
+       variable        { zend_ensure_writable_variable($1.u.ast); AST_COMPILE_VAR(&$$, $1.u.ast, BP_VAR_W); }
 ;
 
 variable_class_name:
@@ -1113,13 +1084,13 @@ variable_class_name:
 
 dereferencable:
                variable                                { $$.u.ast = $1.u.ast; }
-       |       '(' expr ')'                    { $$.u.ast = AST_ZNODE(&$2); }
+       |       '(' expr ')'                    { $$.u.ast = $2.u.ast; }
        |       dereferencable_scalar   { $$.u.ast = AST_ZNODE(&$1); }
 ;
 
 callable_expr:
                callable_variable               { $$.u.ast = $1.u.ast; }
-       |       '(' expr ')'                    { $$.u.ast = AST_ZNODE(&$2); }
+       |       '(' expr ')'                    { $$.u.ast = $2.u.ast; }
        |       dereferencable_scalar   { $$.u.ast = AST_ZNODE(&$1); }
 ;
 
@@ -1129,8 +1100,8 @@ callable_variable:
        |       dereferencable '[' dim_offset ']'
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, $3.u.ast); }
        |       dereferencable '{' expr '}'
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, AST_ZNODE(&$3)); }
-       |       dereferencable T_OBJECT_OPERATOR member_name function_call_parameter_list_ast
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, $3.u.ast); }
+       |       dereferencable T_OBJECT_OPERATOR member_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_METHOD_CALL, $1.u.ast, $3.u.ast, $4.u.ast); }
        |       function_call { $$.u.ast = $1.u.ast; }
 ;
@@ -1148,7 +1119,7 @@ simple_variable:
                T_VARIABLE
                        { $$.u.ast = AST_ZVAL(&$1); }
        |       '$' '{' expr '}'
-                       { $$.u.ast = zend_ast_create_znode(&$3); }
+                       { $$.u.ast = $3.u.ast; }
        |       '$' simple_variable
                        { $$.u.ast = zend_ast_create_unary(ZEND_AST_VAR, $2.u.ast); }
 ;
@@ -1166,7 +1137,7 @@ new_variable:
        |       new_variable '[' dim_offset ']'
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, $3.u.ast); }
        |       new_variable '{' expr '}'
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, AST_ZNODE(&$3)); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM, $1.u.ast, $3.u.ast); }
        |       new_variable T_OBJECT_OPERATOR member_name
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_PROP, $1.u.ast, $3.u.ast); }
        |       class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
@@ -1177,12 +1148,12 @@ new_variable:
 
 dim_offset:
                /* empty */             { $$.u.ast = NULL; }
-       |       expr                    { $$.u.ast = AST_ZNODE(&$1); }
+       |       expr                    { $$.u.ast = $1.u.ast; }
 ;
 
 member_name:
                T_STRING                { $$.u.ast = AST_ZVAL(&$1); }
-       |       '{' expr '}'    { $$.u.ast = AST_ZNODE(&$2); }
+       |       '{' expr '}'    { $$.u.ast = $2.u.ast; }
        |       simple_variable { $$.u.ast = zend_ast_create_unary(ZEND_AST_VAR, $1.u.ast); }
 ;
 
@@ -1207,13 +1178,13 @@ array_pair_list:
 ;
 
 non_empty_array_pair_list:
-               non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr  { zend_do_add_array_element(&$$, &$5, &$3, 0 TSRMLS_CC); }
-       |       non_empty_array_pair_list ',' expr                      { zend_do_add_array_element(&$$, &$3, NULL, 0 TSRMLS_CC); }
-       |       expr T_DOUBLE_ARROW expr        { zend_do_init_array(&$$, &$3, &$1, 0 TSRMLS_CC); }
-       |       expr                            { zend_do_init_array(&$$, &$1, NULL, 0 TSRMLS_CC); }
-       |       non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable { zend_do_add_array_element(&$$, &$6, &$3, 1 TSRMLS_CC); }
+               non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr  { AC($3); AC($5); zend_do_add_array_element(&$$, &$5, &$3, 0 TSRMLS_CC); }
+       |       non_empty_array_pair_list ',' expr                      { AC($3); zend_do_add_array_element(&$$, &$3, NULL, 0 TSRMLS_CC); }
+       |       expr T_DOUBLE_ARROW expr        { AC($1); AC($3); zend_do_init_array(&$$, &$3, &$1, 0 TSRMLS_CC); }
+       |       expr                            { AC($1); zend_do_init_array(&$$, &$1, NULL, 0 TSRMLS_CC); }
+       |       non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable { AC($3); zend_do_add_array_element(&$$, &$6, &$3, 1 TSRMLS_CC); }
        |       non_empty_array_pair_list ',' '&' w_variable { zend_do_add_array_element(&$$, &$4, NULL, 1 TSRMLS_CC); }
-       |       expr T_DOUBLE_ARROW '&' w_variable      { zend_do_init_array(&$$, &$4, &$1, 1 TSRMLS_CC); }
+       |       expr T_DOUBLE_ARROW '&' w_variable      { AC($1); zend_do_init_array(&$$, &$4, &$1, 1 TSRMLS_CC); }
        |       '&' w_variable                  { zend_do_init_array(&$$, &$2, NULL, 1 TSRMLS_CC); }
 ;
 
@@ -1237,10 +1208,10 @@ encaps_var:
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_PROP,
                              zend_ast_create_var(&$1.u.constant), AST_ZNODE(&$3)); }
        |       T_DOLLAR_OPEN_CURLY_BRACES expr '}'
-                       { $$.u.ast = zend_ast_create_unary(ZEND_AST_VAR, AST_ZNODE(&$2)); }
+                       { $$.u.ast = zend_ast_create_unary(ZEND_AST_VAR, $2.u.ast); }
        |       T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_DIM,
-                             zend_ast_create_var(&$2.u.constant), AST_ZNODE(&$4)); }
+                             zend_ast_create_var(&$2.u.constant), $4.u.ast); }
        |       T_CURLY_OPEN variable '}' { $$.u.ast = $2.u.ast; }
 ;
 
@@ -1254,12 +1225,12 @@ encaps_var_offset:
 internal_functions_in_yacc:
                T_ISSET '(' isset_variables ')' { $$ = $3; }
        |       T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
-       |       T_EMPTY '(' expr_without_variable ')' { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$3 TSRMLS_CC); }
-       |       T_INCLUDE expr                  { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
-       |       T_INCLUDE_ONCE expr     { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
-       |       T_EVAL '(' expr ')'     { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
-       |       T_REQUIRE expr                  { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
-       |       T_REQUIRE_ONCE expr             { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
+       |       T_EMPTY '(' expr_without_variable ')' { AC($3); zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$3 TSRMLS_CC); }
+       |       T_INCLUDE expr                  { AC($2); zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
+       |       T_INCLUDE_ONCE expr     { AC($2); zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
+       |       T_EVAL '(' expr ')'     { AC($3); zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
+       |       T_REQUIRE expr                  { AC($2); zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
+       |       T_REQUIRE_ONCE expr             { AC($2); zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
 ;
 
 isset_variables: