]> granicus.if.org Git - php/commitdiff
* Fix all hash checks that checked Bucket.arKey for NULL, when it was changed
authorZeev Suraski <zeev@php.net>
Sat, 15 May 1999 15:47:24 +0000 (15:47 +0000)
committerZeev Suraski <zeev@php.net>
Sat, 15 May 1999 15:47:24 +0000 (15:47 +0000)
  to char[1], these checks should have been changed to Bucket.nKeyLength==0
* Support runtime declaration of functions.  I ended up changing the grammar
  to catch top level functions vs. nested functions.  The reason is simple -
  if we don't have functions properly declared at compile-time, function calls
  cannot be resolved at compile time, and have to be resolved at runtime, which
  ends up being much much slower (without the optimizer, that is).
  It's no biggy though, the grammar change isn't that bad.

Zend/zend-parser.y
Zend/zend.c
Zend/zend.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_hash.c

index 660b490fae95c16e0ebd47d4c8ec8853a1ad1503..7d338c97e298c3f6bf4d8d9d9f24834be0beb1ac 100644 (file)
 
 %% /* Rules */
 
-statement_list:        
-               statement_list  { do_extended_info(CLS_C); } statement { ELS_FETCH(); HANDLE_INTERACTIVE(); }
+top_statement_list:    
+               top_statement_list  { do_extended_info(CLS_C); } top_statement { ELS_FETCH(); HANDLE_INTERACTIVE(); }
        |       /* empty */
 ;
 
 
+top_statement:
+               statement
+       |       declaration_statement   { do_early_binding(CLS_C); }
+;
+
+
+inner_statement_list:
+               inner_statement_list  { do_extended_info(CLS_C); } inner_statement { ELS_FETCH(); HANDLE_INTERACTIVE(); }
+       |       /* empty */
+;
+
+
+inner_statement:
+               statement
+       |       declaration_statement
+;
+
+
 statement:
-               '{' statement_list '}'
+               '{' inner_statement_list '}'
        |       T_IF '(' expr ')' { do_if_cond(&$3, &$4 CLS_CC); } statement { do_if_after_statement(&$4, 1 CLS_CC); } elseif_list else_single { do_if_end(CLS_C); }
