From: Sara Golemon Date: Thu, 29 Jul 2004 15:23:47 +0000 (+0000) Subject: Add goto operator by popular request. X-Git-Tag: PRE_ZEND_VM_DISPATCH_PATCH~317 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5865b3680a450fbf7ffc2621e99e4f876337ada0;p=php Add goto operator by popular request. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 8a2a5648cc..0c0a227e8c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3497,6 +3497,39 @@ void zend_do_exit(znode *result, znode *message TSRMLS_DC) result->u.constant.value.lval = 1; } +void zend_do_label(znode *label TSRMLS_DC) +{ + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_NOP; + SET_UNUSED(opline->result); + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + + if (label->op_type == IS_CONST) { + if (!CG(active_op_array)->labels) { + CG(active_op_array)->labels = emalloc(sizeof(HashTable)); + zend_hash_init(CG(active_op_array)->labels, 16, NULL, NULL, 0); + } + if (zend_hash_exists(CG(active_op_array)->labels, label->u.constant.value.str.val, label->u.constant.value.str.len + 1)) { + zend_error(E_COMPILE_ERROR, "Label cannot be redefined."); + } else { + /* Point to our newly created NOP instruction */ + zend_hash_add(CG(active_op_array)->labels, label->u.constant.value.str.val, label->u.constant.value.str.len + 1, &opline, sizeof(zend_op*), NULL); + } + } else { + zend_error(E_COMPILE_ERROR, "Invalid label identifier, expecting T_STRING"); + } +} +void zend_do_goto(znode *label TSRMLS_DC) +{ + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_GOTO; + SET_UNUSED(opline->result); + opline->op1 = *label; + SET_UNUSED(opline->op2); +} void zend_do_begin_silence(znode *strudel_token TSRMLS_DC) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 69fc099b70..a4ba04d109 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -170,6 +170,7 @@ struct _zend_op_array { zend_uint *refcount; zend_op *opcodes; + HashTable *labels; zend_uint last, size; zend_uint T; @@ -459,6 +460,8 @@ void zend_do_declare_end(znode *declare_token TSRMLS_DC); void zend_do_end_heredoc(TSRMLS_D); void zend_do_exit(znode *result, znode *message TSRMLS_DC); +void zend_do_goto(znode *label TSRMLS_DC); +void zend_do_label(znode *label TSRMLS_DC); void zend_do_begin_silence(znode *strudel_token TSRMLS_DC); void zend_do_end_silence(znode *strudel_token TSRMLS_DC); @@ -714,6 +717,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_HANDLE_EXCEPTION 149 +#define ZEND_GOTO 150 /* end of block */ /* END: OPCODES */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1c84067d1d..14b2514c18 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4064,6 +4064,29 @@ int zend_isset_isempty_prop_obj_handler(ZEND_OPCODE_HANDLER_ARGS) return zend_isset_isempty_dim_prop_obj_handler(1, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +int zend_goto_handler(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op **target; + zval *label = get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R); + zval tmp; + + tmp = *label; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + label = &tmp; + + if (op_array->labels && + zend_hash_find(op_array->labels, label->value.str.val, label->value.str.len + 1, (void **)&target) == SUCCESS) { +#if DEBUG_ZEND>=2 + printf("Jumping on goto to opcode %08X\n", *target); +#endif + SET_OPCODE(*target); + return 0; + } + + zend_error(E_WARNING, "Unknown label %s", Z_STRVAL_P(label)); + NEXT_OPCODE(); +} int zend_exit_handler(ZEND_OPCODE_HANDLER_ARGS) { @@ -4438,6 +4461,8 @@ void zend_init_opcodes_handlers() zend_opcode_handlers[ZEND_ASSIGN_DIM] = zend_assign_dim_handler; zend_opcode_handlers[ZEND_HANDLE_EXCEPTION] = zend_handle_exception_handler; + + zend_opcode_handlers[ZEND_GOTO] = zend_goto_handler; } /* diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 257849fd26..cdaffd0fa6 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -145,6 +145,7 @@ %token T_NULL %token T_FALSE %token T_TRUE +%token T_GOTO %% /* Rules */ @@ -223,6 +224,8 @@ unticked_statement: '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } + | T_GOTO expr ';' { zend_do_goto(&$2 TSRMLS_CC); } + | T_STRING ':' { zend_do_label(&$1 TSRMLS_CC); } ; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 00deccd731..3f4026efd0 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -762,6 +762,10 @@ NEWLINE ("\r"|"\n"|"\r\n") %option noyywrap %% +"goto" { + return T_GOTO; +} + "exit" { return T_EXIT; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 4b4f598900..cdce1a10cd 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -63,6 +63,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->size = initial_ops_size; op_array->last = 0; op_array->opcodes = NULL; + op_array->labels = NULL; op_array_alloc_ops(op_array); op_array->T = 0; @@ -223,6 +224,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) opline++; } efree(op_array->opcodes); + + if (op_array->labels) { + zend_hash_destroy(op_array->labels); + efree(op_array->labels); + } + if (op_array->function_name) { efree(op_array->function_name); }