예제 #1
0
function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name)
{
    global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, $op1_is_tmp_free, $op2_is_tmp_free, $op1_free, $op2_free, $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix;
    // Specializing
    $code = preg_replace(array("/OP1_TYPE/", "/OP2_TYPE/", "/OP1_FREE/", "/OP2_FREE/", "/GET_OP1_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP1_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/IS_OP1_TMP_FREE\\(\\)/", "/IS_OP2_TMP_FREE\\(\\)/", "/FREE_OP1\\(\\)/", "/FREE_OP2\\(\\)/", "/FREE_OP1_IF_VAR\\(\\)/", "/FREE_OP2_IF_VAR\\(\\)/", "/FREE_OP1_VAR_PTR\\(\\)/", "/FREE_OP2_VAR_PTR\\(\\)/", "/^#ifdef\\s+ZEND_VM_SPEC\\s*\n/m", "/^#ifndef\\s+ZEND_VM_SPEC\\s*\n/m", "/\\!defined\\(ZEND_VM_SPEC\\)/m", "/defined\\(ZEND_VM_SPEC\\)/m", "/ZEND_VM_C_LABEL\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/ZEND_VM_C_GOTO\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/^#if\\s+1\\s*\\|\\|.*[^\\\\]\$/m", "/^#if\\s+0\\s*&&.*[^\\\\]\$/m", "/^#ifdef\\s+ZEND_VM_EXPORT\\s*\n/m", "/^#ifndef\\s+ZEND_VM_EXPORT\\s*\n/m"), array($op1_type[$op1], $op2_type[$op2], $op1_free[$op1], $op2_free[$op2], $op1_get_zval_ptr[$op1], $op2_get_zval_ptr[$op2], $op1_get_zval_ptr_ptr[$op1], $op2_get_zval_ptr_ptr[$op2], $op1_get_obj_zval_ptr[$op1], $op2_get_obj_zval_ptr[$op2], $op1_get_obj_zval_ptr_ptr[$op1], $op2_get_obj_zval_ptr_ptr[$op2], $op1_is_tmp_free[$op1], $op2_is_tmp_free[$op2], $op1_free_op[$op1], $op2_free_op[$op2], $op1_free_op_if_var[$op1], $op2_free_op_if_var[$op2], $op1_free_op_var_ptr[$op1], $op2_free_op_var_ptr[$op2], $op1 != "ANY" || $op2 != "ANY" ? "#if 1\n" : "#if 0\n", $op1 != "ANY" || $op2 != "ANY" ? "#if 0\n" : "#if 1\n", $op1 != "ANY" || $op2 != "ANY" ? "0" : "1", $op1 != "ANY" || $op2 != "ANY" ? "1" : "0", "\\1" . ($spec && $kind != ZEND_VM_KIND_CALL ? "_SPEC" . $prefix[$op1] . $prefix[$op2] : ""), "goto \\1" . ($spec && $kind != ZEND_VM_KIND_CALL ? "_SPEC" . $prefix[$op1] . $prefix[$op2] : ""), "#if 1", "#if 0", $export ? "#if 1\n" : "#if 0\n", $export ? "#if 0\n" : "#if 1\n"), $code);
    if (0 && strpos($code, '{') === 0) {
        $code = "{\n\tfprintf(stderr, \"{$name}\\n\");\n" . substr($code, 1);
    }
    // Updating code according to selected threading model
    switch ($kind) {
        case ZEND_VM_KIND_CALL:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER_EX\\(\\s*([A-Za-z_]*)\\s*,\\s*[A-Za-z_]*\\s*,\\s*(.*)\\s*\\);/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "return " . $matches[1] . ($spec ? "_SPEC" : "") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
                    } else {
                        if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
                            return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2] . ", ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);";
                        } else {
                            return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
                        }
                    }
                }
            }, $code);
            break;
        case ZEND_VM_KIND_SWITCH:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER_EX\\(\\s*([A-Za-z_]*)\\s*,\\s*([A-Za-z_]*)\\s*,\\s*(.*)\\s*\\);/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "goto " . $matches[1] . ($spec ? "_SPEC" : "") . $prefix[$op1] . $prefix[$op2] . "_LABEL";
                    } else {
                        if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
                            return $matches[2] . " = " . $matches[3] . "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";";
                        } else {
                            return "goto " . helper_name($matches[1], $spec, $op1, $op2);
                        }
                    }
                }
            }, $code);
            break;
        case ZEND_VM_KIND_GOTO:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER_EX\\(\\s*([A-Za-z_]*)\\s*,\\s*([A-Za-z_]*)\\s*,\\s*(.*)\\s*\\);/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "goto " . $matches[1] . ($spec ? "_SPEC" : "") . $prefix[$op1] . $prefix[$op2] . "_HANDLER";
                    } else {
                        if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
                            return $matches[2] . " = " . $matches[3] . "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";";
                        } else {
                            return "goto " . helper_name($matches[1], $spec, $op1, $op2);
                        }
                    }
                }
            }, $code);
            break;
    }
    /* Remove unused free_op1 and free_op2 declarations */
    if ($spec && preg_match_all('/^\\s*zend_free_op\\s+[^;]+;\\s*$/me', $code, $matches, PREG_SET_ORDER)) {
        $n = 0;
        foreach ($matches as $match) {
            $code = preg_replace('/' . preg_quote($match[0], '/') . '/', "\$D{$n}", $code);
            ++$n;
        }
        $del_free_op1 = strpos($code, "free_op1") === false;
        $del_free_op2 = strpos($code, "free_op2") === false;
        $n = 0;
        foreach ($matches as $match) {
            $dcl = $match[0];
            $changed = 0;
            if ($del_free_op1 && strpos($dcl, "free_op1") !== false) {
                $dcl = preg_replace("/free_op1\\s*,\\s*/", "", $dcl);
                $dcl = preg_replace("/free_op1\\s*;/", ";", $dcl);
                $changed = 1;
            }
            if ($del_free_op2 && strpos($dcl, "free_op2") !== false) {
                $dcl = preg_replace("/free_op2\\s*,\\s*/", "", $dcl);
                $dcl = preg_replace("/free_op2\\s*;/", ";", $dcl);
                $changed = 1;
            }
            if ($changed) {
                $dcl = preg_replace("/,\\s*;/", ";", $dcl);
                $dcl = preg_replace("/zend_free_op\\s*;/", "", $dcl);
            }
            $code = preg_replace("/\\\$D{$n}/", $dcl, $code);
            ++$n;
        }
    }
    /* Remove unnecessary ';' */
    $code = preg_replace('/^\\s*;\\s*$/m', '', $code);
    /* Remove WS */
    $code = preg_replace('/[ \\t]+\\n/m', "\n", $code);
    out($f, $code);
}
예제 #2
0
function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name, $extra_spec = null)
{
    global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, $op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref, $op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef, $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, $op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef, $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, $op1_get_obj_zval_ptr_undef, $op2_get_obj_zval_ptr_undef, $op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref, $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, $op1_get_obj_zval_ptr_ptr_undef, $op2_get_obj_zval_ptr_ptr_undef, $op1_free, $op2_free, $op1_free_unfetched, $op2_free_unfetched, $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix, $op_data_type, $op_data_get_zval_ptr, $op_data_get_zval_ptr_deref, $op_data_free_op, $op_data_free_unfetched;
    // Specializing
    $code = preg_replace(array("/OP1_TYPE/", "/OP2_TYPE/", "/OP1_FREE/", "/OP2_FREE/", "/GET_OP1_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP1_ZVAL_PTR_DEREF\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR_DEREF\\(([^)]*)\\)/", "/GET_OP1_ZVAL_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP1_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP1_ZVAL_PTR_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP2_ZVAL_PTR_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR_DEREF\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR_DEREF\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR_PTR\\(([^)]*)\\)/", "/GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF\\(([^)]*)\\)/", "/GET_OP2_OBJ_ZVAL_PTR_PTR_UNDEF\\(([^)]*)\\)/", "/FREE_OP1\\(\\)/", "/FREE_OP2\\(\\)/", "/FREE_OP1_IF_VAR\\(\\)/", "/FREE_OP2_IF_VAR\\(\\)/", "/FREE_OP1_VAR_PTR\\(\\)/", "/FREE_OP2_VAR_PTR\\(\\)/", "/FREE_UNFETCHED_OP1\\(\\)/", "/FREE_UNFETCHED_OP2\\(\\)/", "/^#(\\s*)ifdef\\s+ZEND_VM_SPEC\\s*\n/m", "/^#(\\s*)ifndef\\s+ZEND_VM_SPEC\\s*\n/m", "/\\!defined\\(ZEND_VM_SPEC\\)/m", "/defined\\(ZEND_VM_SPEC\\)/m", "/ZEND_VM_C_LABEL\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/ZEND_VM_C_GOTO\\(\\s*([A-Za-z_]*)\\s*\\)/m", "/^#(\\s*)if\\s+1\\s*\\|\\|.*[^\\\\]\$/m", "/^#(\\s*)if\\s+0\\s*&&.*[^\\\\]\$/m", "/^#(\\s*)ifdef\\s+ZEND_VM_EXPORT\\s*\n/m", "/^#(\\s*)ifndef\\s+ZEND_VM_EXPORT\\s*\n/m", "/OP_DATA_TYPE/", "/GET_OP_DATA_ZVAL_PTR\\(([^)]*)\\)/", "/GET_OP_DATA_ZVAL_PTR_DEREF\\(([^)]*)\\)/", "/FREE_OP_DATA\\(\\)/", "/FREE_UNFETCHED_OP_DATA\\(\\)/", "/RETURN_VALUE_USED\\(opline\\)/", "/arg_num <= MAX_ARG_FLAG_NUM/"), array($op1_type[$op1], $op2_type[$op2], $op1_free[$op1], $op2_free[$op2], $op1_get_zval_ptr[$op1], $op2_get_zval_ptr[$op2], $op1_get_zval_ptr_deref[$op1], $op2_get_zval_ptr_deref[$op2], $op1_get_zval_ptr_undef[$op1], $op2_get_zval_ptr_undef[$op2], $op1_get_zval_ptr_ptr[$op1], $op2_get_zval_ptr_ptr[$op2], $op1_get_zval_ptr_ptr_undef[$op1], $op2_get_zval_ptr_ptr_undef[$op2], $op1_get_obj_zval_ptr[$op1], $op2_get_obj_zval_ptr[$op2], $op1_get_obj_zval_ptr_undef[$op1], $op2_get_obj_zval_ptr_undef[$op2], $op1_get_obj_zval_ptr_deref[$op1], $op2_get_obj_zval_ptr_deref[$op2], $op1_get_obj_zval_ptr_ptr[$op1], $op2_get_obj_zval_ptr_ptr[$op2], $op1_get_obj_zval_ptr_ptr_undef[$op1], $op2_get_obj_zval_ptr_ptr_undef[$op2], $op1_free_op[$op1], $op2_free_op[$op2], $op1_free_op_if_var[$op1], $op2_free_op_if_var[$op2], $op1_free_op_var_ptr[$op1], $op2_free_op_var_ptr[$op2], $op1_free_unfetched[$op1], $op2_free_unfetched[$op2], $op1 != "ANY" || $op2 != "ANY" ? "#\\1if 1\n" : "#\\1if 0\n", $op1 != "ANY" || $op2 != "ANY" ? "#\\1if 0\n" : "#\\1if 1\n", $op1 != "ANY" || $op2 != "ANY" ? "0" : "1", $op1 != "ANY" || $op2 != "ANY" ? "1" : "0", "\\1" . ($spec && $kind != ZEND_VM_KIND_CALL ? "_SPEC" . $prefix[$op1] . $prefix[$op2] . extra_spec_name($extra_spec) : ""), "goto \\1" . ($spec && $kind != ZEND_VM_KIND_CALL ? "_SPEC" . $prefix[$op1] . $prefix[$op2] . extra_spec_name($extra_spec) : ""), "#\\1if 1", "#\\1if 0", $export ? "#\\1if 1\n" : "#\\1if 0\n", $export ? "#\\1if 0\n" : "#\\1if 1\n", $op_data_type[isset($extra_spec['op_data']) ? $extra_spec['op_data'] : "ANY"], $op_data_get_zval_ptr[isset($extra_spec['op_data']) ? $extra_spec['op_data'] : "ANY"], $op_data_get_zval_ptr_deref[isset($extra_spec['op_data']) ? $extra_spec['op_data'] : "ANY"], $op_data_free_op[isset($extra_spec['op_data']) ? $extra_spec['op_data'] : "ANY"], $op_data_free_unfetched[isset($extra_spec['op_data']) ? $extra_spec['op_data'] : "ANY"], isset($extra_spec['retval']) ? $extra_spec['retval'] : "RETURN_VALUE_USED(opline)", isset($extra_spec['quick_arg']) ? $extra_spec['quick_arg'] : "arg_num <= MAX_ARG_FLAG_NUM"), $code);
    if (0 && strpos($code, '{') === 0) {
        $code = "{\n\tfprintf(stderr, \"{$name}\\n\");\n" . substr($code, 1);
    }
    // Updating code according to selected threading model
    switch ($kind) {
        case ZEND_VM_KIND_CALL:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*(,[^)]*)?\\)/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "ZEND_VM_TAIL_CALL(" . opcode_name($matches[1], $spec, $op1, $op2) . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
                    } else {
                        // ZEND_VM_DISPATCH_TO_HELPER
                        if (isset($matches[2])) {
                            // extra args
                            $args = substr(preg_replace("/,\\s*[A-Za-z_]*\\s*,\\s*([^,)\\s]*)\\s*/", ", \$1", $matches[2]), 2);
                            return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(" . $args . " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))";
                        }
                        return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
                    }
                }
            }, $code);
            break;
        case ZEND_VM_KIND_SWITCH:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*(,[^)]*)?\\)/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_LABEL";
                    } else {
                        // ZEND_VM_DISPATCH_TO_HELPER
                        if (isset($matches[2])) {
                            // extra args
                            $args = preg_replace("/,\\s*([A-Za-z_]*)\\s*,\\s*([^,)\\s]*)\\s*/", "\$1 = \$2; ", $matches[2]);
                            return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2);
                        }
                        return "goto " . helper_name($matches[1], $spec, $op1, $op2);
                    }
                }
            }, $code);
            break;
        case ZEND_VM_KIND_GOTO:
            $code = preg_replace_callback(array("/EXECUTE_DATA/m", "/ZEND_VM_DISPATCH_TO_HANDLER\\(\\s*([A-Z_]*)\\s*\\)/m", "/ZEND_VM_DISPATCH_TO_HELPER\\(\\s*([A-Za-z_]*)\\s*(,[^)]*)?\\)/m"), function ($matches) use($spec, $prefix, $op1, $op2) {
                if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
                    return "execute_data";
                } else {
                    if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
                        return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_HANDLER";
                    } else {
                        // ZEND_VM_DISPATCH_TO_HELPER
                        if (isset($matches[2])) {
                            // extra args
                            $args = preg_replace("/,\\s*([A-Za-z_]*)\\s*,\\s*([^,)\\s]*)\\s*/", "\$1 = \$2; ", $matches[2]);
                            return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2);
                        }
                        return "goto " . helper_name($matches[1], $spec, $op1, $op2);
                    }
                }
            }, $code);
            break;
    }
    /* Remove unused free_op1 and free_op2 declarations */
    if ($spec && preg_match_all('/^\\s*zend_free_op\\s+[^;]+;\\s*$/me', $code, $matches, PREG_SET_ORDER)) {
        $n = 0;
        foreach ($matches as $match) {
            $code = preg_replace('/' . preg_quote($match[0], '/') . '/', "\$D{$n}", $code);
            ++$n;
        }
        $del_free_op1 = strpos($code, "free_op1") === false;
        $del_free_op2 = strpos($code, "free_op2") === false;
        $del_free_op_data = strpos($code, "free_op_data") === false;
        $n = 0;
        foreach ($matches as $match) {
            $dcl = $match[0];
            $changed = 0;
            if ($del_free_op1 && strpos($dcl, "free_op1") !== false) {
                $dcl = preg_replace("/free_op1\\s*,\\s*/", "", $dcl);
                $dcl = preg_replace("/free_op1\\s*;/", ";", $dcl);
                $changed = 1;
            }
            if ($del_free_op2 && strpos($dcl, "free_op2") !== false) {
                $dcl = preg_replace("/free_op2\\s*,\\s*/", "", $dcl);
                $dcl = preg_replace("/free_op2\\s*;/", ";", $dcl);
                $changed = 1;
            }
            if ($del_free_op_data && strpos($dcl, "free_op_data") !== false) {
                $dcl = preg_replace("/free_op_data\\s*,\\s*/", "", $dcl);
                $dcl = preg_replace("/free_op_data\\s*;/", ";", $dcl);
                $changed = 1;
            }
            if ($changed) {
                $dcl = preg_replace("/,\\s*;/", ";", $dcl);
                $dcl = preg_replace("/zend_free_op\\s*;/", "", $dcl);
            }
            $code = preg_replace("/\\\$D{$n}/", $dcl, $code);
            ++$n;
        }
    }
    /* Remove unnecessary ';' */
    $code = preg_replace('/^\\s*;\\s*$/m', '', $code);
    /* Remove WS */
    $code = preg_replace('/[ \\t]+\\n/m', "\n", $code);
    out($f, $code);
}