-       |       T_IF '(' expr ')' ':' { do_if_cond(&$3, &$4 CLS_CC); } statement_list { do_if_after_statement(&$4, 1 CLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { do_if_end(CLS_C); }
+       |       T_IF '(' expr ')' ':' { do_if_cond(&$3, &$4 CLS_CC); } inner_statement_list { do_if_after_statement(&$4, 1 CLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { do_if_end(CLS_C); }
        |       T_WHILE '(' { $1.u.opline_num = get_next_op_number(CG(active_op_array));  } expr  ')' { do_while_cond(&$4, &$5 CLS_CC); } while_statement { do_while_end(&$1, &$5 CLS_CC); }
        |       T_DO { $1.u.opline_num = get_next_op_number(CG(active_op_array));  do_do_while_begin(CLS_C); } statement T_WHILE '(' expr ')' ';' { do_do_while_end(&$1, &$6 CLS_CC); }
        |       T_FOR 
@@ -151,16 +169,10 @@ statement:
        |       T_BREAK expr ';'                { do_brk_cont(ZEND_BRK, &$2 CLS_CC); }
        |       T_CONTINUE ';'          { do_brk_cont(ZEND_CONT, NULL CLS_CC); }
        |       T_CONTINUE expr ';'     { do_brk_cont(ZEND_CONT, &$2 CLS_CC); }
-       |       T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
-                       '(' parameter_list ')' '{' statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
-       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING  { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
-                       parameter_list '(' statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
        |       T_RETURN ';'                    { do_return(NULL CLS_CC); }
        |       T_RETURN expr ';'               { do_return(&$2 CLS_CC); }
        |       T_GLOBAL global_var_list
        |       T_STATIC static_var_list
-       |       T_CLASS T_STRING { do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
-       |       T_CLASS T_STRING T_EXTENDS T_STRING { do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
        |       T_ECHO echo_expr_list ';'
        |       T_INLINE_HTML                   { do_echo(&$1 CLS_CC); }
        |       expr ';'                        { do_free(&$1 CLS_CC); }
@@ -172,6 +184,16 @@ statement:
 ;
 
 
+declaration_statement:
+               T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
+                       '(' parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
+       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING  { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
+                       parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
+       |       T_CLASS T_STRING { do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
+       |       T_CLASS T_STRING T_EXTENDS T_STRING { do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
+;
+
+
 foreach_optional_arg:
                /* empty */             { $$.op_type = IS_UNUSED; }
        |       T_DOUBLE_ARROW w_cvar           { $$ = $2; }
@@ -180,13 +202,13 @@ foreach_optional_arg:
 
 for_statement:
                statement
-       |       ':' statement_list T_ENDFOR ';'
+       |       ':' inner_statement_list T_ENDFOR ';'
 ;
 
 
 foreach_statement:
                statement
-       |       ':' statement_list T_ENDFOREACH ';'
+       |       ':' inner_statement_list T_ENDFOREACH ';'
 ;
 
 
@@ -200,8 +222,8 @@ switch_case_list:
 
 case_list:
                /* empty */     { $$.u.opline_num = -1; }
-       |       case_list T_CASE expr case_separator { do_case_before_statement(&$1, &$2, &$3 CLS_CC); } statement_list { do_case_after_statement(&$$, &$2 CLS_CC); }
-       |       case_list T_DEFAULT case_separator { do_default_before_statement(&$1, &$2 CLS_CC); } statement_list { do_case_after_statement(&$$, &$2 CLS_CC); }
+       |       case_list T_CASE expr case_separator { do_case_before_statement(&$1, &$2, &$3 CLS_CC); } inner_statement_list { do_case_after_statement(&$$, &$2 CLS_CC); }
+       |       case_list T_DEFAULT case_separator { do_default_before_statement(&$1, &$2 CLS_CC); } inner_statement_list { do_case_after_statement(&$$, &$2 CLS_CC); }
 ;
 
 
@@ -213,7 +235,7 @@ case_separator:
 
 while_statement:
                statement
-       |       ':' statement_list T_ENDWHILE ';'
+       |       ':' inner_statement_list T_ENDWHILE ';'
 ;
 
 
@@ -226,7 +248,7 @@ elseif_list:
 
 new_elseif_list:
                /* empty */
-       |       new_elseif_list T_ELSEIF '(' expr ')' ':' { do_if_cond(&$4, &$5 CLS_CC); } statement_list { do_if_after_statement(&$5, 0 CLS_CC); }
+       |       new_elseif_list T_ELSEIF '(' expr ')' ':' { do_if_cond(&$4, &$5 CLS_CC); } inner_statement_list { do_if_after_statement(&$5, 0 CLS_CC); }
 ;
 
 
@@ -238,7 +260,7 @@ else_single:
 
 new_else_single:
                /* empty */
-       |       T_ELSE ':' statement_list
+       |       T_ELSE ':' inner_statement_list
 ;
 
 
@@ -310,9 +332,9 @@ class_statement_list:
 class_statement:
                T_VAR class_variable_decleration ';'
        |       T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); } '(' 
-                       parameter_list ')' '{' statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
+                       parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
        |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); }
-                       parameter_list '(' statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
+                       parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
 
 ;
 
index f9b0640d09512de87e587eb1d707aeb5effe944f..0ede40804b0969664a87d112540fa02e4bd031a0 100644 (file)
@@ -320,6 +320,7 @@ void zenderror(char *error)
 }
 
 
+BEGIN_EXTERN_C()
 ZEND_API void zend_bailout()
 {
        CLS_FETCH();
@@ -328,6 +329,7 @@ ZEND_API void zend_bailout()
        CG(unclean_shutdown) = 1;
        longjmp(EG(bailout), FAILURE);
 }
+END_EXTERN_C()
 
 
 void zend_append_version_info(zend_extension *extension)
index 0f4bd2574411f8d8acb1b59f6239b0ef1cf6e6f5..2a397b9a535d2da307c32e87a76e00f338e6ee58 100644 (file)
@@ -173,7 +173,9 @@ typedef struct {
 int zend_startup(zend_utility_functions *utility_functions, char **extensions);
 void zend_shutdown();
 void zend_set_utility_values(zend_utility_values *utility_values);
+BEGIN_EXTERN_C()
 ZEND_API void zend_bailout();
+END_EXTERN_C()
 ZEND_API char *get_zend_version();
 
 ZEND_API int zend_print_zval(zval *expr, int indent);
index bb4d1ee2aacef2259a9266c4306844c8ffd8372a..cf5a1dcc16cc8a1b9abf6d71bd2e844340875d82 100644 (file)
@@ -622,7 +622,18 @@ void do_begin_function_declaration(znode *function_token, znode *function_name,
        if (is_method) {
                zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
        } else {
-               zend_hash_add(CG(function_table), name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
+               zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+               opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS;
+               opline->op1.op_type = IS_CONST;
+               opline->op1.u.constant.type = IS_LONG;
+               opline->op1.u.constant.value.lval = zend_hash_next_free_element(CG(function_table));
+               opline->op2.op_type = IS_CONST;
+               opline->op2.u.constant.type = IS_STRING;
+               opline->op2.u.constant.value.str.val = estrndup(name, name_len);
+               opline->op2.u.constant.value.str.len = name_len;
+               opline->extended_value = ZEND_DECLARE_FUNCTION;
+               zend_hash_next_index_insert(CG(function_table), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
        }
 
        if (CG(extended_info)) {
@@ -825,6 +836,53 @@ void do_return(znode *expr CLS_DC)
 }
 
 
+void do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table)
+{
+       switch (opline->extended_value) {
+               case ZEND_DECLARE_FUNCTION: {
+                               zend_function *function;
+
+                               zend_hash_index_find(function_table, opline->op1.u.constant.value.lval, (void **) &function);
+                               (*function->op_array.refcount)++;
+                               if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) {
+                                       zend_error(E_ERROR, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val);
+                               }
+                       }
+                       break;
+               case ZEND_DECLARE_CLASS: {
+                               zend_class_entry *ce;
+
+                               zend_hash_index_find(class_table, opline->op1.u.constant.value.lval, (void **) &ce);
+                               (*ce->refcount)++;
+                               if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, ce, sizeof(zend_class_entry), NULL)==FAILURE) {
+                                       zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+                               }
+                       }
+                       break;
+       }
+}
+
+
+void do_early_binding(CLS_D)
+{
+       zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
+
+       do_bind_function_or_class(opline, CG(function_table), CG(class_table));
+       switch (opline->extended_value) {
+               case ZEND_DECLARE_FUNCTION:
+                       zend_hash_index_del(CG(function_table), opline->op1.u.constant.value.lval);
+                       break;
+               case ZEND_DECLARE_CLASS:
+                       zend_hash_index_del(CG(class_table), opline->op1.u.constant.value.lval);
+                       break;
+       }
+       zval_dtor(&opline->op2.u.constant);
+       opline->opcode = ZEND_NOP;
+       SET_UNUSED(opline->op1);
+       SET_UNUSED(opline->op2);
+}
+
+
 void do_boolean_or_begin(znode *expr1, znode *op_token CLS_DC)
 {
        int next_op_number = get_next_op_number(CG(active_op_array));
@@ -1101,6 +1159,8 @@ static void function_add_ref(zend_function *function)
 
 void do_begin_class_declaration(znode *class_name, znode *parent_class_name CLS_DC)
 {
+       zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
        if (CG(active_class_entry)) {
                zend_error(E_COMPILE_ERROR, "Class declarations may not be nested");
                return;
@@ -1141,9 +1201,17 @@ void do_begin_class_declaration(znode *class_name, znode *parent_class_name CLS_
        CG(class_entry).handle_property_set = NULL;
        CG(class_entry).handle_property_get = NULL;
 
-       if (zend_hash_add(CG(class_table), CG(class_entry).name, CG(class_entry).name_length+1, &CG(class_entry), sizeof(zend_class_entry), (void **) &CG(active_class_entry))==FAILURE) {
-               zend_error(E_COMPILE_ERROR, "Class %s cannot be redeclared", CG(class_entry).name);
-       }
+       opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS;
+       opline->op1.op_type = IS_CONST;
+       opline->op1.u.constant.type = IS_LONG;
+       opline->op1.u.constant.value.lval = zend_hash_next_free_element(CG(function_table));
+       opline->op2.op_type = IS_CONST;
+       opline->op2.u.constant.type = IS_STRING;
+       opline->op2.u.constant.value.str.val = estrndup(CG(class_entry).name, CG(class_entry).name_length);
+       opline->op2.u.constant.value.str.len = CG(class_entry).name_length;
+       opline->extended_value = ZEND_DECLARE_CLASS;
+
+       zend_hash_next_index_insert(CG(class_table), &CG(class_entry), sizeof(zend_class_entry), (void **) &CG(active_class_entry));
 }
 
 
index 8002c66ce1749805555c793bc1f0282adff479ef..1a1f46dfcd2d63a62fcd5d156fa5a15f0fbab863 100644 (file)
@@ -257,6 +257,8 @@ void do_begin_dynamic_function_call(znode *function_name CLS_DC);
 void do_begin_class_member_function_call(znode *class_name, znode *function_name CLS_DC);
 void do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method CLS_DC);
 void do_return(znode *expr CLS_DC);
+void do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table);
+void do_early_binding(CLS_D);
 
 void do_pass_param(znode *param, int op, int offset CLS_DC);
 
@@ -476,12 +478,14 @@ int zendlex(znode *zendlval CLS_DC);
 #define ZEND_FETCH_DIM_TMP_VAR         89
 #define ZEND_FETCH_CONSTANT                    90
 
-#define ZEND_INIT_GLOBALS                      91
+#define ZEND_DECLARE_FUNCTION_OR_CLASS 91
 
-#define ZEND_EXT_STMT                          92
-#define ZEND_EXT_FCALL_BEGIN           93
-#define ZEND_EXT_FCALL_END                     94
-#define ZEND_EXT_NOP                           95
+#define ZEND_INIT_GLOBALS                      92
+
+#define ZEND_EXT_STMT                          93
+#define ZEND_EXT_FCALL_BEGIN           94
+#define ZEND_EXT_FCALL_END                     95
+#define ZEND_EXT_NOP                           96
 
 /* end of block */
 
@@ -524,4 +528,7 @@ int zendlex(znode *zendlval CLS_DC);
 #define ZEND_HANDLE_FP                 2
 #define ZEND_HANDLE_ISTREAM            3
 
+#define ZEND_DECLARE_CLASS             1
+#define ZEND_DECLARE_FUNCTION  2
+
 #endif /* _COMPILE_H */
index ee56394f1e7c23cc00bdfd755f2b775ede97652d..2c6f04120e47ca27c5ee2efdfabb2a3d9a6dccef 100644 (file)
@@ -1304,7 +1304,7 @@ binary_assign_op_addr: {
                                                active_function_table = EG(function_table);
                                        }
                                        if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) {
-                                               zend_error(E_ERROR, "Call to undefined function:  %s()\n", function_name->value.str.val);
+                                               zend_error(E_ERROR, "Call to undefined function:  %s()", function_name->value.str.val);
                                        }
                                        zval_dtor(&tmp);
                                        function_being_called = function;
@@ -1890,6 +1890,9 @@ send_by_ref:
                                        zend_llist_apply_with_argument(&zend_extensions, (void (*)(void *, void *)) zend_extension_fcall_end_handler, op_array);
                                }
                                break;
+                       case ZEND_DECLARE_FUNCTION_OR_CLASS:
+                               do_bind_function_or_class(opline, EG(function_table), EG(class_table));
+                               break;
                        case ZEND_INIT_GLOBALS: {
                                        zval *globals = (zval *) emalloc(sizeof(zval));
 
index 4cb93c9c690620b73bf8d93682039e107bee2bae..710d2418dd1c94a14e6c8a23a03ce9ac10f1770e 100644 (file)
@@ -779,7 +779,7 @@ ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct) (void *))
                q = p;
                p = p->pListNext;
                if (destruct(q->pData)) {
-                       if (q->arKey == NULL) {
+                       if (q->nKeyLength==0) {
                                zend_hash_index_del(ht, q->h);
                        } else {
                                zend_hash_del(ht,q->arKey,q->nKeyLength);
@@ -798,7 +798,7 @@ ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct) (void
                q = p;
                p = p->pListNext;
                if (destruct(q->pData, argument)) {
-                       if (q->arKey == NULL) {
+                       if (q->nKeyLength == 0) {
                                zend_hash_index_del(ht, q->h);
                        } else {
                                zend_hash_del(ht,q->arKey,q->nKeyLength);
@@ -837,7 +837,7 @@ ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, void (*pCopy
     p = source->pListHead;
        while (p) {
                memcpy(tmp, p->pData, size);
-               if (p->arKey) {
+               if (p->nKeyLength>0) {
                        if (zend_hash_add(target, p->arKey, p->nKeyLength, tmp, size, &t)==SUCCESS && pCopyConstructor) {
                                pCopyConstructor(t);
                        }