This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
B::Deparse 0.64
[perl5.git] / ext / B / B / Deparse.pm
index a96e3c2..fe820b6 100644 (file)
@@ -1,5 +1,5 @@
 # B::Deparse.pm
-# Copyright (c) 1998, 1999, 2000 Stephen McCamant. All rights reserved.
+# Copyright (c) 1998-2000, 2002, 2003 Stephen McCamant. All rights reserved.
 # This module is free software; you can redistribute and/or modify
 # it under the same terms as Perl itself.
 
@@ -7,19 +7,21 @@
 # but essentially none of his code remains.
 
 package B::Deparse;
-use Carp 'cluck', 'croak';
-use B qw(class main_root main_start main_cv svref_2object opnumber cstring
+use Carp;
+use B qw(class main_root main_start main_cv svref_2object opnumber perlstring
         OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST
-        OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL
-        OPpLVAL_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE
+        OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL OPf_MOD
+        OPpLVAL_INTRO OPpOUR_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE
         OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY
-        OPpCONST_ARYBASE OPpEXISTS_SUB
-        SVf_IOK SVf_NOK SVf_ROK SVf_POK
-         CVf_METHOD CVf_LOCKED CVf_LVALUE
+        OPpCONST_ARYBASE OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER
+        OPpSORT_REVERSE
+        SVf_IOK SVf_NOK SVf_ROK SVf_POK SVpad_OUR SVf_FAKE SVs_RMG SVs_SMG
+         CVf_METHOD CVf_LOCKED CVf_LVALUE CVf_ASSERTION
         PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE PMf_SKIPWHITE
         PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED);
-$VERSION = 0.60;
+$VERSION = 0.64;
 use strict;
+use vars qw/$AUTOLOAD/;
 use warnings ();
 
 # Changes between 0.50 and 0.51:
@@ -34,7 +36,7 @@ use warnings ();
 # - package declarations using cop_stash
 # - subs, formats and code sorted by cop_seq
 # Changes between 0.51 and 0.52:
-# - added pp_threadsv (special variables under USE_THREADS)
+# - added pp_threadsv (special variables under USE_5005THREADS)
 # - added documentation
 # Changes between 0.52 and 0.53:
 # - many changes adding precedence contexts and associativity
@@ -80,7 +82,7 @@ use warnings ();
 # - preliminary version of utf8 tr/// handling
 # Changes after 0.58:
 # - uses of $op->ppaddr changed to new $op->name (done by Sarathy)
-# - added support for Hugo's new OP_SETSTATE (like nextstate) 
+# - added support for Hugo's new OP_SETSTATE (like nextstate)
 # Changes between 0.58 and 0.59
 # - added support for Chip's OP_METHOD_NAMED
 # - added support for Ilya's OPpTARGET_MY optimization
@@ -91,12 +93,36 @@ use warnings ();
 # - separate recognition of constant subs
 # - rewrote continue block handling, now recoginizing for loops
 # - added more control of expanding control structures
+# Changes between 0.60 and 0.61 (mostly by Robin Houston)
+# - many bug-fixes
+# - support for pragmas and 'use'
+# - support for the little-used $[ variable
+# - support for __DATA__ sections
+# - UTF8 support
+# - BEGIN, CHECK, INIT and END blocks
+# - scoping of subroutine declarations fixed
+# - compile-time output from the input program can be suppressed, so that the
+#   output is just the deparsed code. (a change to O.pm in fact)
+# - our() declarations
+# - *all* the known bugs are now listed in the BUGS section
+# - comprehensive test mechanism (TEST -deparse)
+# Changes between 0.62 and 0.63 (mostly by Rafael Garcia-Suarez)
+# - bug-fixes
+# - new switch -P
+# - support for command-line switches (-l, -0, etc.)
+# Changes between 0.63 and 0.64
+# - support for //, CHECK blocks, and assertions
+# - improved handling of foreach loops and lexicals
+# - option to use Data::Dumper for constants
+# - more bug fixes
+# - discovered lots more bugs not yet fixed
 
 # Todo:
+#  (See also BUGS section at the end of this file)
+#
 # - finish tr/// changes
 # - add option for even more parens (generalize \&foo change)
 # - left/right context
-# - treat top-level block specially for incremental output
 # - copy comments (look at real text with $^P?)
 # - avoid semis in one-statement blocks
 # - associativity of &&=, ||=, ?:
@@ -106,13 +132,58 @@ use warnings ();
 # - more style options: brace style, hex vs. octal, quotes, ...
 # - print big ints as hex/octal instead of decimal (heuristic?)
 # - handle `my $x if 0'?
-# - coordinate with Data::Dumper (both directions? see previous)
 # - version using op_next instead of op_first/sibling?
 # - avoid string copies (pass arrays, one big join?)
 # - here-docs?
 
-# Tests that will always fail:
-# comp/redef.t -- all (redefinition happens at compile time)
+# Current test.deparse failures
+# comp/assertions 38 - disabled assertions should be like "my($x) if 0"
+#    'sub f : assertion {}; no assertions; my $x=1; {f(my $x=2); print "$x\n"}'
+# comp/hints 6 - location of BEGIN blocks wrt. block openings
+# run/switchI 1 - missing -I switches entirely
+#    perl -Ifoo -e 'print @INC'
+# op/caller 2 - warning mask propagates backwards before warnings::register
+#    'use warnings; BEGIN {${^WARNING_BITS} eq "U"x12;} use warnings::register'
+# op/getpid 2 - can't assign to shared my() declaration (threads only)
+#    'my $x : shared = 5'
+# op/override 7 - parens on overriden require change v-string interpretation
+#    'BEGIN{*CORE::GLOBAL::require=sub {}} require v5.6'
+#    c.f. 'BEGIN { *f = sub {0} }; f 2'
+# op/pat 774 - losing Unicode-ness of Latin1-only strings
+#    'use charnames ":short"; $x="\N{latin:a with acute}"'
+# op/recurse 12 - missing parens on recursive call makes it look like method
+#    'sub f { f($x) }'
+# op/subst 90 - inconsistent handling of utf8 under "use utf8"
+# op/taint 29 - "use re 'taint'" deparsed in the wrong place wrt. block open
+# op/tiehandle compile - "use strict" deparsed in the wrong place
+# uni/tr_ several
+# ext/B/t/xref 11 - line numbers when we add newlines to one-line subs
+# ext/Data/Dumper/t/dumper compile
+# ext/DB_file/several
+# ext/Encode/several
+# ext/Ernno/Errno warnings
+# ext/IO/lib/IO/t/io_sel 23
+# ext/PerlIO/t/encoding compile
+# ext/POSIX/t/posix 6
+# ext/Socket/Socket 8
+# ext/Storable/t/croak compile
+# lib/Attribute/Handlers/t/multi compile
+# lib/bignum/ several
+# lib/charnames 35
+# lib/constant 32
+# lib/English 40
+# lib/ExtUtils/t/bytes 4
+# lib/File/DosGlob compile
+# lib/Filter/Simple/t/data 1
+# lib/Math/BigInt/t/constant 1
+# lib/Net/t/config Deparse-warning
+# lib/overload compile
+# lib/Switch/ several
+# lib/Symbol 4
+# lib/Test/Simple several
+# lib/Term/Complete
+# lib/Tie/File/t/29_downcopy 5
+# lib/vars 22
 
 # Object fields (were globals):
 #
@@ -120,7 +191,7 @@ use warnings ();
 # (local($a), local($b)) and local($a, $b) have the same internal
 # representation but the short form looks better. We notice we can
 # use a large-scale local when checking the list, but need to prevent
-# individual locals too. This hash holds the addresses of OPs that 
+# individual locals too. This hash holds the addresses of OPs that
 # have already had their local-ness accounted for. The same thing
 # is done with my().
 #
@@ -153,6 +224,9 @@ use warnings ();
 # keys are names of subs for which we've printed declarations.
 # That means we can omit parentheses from the arguments.
 #
+# subs_deparsed
+# Keeps track of fully qualified names of all deparsed subs.
+#
 # parens: -p
 # linenums: -l
 # unquote: -q
@@ -203,6 +277,7 @@ use warnings ();
 #  3 left        and
 #  2 left        or xor
 #  1             statement modifiers
+#  0.5           statements, but still print scopes as do { ... }
 #  0             statement level
 
 # Nonprinting characters with special meaning:
@@ -223,12 +298,17 @@ sub todo {
     my($cv, $is_form) = @_;
     return unless ($cv->FILE eq $0 || exists $self->{files}{$cv->FILE});
     my $seq;
-    if (!null($cv->START) and is_state($cv->START)) {
+    if ($cv->OUTSIDE_SEQ) {
+       $seq = $cv->OUTSIDE_SEQ;
+    } elsif (!null($cv->START) and is_state($cv->START)) {
        $seq = $cv->START->cop_seq;
     } else {
        $seq = 0;
     }
     push @{$self->{'subs_todo'}}, [$seq, $cv, $is_form];
+    unless ($is_form || class($cv->STASH) eq 'SPECIAL') {
+       $self->{'subs_deparsed'}{$cv->STASH->NAME."::".$cv->GV->NAME} = 1;
+    }
 }
 
 sub next_todo {
@@ -244,12 +324,28 @@ sub next_todo {
        $self->{'subs_declared'}{$name} = 1;
        if ($name eq "BEGIN") {
            my $use_dec = $self->begin_is_use($cv);
-           if (defined ($use_dec)) {
+           if (defined ($use_dec) and $self->{'expand'} < 5) {
                return () if 0 == length($use_dec);
                return $use_dec;
            }
        }
-        return "sub $name " . $self->deparse_sub($cv);
+       my $l = '';
+       if ($self->{'linenums'}) {
+           my $line = $gv->LINE;
+           my $file = $gv->FILE;
+           $l = "\n\f#line $line \"$file\"\n";
+       }
+       my $p = '';
+       if (class($cv->STASH) ne "SPECIAL") {
+           my $stash = $cv->STASH->NAME;
+           if ($stash ne $self->{'curstash'}) {
+               $p = "package $stash;\n";
+               $name = "$self->{'curstash'}::$name" unless $name =~ /::/;
+               $self->{'curstash'} = $stash;
+           }
+           $name =~ s/^\Q$stash\E:://;
+       }
+        return "${p}${l}sub $name " . $self->deparse_sub($cv);
     }
 }
 
@@ -257,6 +353,7 @@ sub next_todo {
 sub begin_is_use {
     my ($self, $cv) = @_;
     my $root = $cv->ROOT;
+    local @$self{qw'curcv curcvlex'} = ($cv);
 #require B::Debug;
 #B::walkoptree($cv->ROOT, "debug");
     my $lineseq = $root->first;
@@ -273,7 +370,7 @@ sub begin_is_use {
        $module =~ s/.pm$//;
     }
     else {
-       $module = const($self->const_sv($req_op->first));
+       $module = $self->const($self->const_sv($req_op->first), 6);
     }
 
     my $version;
@@ -285,8 +382,18 @@ sub begin_is_use {
 
        return unless $self->const_sv($constop)->PV eq $module;
        $constop = $constop->sibling;
-
-       $version = $self->const_sv($constop)->int_value;
+       $version = $self->const_sv($constop);
+       if (class($version) eq "IV") {
+           $version = $version->int_value;
+       } elsif (class($version) eq "NV") {
+           $version = $version->NV;
+       } elsif (class($version) ne "PVMG") {
+           # Includes PVIV and PVNV
+           $version = $version->PV;
+       } else {
+           # version specified as a v-string
+           $version = 'v'.join '.', map ord, split //, $version->PV;
+       }
        $constop = $constop->sibling;
        return if $constop->name ne "method_named";
        return if $self->const_sv($constop)->PV ne "VERSION";
@@ -304,18 +411,18 @@ sub begin_is_use {
     # See if there are import arguments
     my $args = '';
 
-    my $constop = $entersub->first->sibling; # Skip over pushmark
-    return unless $self->const_sv($constop)->PV eq $module;
+    my $svop = $entersub->first->sibling; # Skip over pushmark
+    return unless $self->const_sv($svop)->PV eq $module;
 
     # Pull out the arguments
-    for ($constop=$constop->sibling; $constop->name eq "const";
-               $constop = $constop->sibling) {
+    for ($svop=$svop->sibling; $svop->name ne "method_named";
+               $svop = $svop->sibling) {
        $args .= ", " if length($args);
-       $args .= $self->deparse($constop, 6);
+       $args .= $self->deparse($svop, 6);
     }
 
     my $use = 'use';
-    my $method_named = $constop;
+    my $method_named = $svop;
     return if $method_named->name ne "method_named";
     my $method_name = $self->const_sv($method_named)->PV;
 
@@ -358,11 +465,25 @@ sub stash_subs {
        next if $key eq 'main::';       # avoid infinite recursion
        my $class = class($val);
        if ($class eq "PV") {
-           # Just a prototype
+           # Just a prototype. As an ugly but fairly effective way
+           # to find out if it belongs here is to see if the AUTOLOAD
+           # (if any) for the stash was defined in one of our files.
+           my $A = $stash{"AUTOLOAD"};
+           if (defined ($A) && class($A) eq "GV" && defined($A->CV)
+               && class($A->CV) eq "CV") {
+               my $AF = $A->FILE;
+               next unless $AF eq $0 || exists $self->{'files'}{$AF};
+           }
            push @{$self->{'protos_todo'}}, [$pack . $key, $val->PV];
        } elsif ($class eq "IV") {
-           # Just a name
-           push @{$self->{'protos_todo'}}, [$pack . $key, undef];          
+           # Just a name. As above.
+           my $A = $stash{"AUTOLOAD"};
+           if (defined ($A) && class($A) eq "GV" && defined($A->CV)
+               && class($A->CV) eq "CV") {
+               my $AF = $A->FILE;
+               next unless $AF eq $0 || exists $self->{'files'}{$AF};
+           }
+           push @{$self->{'protos_todo'}}, [$pack . $key, undef];
        } elsif ($class eq "GV") {
            if (class(my $cv = $val->CV) ne "SPECIAL") {
                next if $self->{'subs_done'}{$$val}++;
@@ -417,18 +538,19 @@ sub style_opts {
 sub new {
     my $class = shift;
     my $self = bless {}, $class;
-    $self->{'subs_todo'} = [];
-    $self->{'files'} = {};
-    $self->{'curstash'} = "main";
-    $self->{'curcop'} = undef;
     $self->{'cuddle'} = "\n";
-    $self->{'indent_size'} = 4;
-    $self->{'use_tabs'} = 0;
+    $self->{'curcop'} = undef;
+    $self->{'curstash'} = "main";
+    $self->{'ex_const'} = "'???'";
     $self->{'expand'} = 0;
-    $self->{'unquote'} = 0;
+    $self->{'files'} = {};
+    $self->{'indent_size'} = 4;
     $self->{'linenums'} = 0;
     $self->{'parens'} = 0;
-    $self->{'ex_const'} = "'???'";
+    $self->{'subs_todo'} = [];
+    $self->{'unquote'} = 0;
+    $self->{'use_dumper'} = 0;
+    $self->{'use_tabs'} = 0;
 
     $self->{'ambient_arybase'} = 0;
     $self->{'ambient_warnings'} = undef; # Assume no lexical warnings
@@ -436,12 +558,17 @@ sub new {
     $self->init();
 
     while (my $arg = shift @_) {
-       if ($arg =~ /^-f(.*)/) {
+       if ($arg eq "-d") {
+           $self->{'use_dumper'} = 1;
+           require Data::Dumper;
+       } elsif ($arg =~ /^-f(.*)/) {
            $self->{'files'}{$1} = 1;
-       } elsif ($arg eq "-p") {
-           $self->{'parens'} = 1;
        } elsif ($arg eq "-l") {
            $self->{'linenums'} = 1;
+       } elsif ($arg eq "-p") {
+           $self->{'parens'} = 1;
+       } elsif ($arg eq "-P") {
+           $self->{'noproto'} = 1;
        } elsif ($arg eq "-q") {
            $self->{'unquote'} = 1;
        } elsif (substr($arg, 0, 2) eq "-s") {
@@ -453,9 +580,15 @@ sub new {
     return $self;
 }
 
-sub WARN_MASK () {
-    # Mask out the bits that C<use vars> uses
-    $warnings::Bits{all} | $warnings::DeadBits{all};
+{
+    # Mask out the bits that L<warnings::register> uses
+    my $WARN_MASK;
+    BEGIN {
+       $WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all};
+    }
+    sub WARN_MASK () {
+       return $WARN_MASK;
+    }
 }
 
 # Initialise the contextual information, either from
@@ -476,21 +609,42 @@ sub init {
 
 sub compile {
     my(@args) = @_;
-    return sub { 
+    return sub {
        my $self = B::Deparse->new(@args);
+       # First deparse command-line args
+       if (defined $^I) { # deparse -i
+           print q(BEGIN { $^I = ).perlstring($^I).qq(; }\n);
+       }
+       if ($^W) { # deparse -w
+           print qq(BEGIN { \$^W = $^W; }\n);
+       }
+       if ($/ ne "\n" or defined $O::savebackslash) { # deparse -l and -0
+           my $fs = perlstring($/) || 'undef';
+           my $bs = perlstring($O::savebackslash) || 'undef';
+           print qq(BEGIN { \$/ = $fs; \$\\ = $bs; }\n);
+       }
        my @BEGINs  = B::begin_av->isa("B::AV") ? B::begin_av->ARRAY : ();
+       my @CHECKs  = B::check_av->isa("B::AV") ? B::check_av->ARRAY : ();
        my @INITs   = B::init_av->isa("B::AV") ? B::init_av->ARRAY : ();
        my @ENDs    = B::end_av->isa("B::AV") ? B::end_av->ARRAY : ();
-       for my $block (@BEGINs, @INITs, @ENDs) {
+       for my $block (@BEGINs, @CHECKs, @INITs, @ENDs) {
            $self->todo($block, 0);
        }
        $self->stash_subs();
+       local($SIG{"__DIE__"}) =
+         sub {
+             if ($self->{'curcop'}) {
+                 my $cop = $self->{'curcop'};
+                 my($line, $file) = ($cop->line, $cop->file);
+                 print STDERR "While deparsing $file near line $line,\n";
+             }
+           };
        $self->{'curcv'} = main_cv;
        $self->{'curcvlex'} = undef;
        print $self->print_protos;
        @{$self->{'subs_todo'}} =
          sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}};
-       print $self->indent($self->deparse(main_root, 0)), "\n"
+       print $self->indent($self->deparse_root(main_root)), "\n"
          unless null main_root;
        my @text;
        while (scalar(@{$self->{'subs_todo'}})) {
@@ -500,9 +654,13 @@ sub compile {
 
        # Print __DATA__ section, if necessary
        no strict 'refs';
-       if (defined *{$self->{'curstash'}."::DATA"}{IO}) {
+       my $laststash = defined $self->{'curcop'}
+           ? $self->{'curcop'}->stash->NAME : $self->{'curstash'};
+       if (defined *{$laststash."::DATA"}{IO}) {
+           print "package $laststash;\n"
+               unless $laststash eq $self->{'curstash'};
            print "__DATA__\n";
-           print readline(*{$self->{'curstash'}."::DATA"});
+           print readline(*{$laststash."::DATA"});
        }
     }
 }
@@ -510,7 +668,7 @@ sub compile {
 sub coderef2text {
     my $self = shift;
     my $sub = shift;
-    croak "Usage: ->coderef2text(CODEREF)" unless ref($sub) eq "CODE";
+    croak "Usage: ->coderef2text(CODEREF)" unless UNIVERSAL::isa($sub, "CODE");
 
     $self->init();
     return $self->indent($self->deparse_sub(svref_2object($sub)));
@@ -564,13 +722,13 @@ sub ambient_pragmas {
        elsif ($name eq 're') {
            require re;
            if ($val eq 'none') {
-               $hint_bits &= ~re::bits(qw/taint eval asciirange/);
+               $hint_bits &= ~re::bits(qw/taint eval/);
                next();
            }
 
            my @names;
            if ($val eq 'all') {
-               @names = qw/taint eval asciirange/;
+               @names = qw/taint eval/;
            }
            elsif (ref $val) {
                @names = @$val;
@@ -583,7 +741,7 @@ sub ambient_pragmas {
 
        elsif ($name eq 'warnings') {
            if ($val eq 'none') {
-               $warning_bits = "\0"x12;
+               $warning_bits = $warnings::NONE;
                next();
            }
 
@@ -595,7 +753,7 @@ sub ambient_pragmas {
                @names = split/\s+/, $val;
            }
 
-           $warning_bits = "\0"x12 if !defined ($warning_bits);
+           $warning_bits = $warnings::NONE if !defined ($warning_bits);
            $warning_bits |= warnings::bits(@names);
        }
 
@@ -620,6 +778,7 @@ sub ambient_pragmas {
     $self->{'ambient_hints'} = $hint_bits;
 }
 
+# This method is the inner loop, so try to keep it simple
 sub deparse {
     my $self = shift;
     my($op, $cx) = @_;
@@ -662,34 +821,53 @@ sub deparse_sub {
     my $self = shift;
     my $cv = shift;
     my $proto = "";
+Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL");
 Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
     local $self->{'curcop'} = $self->{'curcop'};
     if ($cv->FLAGS & SVf_POK) {
        $proto = "(". $cv->PV . ") ";
     }
-    if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE)) {
+    if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE|CVf_ASSERTION)) {
         $proto .= ": ";
         $proto .= "lvalue " if $cv->CvFLAGS & CVf_LVALUE;
         $proto .= "locked " if $cv->CvFLAGS & CVf_LOCKED;
         $proto .= "method " if $cv->CvFLAGS & CVf_METHOD;
+        $proto .= "assertion " if $cv->CvFLAGS & CVf_ASSERTION;
     }
 
     local($self->{'curcv'}) = $cv;
     local($self->{'curcvlex'});
     local(@$self{qw'curstash warnings hints'})
                = @$self{qw'curstash warnings hints'};
+    my $body;
     if (not null $cv->ROOT) {
-       # skip leavesub
-       return $proto . "{\n\t" . 
-           $self->deparse($cv->ROOT->first, 0) . "\n\b}\n"; 
+       my $lineseq = $cv->ROOT->first;
+       if ($lineseq->name eq "lineseq") {
+           my @ops;
+           for(my$o=$lineseq->first; $$o; $o=$o->sibling) {
+               push @ops, $o;
+           }
+           $body = $self->lineseq(undef, @ops).";";
+           my $scope_en = $self->find_scope_en($lineseq);
+           if (defined $scope_en) {
+               my $subs = join"", $self->seq_subs($scope_en);
+               $body .= ";\n$subs" if length($subs);
+           }
+       }
+       else {
+           $body = $self->deparse($cv->ROOT->first, 0);
+       }
     }
-    my $sv = $cv->const_sv;
-    if ($$sv) {
-       # uh-oh. inlinable sub... format it differently
-       return $proto . "{ " . const($sv) . " }\n";
-    } else { # XSUB? (or just a declaration)
-       return "$proto;\n";
+    else {
+       my $sv = $cv->const_sv;
+       if ($$sv) {
+           # uh-oh. inlinable sub... format it differently
+           return $proto . "{ " . $self->const($sv, 0) . " }\n";
+       } else { # XSUB? (or just a declaration)
+           return "$proto;\n";
+       }
     }
+    return $proto ."{\n\t$body\n\b}" ."\n";
 }
 
 sub deparse_format {
@@ -698,31 +876,34 @@ sub deparse_format {
     my @text;
     local($self->{'curcv'}) = $form;
     local($self->{'curcvlex'});
+    local($self->{'in_format'}) = 1;
     local(@$self{qw'curstash warnings hints'})
-               = @$self{'curstash warnings hints'};
+               = @$self{qw'curstash warnings hints'};
     my $op = $form->ROOT;
     my $kid;
+    return "\f." if $op->first->name eq 'stub'
+                || $op->first->name eq 'nextstate';
     $op = $op->first->first; # skip leavewrite, lineseq
     while (not null $op) {
        $op = $op->sibling; # skip nextstate
        my @exprs;
        $kid = $op->first->sibling; # skip pushmark
-       push @text, $self->const_sv($kid)->PV;
+       push @text, "\f".$self->const_sv($kid)->PV;
        $kid = $kid->sibling;
        for (; not null $kid; $kid = $kid->sibling) {
            push @exprs, $self->deparse($kid, 0);
        }
-       push @text, join(", ", @exprs)."\n" if @exprs;
+       push @text, "\f".join(", ", @exprs)."\n" if @exprs;
        $op = $op->sibling;
     }
-    return join("", @text) . ".";
+    return join("", @text) . "\f.";
 }
 
 sub is_scope {
     my $op = shift;
     return $op->name eq "leave" || $op->name eq "scope"
       || $op->name eq "lineseq"
-       || ($op->name eq "null" && class($op) eq "UNOP" 
+       || ($op->name eq "null" && class($op) eq "UNOP"
            && (is_scope($op->first) || $op->first->name eq "enter"));
 }
 
@@ -733,7 +914,7 @@ sub is_state {
 
 sub is_miniwhile { # check for one-line loop (`foo() while $y--')
     my $op = shift;
-    return (!null($op) and null($op->sibling) 
+    return (!null($op) and null($op->sibling)
            and $op->name eq "null" and class($op) eq "UNOP"
            and (($op->first->name =~ /^(and|or)$/
                  and $op->first->first->sibling->name eq "lineseq")
@@ -743,6 +924,24 @@ sub is_miniwhile { # check for one-line loop (`foo() while $y--')
                 ));
 }
 
+# Check if the op and its sibling are the initialization and the rest of a
+# for (..;..;..) { ... } loop
+sub is_for_loop {
+    my $op = shift;
+    # This OP might be almost anything, though it won't be a
+    # nextstate. (It's the initialization, so in the canonical case it
+    # will be an sassign.) The sibling is a lineseq whose first child
+    # is a nextstate and whose second is a leaveloop.
+    my $lseq = $op->sibling;
+    if (!is_state $op and !null($lseq) and $lseq->name eq "lineseq") {
+       if ($lseq->first && !null($lseq->first) && is_state($lseq->first)
+           && (my $sib = $lseq->first->sibling)) {
+           return (!null($sib) && $sib->name eq "leaveloop");
+       }
+    }
+    return 0;
+}
+
 sub is_scalar {
     my $op = shift;
     return ($op->name eq "rv2sv" or
@@ -773,9 +972,16 @@ sub maybe_parens_unop {
     my $self = shift;
     my($name, $kid, $cx) = @_;
     if ($cx > 16 or $self->{'parens'}) {
-       return "$name(" . $self->deparse($kid, 1) . ")";
+       $kid =  $self->deparse($kid, 1);
+       if ($name eq "umask" && $kid =~ /^\d+$/) {
+           $kid = sprintf("%#o", $kid);
+       }
+       return "$name($kid)";
     } else {
        $kid = $self->deparse($kid, 16);
+       if ($name eq "umask" && $kid =~ /^\d+$/) {
+           $kid = sprintf("%#o", $kid);
+       }
        if (substr($kid, 0, 1) eq "\cS") {
            # use kid's parens
            return $name . substr($kid, 1);
@@ -802,11 +1008,18 @@ sub maybe_parens_func {
 sub maybe_local {
     my $self = shift;
     my($op, $cx, $text) = @_;
-    if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
+    my $our_intro = ($op->name =~ /^(gv|rv2)[ash]v$/) ? OPpOUR_INTRO : 0;
+    if ($op->private & (OPpLVAL_INTRO|$our_intro)
+       and not $self->{'avoid_local'}{$$op}) {
+       my $our_local = ($op->private & OPpLVAL_INTRO) ? "local" : "our";
+       if( $our_local eq 'our' ) {
+           die "Unexpected our($text)\n" unless $text =~ /^\W(\w+::)*\w+\z/;
+           $text =~ s/(\w+::)+//;
+       }
         if (want_scalar($op)) {
-           return "local $text";
+           return "$our_local $text";
        } else {
-           return $self->maybe_parens_func("local", $text, $cx, 16);
+           return $self->maybe_parens_func("$our_local", $text, $cx, 16);
        }
     } else {
        return $text;
@@ -828,7 +1041,7 @@ sub maybe_targmy {
 sub padname_sv {
     my $self = shift;
     my $targ = shift;
-    return (($self->{'curcv'}->PADLIST->ARRAY)[0]->ARRAY)[$targ];
+    return $self->{'curcv'}->PADLIST->ARRAYelt(0)->ARRAYelt($targ);
 }
 
 sub maybe_my {
@@ -848,111 +1061,71 @@ sub maybe_my {
 # The following OPs don't have functions:
 
 # pp_padany -- does not exist after parsing
-# pp_rcatline -- does not exist
-
-sub pp_enter { # see also leave
-    cluck "unexpected OP_ENTER";
-    return "XXX";
-}
-
-sub pp_pushmark { # see also list
-    cluck "unexpected OP_PUSHMARK";
-    return "XXX";
-}
-
-sub pp_leavesub { # see also deparse_sub
-    cluck "unexpected OP_LEAVESUB";
-    return "XXX";
-}
-
-sub pp_leavewrite { # see also deparse_format
-    cluck "unexpected OP_LEAVEWRITE";
-    return "XXX";
-}
-
-sub pp_method { # see also entersub
-    cluck "unexpected OP_METHOD";
-    return "XXX";
-}
-
-sub pp_regcmaybe { # see also regcomp
-    cluck "unexpected OP_REGCMAYBE";
-    return "XXX";
-}
-
-sub pp_regcreset { # see also regcomp
-    cluck "unexpected OP_REGCRESET";
-    return "XXX";
-}
-
-sub pp_substcont { # see also subst
-    cluck "unexpected OP_SUBSTCONT";
-    return "XXX";
-}
-
-sub pp_grepstart { # see also grepwhile
-    cluck "unexpected OP_GREPSTART";
-    return "XXX";
-}
-
-sub pp_mapstart { # see also mapwhile
-    cluck "unexpected OP_MAPSTART";
-    return "XXX";
-}
 
-sub pp_flip { # see also flop
-    cluck "unexpected OP_FLIP";
-    return "XXX";
-}
-
-sub pp_iter { # see also leaveloop
-    cluck "unexpected OP_ITER";
-    return "XXX";
-}
-
-sub pp_enteriter { # see also leaveloop
-    cluck "unexpected OP_ENTERITER";
-    return "XXX";
-}
-
-sub pp_enterloop { # see also leaveloop
-    cluck "unexpected OP_ENTERLOOP";
-    return "XXX";
+sub AUTOLOAD {
+    if ($AUTOLOAD =~ s/^.*::pp_//) {
+       warn "unexpected OP_".uc $AUTOLOAD;
+       return "XXX";
+    } else {
+       die "Undefined subroutine $AUTOLOAD called";
+    }
 }
 
-sub pp_leaveeval { # see also entereval
-    cluck "unexpected OP_LEAVEEVAL";
-    return "XXX";
-}
-
-sub pp_entertry { # see also leavetry
-    cluck "unexpected OP_ENTERTRY";
-    return "XXX";
-}
+sub DESTROY {} #       Do not AUTOLOAD
 
+# $root should be the op which represents the root of whatever
+# we're sequencing here. If it's undefined, then we don't append
+# any subroutine declarations to the deparsed ops, otherwise we
+# append appropriate declarations.
 sub lineseq {
-    my $self = shift;
-    my(@ops) = @_;
+    my($self, $root, @ops) = @_;
     my($expr, @exprs);
+
+    my $out_cop = $self->{'curcop'};
+    my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef;
+    my $limit_seq;
+    if (defined $root) {
+       $limit_seq = $out_seq;
+       my $nseq = $self->find_scope_st($root->sibling) if ${$root->sibling};
+       $limit_seq = $nseq if !defined($limit_seq)
+                          or defined($nseq) && $nseq < $limit_seq;
+    }
+    $limit_seq = $self->{'limit_seq'}
+       if defined($self->{'limit_seq'})
+       && (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq);
+    local $self->{'limit_seq'} = $limit_seq;
     for (my $i = 0; $i < @ops; $i++) {
        $expr = "";
        if (is_state $ops[$i]) {
            $expr = $self->deparse($ops[$i], 0);
            $i++;
-           last if $i > $#ops;
+           if ($i > $#ops) {
+               push @exprs, $expr;
+               last;
+           }
        }
-       if (!is_state $ops[$i] and $ops[$i+1] and !null($ops[$i+1]) and
-           $ops[$i+1]->name eq "leaveloop" and $self->{'expand'} < 3)
+       if (!is_state $ops[$i] and (my $ls = $ops[$i+1]) and
+           !null($ops[$i+1]) and $ops[$i+1]->name eq "lineseq")
        {
-           push @exprs, $expr . $self->for_loop($ops[$i], 0);
-           $i++;
-           next;
+           if ($ls->first && !null($ls->first) && is_state($ls->first)
+               && (my $sib = $ls->first->sibling)) {
+               if (!null($sib) && $sib->name eq "leaveloop") {
+                   push @exprs, $expr . $self->for_loop($ops[$i], 0);
+                   $i++;
+                   next;
+               }
+           }
        }
-       $expr .= $self->deparse($ops[$i], 0);
-       push @exprs, $expr if length $expr;
+       $expr .= $self->deparse($ops[$i], (@ops != 1)/2);
+       $expr =~ s/;\n?\z//;
+       push @exprs, $expr;
+    }
+    my $body = join(";\n", grep {length} @exprs);
+    my $subs = "";
+    if (defined $root && defined $limit_seq && !$self->{'in_format'}) {
+       $subs = join "\n", $self->seq_subs($limit_seq);
     }
-    for(@exprs[0..@exprs-1]) { s/;\n\z// }
-    return join(";\n", @exprs);
+    return join(";\n", grep {length} $body, $subs);
 }
 
 sub scopeop {
@@ -987,9 +1160,9 @@ sub scopeop {
        push @kids, $kid;
     }
     if ($cx > 0) { # inside an expression, (a do {} while for lineseq)
-       return "do { " . $self->lineseq(@kids) . " }";
+       return "do {\n\t" . $self->lineseq($op, @kids) . "\n\b}";
     } else {
-       my $lineseq = $self->lineseq(@kids);
+       my $lineseq = $self->lineseq($op, @kids);
        return (length ($lineseq) ? "$lineseq;" : "");
     }
 }
@@ -998,6 +1171,43 @@ sub pp_scope { scopeop(0, @_); }
 sub pp_lineseq { scopeop(0, @_); }
 sub pp_leave { scopeop(1, @_); }
 
+# This is a special case of scopeop and lineseq, for the case of the
+# main_root. The difference is that we print the output statements as
+# soon as we get them, for the sake of impatient users.
+sub deparse_root {
+    my $self = shift;
+    my($op) = @_;
+    local(@$self{qw'curstash warnings hints'})
+      = @$self{qw'curstash warnings hints'};
+    my @kids;
+    for (my $kid = $op->first->sibling; !null($kid); $kid = $kid->sibling) {
+       push @kids, $kid;
+    }
+    for (my $i = 0; $i < @kids; $i++) {
+       my $expr = "";
+       if (is_state $kids[$i]) {
+           $expr = $self->deparse($kids[$i], 0);
+           $i++;
+           if ($i > $#kids) {
+               print $self->indent($expr);
+               last;
+           }
+       }
+       if (is_for_loop($kids[$i])) {
+           $expr .= $self->for_loop($kids[$i], 0);
+           $expr .= ";\n" unless $i == $#kids;
+           print $self->indent($expr);
+           $i++;
+           next;
+       }
+       $expr .= $self->deparse($kids[$i], (@kids != 1)/2);
+       $expr =~ s/;\n?\z//;
+       $expr .= ";";
+       print $self->indent($expr);
+       print "\n" unless $i == $#kids;
+    }
+}
+
 # The BEGIN {} is used here because otherwise this code isn't executed
 # when you run B::Deparse on itself.
 my %globalnames;
@@ -1007,18 +1217,19 @@ BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
 sub gv_name {
     my $self = shift;
     my $gv = shift;
-Carp::confess() if $gv->isa("B::CV");
+Carp::confess() unless ref($gv) eq "B::GV";
     my $stash = $gv->STASH->NAME;
     my $name = $gv->SAFENAME;
-    if ($stash eq $self->{'curstash'} or $globalnames{$name}
+    if (($stash eq 'main' && $globalnames{$name})
+       or ($stash eq $self->{'curstash'} && !$globalnames{$name})
        or $name =~ /^[^A-Za-z_]/)
     {
        $stash = "";
     } else {
        $stash = $stash . "::";
     }
-    if ($name =~ /^\^../) {
-        $name = "{$name}";       # ${^WARNING_BITS} etc
+    if ($name =~ /^(\^..|{)/) {
+        $name = "{$name}";       # ${^WARNING_BITS}, etc and ${
     }
     return $stash . $name;
 }
@@ -1031,7 +1242,7 @@ sub stash_variable {
 
     return "$prefix$name" if $name =~ /::/;
 
-    unless ($prefix eq '$' || $prefix eq '@' ||
+    unless ($prefix eq '$' || $prefix eq '@' || #'
            $prefix eq '%' || $prefix eq '$#') {
        return "$prefix$name";
     }
@@ -1045,6 +1256,7 @@ sub lex_in_scope {
     my ($self, $name) = @_;
     $self->populate_curcvlex() if !defined $self->{'curcvlex'};
 
+    return 0 if !defined($self->{'curcop'});
     my $seq = $self->{'curcop'}->cop_seq;
     return 0 if !exists $self->{'curcvlex'}{$name};
     for my $a (@{$self->{'curcvlex'}{$name}}) {
@@ -1056,36 +1268,59 @@ sub lex_in_scope {
 
 sub populate_curcvlex {
     my $self = shift;
-    for (my $cv = $self->{'curcv'}; $$cv; $cv = $cv->OUTSIDE) {
-       my @padlist = $cv->PADLIST->ARRAY;
+    for (my $cv = $self->{'curcv'}; class($cv) eq "CV"; $cv = $cv->OUTSIDE) {
+       my $padlist = $cv->PADLIST;
+       # an undef CV still in lexical chain
+       next if class($padlist) eq "SPECIAL";
+       my @padlist = $padlist->ARRAY;
        my @ns = $padlist[0]->ARRAY;
 
        for (my $i=0; $i<@ns; ++$i) {
            next if class($ns[$i]) eq "SPECIAL";
+           next if $ns[$i]->FLAGS & SVpad_OUR;  # Skip "our" vars
            if (class($ns[$i]) eq "PV") {
                # Probably that pesky lexical @_
                next;
            }
             my $name = $ns[$i]->PVX;
-           my $seq_st = $ns[$i]->NVX;
-           my $seq_en = int($ns[$i]->IVX);
+           my ($seq_st, $seq_en) =
+               ($ns[$i]->FLAGS & SVf_FAKE)
+                   ? (0, 999999)
+                   : ($ns[$i]->NVX, $ns[$i]->IVX);
 
            push @{$self->{'curcvlex'}{$name}}, [$seq_st, $seq_en];
        }
     }
 }
 
-# Recurses down the tree, looking for a COP
-sub find_cop {
-    my ($self, $op) = @_;
-    if ($op->flags & OPf_KIDS) {
-       for (my $o=$op->first; $$o; $o=$o->sibling) {
-           return $o if is_state($o);
-           my $r = $self->find_cop($o);
-           return $r if defined $r;
+sub find_scope_st { ((find_scope(@_))[0]); }
+sub find_scope_en { ((find_scope(@_))[1]); }
+
+# Recurses down the tree, looking for pad variable introductions and COPs
+sub find_scope {
+    my ($self, $op, $scope_st, $scope_en) = @_;
+    carp("Undefined op in find_scope") if !defined $op;
+    return ($scope_st, $scope_en) unless $op->flags & OPf_KIDS;
+
+    for (my $o=$op->first; $$o; $o=$o->sibling) {
+       if ($o->name =~ /^pad.v$/ && $o->private & OPpLVAL_INTRO) {
+           my $s = int($self->padname_sv($o->targ)->NVX);
+           my $e = $self->padname_sv($o->targ)->IVX;
+           $scope_st = $s if !defined($scope_st) || $s < $scope_st;
+           $scope_en = $e if !defined($scope_en) || $e > $scope_en;
+       }
+       elsif (is_state($o)) {
+           my $c = $o->cop_seq;
+           $scope_st = $c if !defined($scope_st) || $c < $scope_st;
+           $scope_en = $c if !defined($scope_en) || $c > $scope_en;
+       }
+       elsif ($o->flags & OPf_KIDS) {
+           ($scope_st, $scope_en) =
+               $self->find_scope($o, $scope_st, $scope_en)
        }
     }
-    return undef;
+
+    return ($scope_st, $scope_en);
 }
 
 # Returns a list of subs which should be inserted before the COP
@@ -1095,8 +1330,8 @@ sub cop_subs {
     # If we have nephews, then our sequence number indicates
     # the cop_seq of the end of some sort of scope.
     if (class($op->sibling) ne "NULL" && $op->sibling->flags & OPf_KIDS
-       and my $ncop = $self->find_cop($op->sibling)) {
-       $seq = $ncop->cop_seq;
+       and my $nseq = $self->find_scope_st($op->sibling) ) {
+       $seq = $nseq;
     }
     $seq = $out_seq if defined($out_seq) && $out_seq < $seq;
     return $self->seq_subs($seq);
@@ -1107,6 +1342,7 @@ sub seq_subs {
     my @text;
 #push @text, "# ($seq)\n";
 
+    return "" if !defined $seq;
     while (scalar(@{$self->{'subs_todo'}})
           and $seq > $self->{'subs_todo'}[0][0]) {
        push @text, $self->next_todo;
@@ -1121,18 +1357,13 @@ sub pp_nextstate {
     my($op, $cx) = @_;
     $self->{'curcop'} = $op;
     my @text;
-    @text = $op->label . ": " if $op->label;
-#push @text, "# ", $op->cop_seq, "\n";
     push @text, $self->cop_subs($op);
+    push @text, $op->label . ": " if $op->label;
     my $stash = $op->stashpv;
     if ($stash ne $self->{'curstash'}) {
        push @text, "package $stash;\n";
        $self->{'curstash'} = $stash;
     }
-    if ($self->{'linenums'}) {
-       push @text, "\f#line " . $op->line . 
-         ' "' . $op->file, qq'"\n';
-    }
 
     if ($self->{'arybase'} != $op->arybase) {
        push @text, '$[ = '. $op->arybase .";\n";
@@ -1142,10 +1373,10 @@ sub pp_nextstate {
     my $warnings = $op->warnings;
     my $warning_bits;
     if ($warnings->isa("B::SPECIAL") && $$warnings == 4) {
-       $warning_bits = $warnings::Bits{"all"};
+       $warning_bits = $warnings::Bits{"all"} & WARN_MASK;
     }
     elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) {
-        $warning_bits = "\0"x12;
+        $warning_bits = $warnings::NONE;
     }
     elsif ($warnings->isa("B::SPECIAL")) {
        $warning_bits = undef;
@@ -1165,24 +1396,49 @@ sub pp_nextstate {
        $self->{'hints'} = $op->private;
     }
 
+    # This should go after of any branches that add statements, to
+    # increase the chances that it refers to the same line it did in
+    # the original program.
+    if ($self->{'linenums'}) {
+       push @text, "\f#line " . $op->line .
+         ' "' . $op->file, qq'"\n';
+    }
+
     return join("", @text);
 }
 
 sub declare_warnings {
     my ($from, $to) = @_;
-    if ($to eq warnings::bits("all")) {
+    if (($to & WARN_MASK) eq warnings::bits("all")) {
        return "use warnings;\n";
     }
-    elsif ($to eq "\0"x12) {
+    elsif (($to & WARN_MASK) eq "\0"x length($to)) {
        return "no warnings;\n";
     }
-    return "BEGIN {\${^WARNING_BITS} = ".cstring($to)."}\n";
+    return "BEGIN {\${^WARNING_BITS} = ".perlstring($to)."}\n";
 }
 
 sub declare_hints {
     my ($from, $to) = @_;
-    my $bits = $to;
-    return sprintf "BEGIN {\$^H &= ~0xFF; \$^H |= %x}\n", $bits;
+    my $use = $to   & ~$from;
+    my $no  = $from & ~$to;
+    my $decls = "";
+    for my $pragma (hint_pragmas($use)) {
+       $decls .= "use $pragma;\n";
+    }
+    for my $pragma (hint_pragmas($no)) {
+        $decls .= "no $pragma;\n";
+    }
+    return $decls;
+}
+
+sub hint_pragmas {
+    my ($bits) = @_;
+    my @pragmas;
+    push @pragmas, "integer" if $bits & 0x1;
+    push @pragmas, "strict 'refs'" if $bits & 0x2;
+    push @pragmas, "bytes" if $bits & 0x8;
+    return @pragmas;
 }
 
 sub pp_dbstate { pp_nextstate(@_) }
@@ -1196,7 +1452,16 @@ sub baseop {
     return $name;
 }
 
-sub pp_stub { baseop(@_, "()") }
+sub pp_stub {
+    my $self = shift;
+    my($op, $cx, $name) = @_;
+    if ($cx >= 1) {
+       return "()";
+    }
+    else {
+       return "();";
+    }
+}
 sub pp_wantarray { baseop(@_, "wantarray") }
 sub pp_fork { baseop(@_, "fork") }
 sub pp_wait { maybe_targmy(@_, \&baseop, "wait") }
@@ -1272,7 +1537,7 @@ sub unop {
     my $kid;
     if ($op->flags & OPf_KIDS) {
        $kid = $op->first;
-       if (defined prototype("CORE::$name") 
+       if (defined prototype("CORE::$name")
           && prototype("CORE::$name") =~ /^;?\*/
           && $kid->name eq "rv2gv") {
            $kid = $kid->first;
@@ -1280,7 +1545,7 @@ sub unop {
 
        return $self->maybe_parens_unop($name, $kid, $cx);
     } else {
-       return $name .  ($op->flags & OPf_SPECIAL ? "()" : "");       
+       return $name .  ($op->flags & OPf_SPECIAL ? "()" : "");
     }
 }
 
@@ -1424,7 +1689,7 @@ sub pp_require {
     }
 }
 
-sub pp_scalar { 
+sub pp_scalar {
     my $self = shift;
     my($op, $cv) = @_;
     my $kid = $op->first;
@@ -1439,8 +1704,7 @@ sub pp_scalar {
 sub padval {
     my $self = shift;
     my $targ = shift;
-    #cluck "curcv was undef" unless $self->{curcv};
-    return (($self->{'curcv'}->PADLIST->ARRAY)[1]->ARRAY)[$targ];
+    return $self->{'curcv'}->PADLIST->ARRAYelt(1)->ARRAYelt($targ);
 }
 
 sub pp_refgen {
@@ -1459,7 +1723,7 @@ sub pp_refgen {
                push @exprs, $expr;
            }
            return $pre . join(", ", @exprs) . $post;
-       } elsif (!null($kid->sibling) and 
+       } elsif (!null($kid->sibling) and
                 $kid->sibling->name eq "anoncode") {
            return "sub " .
                $self->deparse_sub($self->padval($kid->sibling->targ));
@@ -1470,7 +1734,7 @@ sub pp_refgen {
             {
                 # The @a in \(@a) isn't in ref context, but only when the
                 # parens are there.
-                return "\\(" . $self->deparse($kid->sibling, 1) . ")";
+               return "\\(" . $self->pp_list($op->first) . ")";
             } elsif ($sib_name eq 'entersub') {
                 my $text = $self->deparse($kid->sibling, 1);
                 # Always show parens for \(&func()), but only with -p otherwise
@@ -1494,6 +1758,12 @@ sub pp_readline {
     return $self->unop($op, $cx, "readline");
 }
 
+sub pp_rcatline {
+    my $self = shift;
+    my($op) = @_;
+    return "<" . $self->gv_name($self->gv_or_padgv($op)) . ">";
+}
+
 # Unary operators that can occur as pseudo-listops inside double quotes
 sub dq_unop {
     my $self = shift;
@@ -1505,7 +1775,7 @@ sub dq_unop {
        $kid = $kid->sibling if not null $kid->sibling;
        return $self->maybe_parens_unop($name, $kid, $cx);
     } else {
-       return $name .  ($op->flags & OPf_SPECIAL ? "()" : "");       
+       return $name .  ($op->flags & OPf_SPECIAL ? "()" : "");
     }
 }
 
@@ -1542,45 +1812,46 @@ sub ftst {
        # Genuine `-X' filetests are exempt from the LLAFR, but not
        # l?stat(); for the sake of clarity, give'em all parens
        return $self->maybe_parens_unop($name, $op->first, $cx);
-    } elsif (class($op) eq "SVOP") {
+    } elsif (class($op) =~ /^(SV|PAD)OP$/) {
        return $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16);
     } else { # I don't think baseop filetests ever survive ck_ftst, but...
        return $name;
     }
 }
 
-sub pp_lstat { ftst(@_, "lstat") }
-sub pp_stat { ftst(@_, "stat") }
-sub pp_ftrread { ftst(@_, "-R") }
+sub pp_lstat    { ftst(@_, "lstat") }
+sub pp_stat     { ftst(@_, "stat") }
+sub pp_ftrread  { ftst(@_, "-R") }
 sub pp_ftrwrite { ftst(@_, "-W") }
-sub pp_ftrexec { ftst(@_, "-X") }
-sub pp_fteread { ftst(@_, "-r") }
+sub pp_ftrexec  { ftst(@_, "-X") }
+sub pp_fteread  { ftst(@_, "-r") }
 sub pp_ftewrite { ftst(@_, "-w") }
-sub pp_fteexec { ftst(@_, "-x") }
-sub pp_ftis { ftst(@_, "-e") }
+sub pp_fteexec  { ftst(@_, "-x") }
+sub pp_ftis     { ftst(@_, "-e") }
 sub pp_fteowned { ftst(@_, "-O") }
 sub pp_ftrowned { ftst(@_, "-o") }
-sub pp_ftzero { ftst(@_, "-z") }
-sub pp_ftsize { ftst(@_, "-s") }
-sub pp_ftmtime { ftst(@_, "-M") }
-sub pp_ftatime { ftst(@_, "-A") }
-sub pp_ftctime { ftst(@_, "-C") }
-sub pp_ftsock { ftst(@_, "-S") }
-sub pp_ftchr { ftst(@_, "-c") }
-sub pp_ftblk { ftst(@_, "-b") }
-sub pp_ftfile { ftst(@_, "-f") }
-sub pp_ftdir { ftst(@_, "-d") }
-sub pp_ftpipe { ftst(@_, "-p") }
-sub pp_ftlink { ftst(@_, "-l") }
-sub pp_ftsuid { ftst(@_, "-u") }
-sub pp_ftsgid { ftst(@_, "-g") }
-sub pp_ftsvtx { ftst(@_, "-k") }
-sub pp_fttty { ftst(@_, "-t") }
-sub pp_fttext { ftst(@_, "-T") }
+sub pp_ftzero   { ftst(@_, "-z") }
+sub pp_ftsize   { ftst(@_, "-s") }
+sub pp_ftmtime  { ftst(@_, "-M") }
+sub pp_ftatime  { ftst(@_, "-A") }
+sub pp_ftctime  { ftst(@_, "-C") }
+sub pp_ftsock   { ftst(@_, "-S") }
+sub pp_ftchr    { ftst(@_, "-c") }
+sub pp_ftblk    { ftst(@_, "-b") }
+sub pp_ftfile   { ftst(@_, "-f") }
+sub pp_ftdir    { ftst(@_, "-d") }
+sub pp_ftpipe   { ftst(@_, "-p") }
+sub pp_ftlink   { ftst(@_, "-l") }
+sub pp_ftsuid   { ftst(@_, "-u") }
+sub pp_ftsgid   { ftst(@_, "-g") }
+sub pp_ftsvtx   { ftst(@_, "-k") }
+sub pp_fttty    { ftst(@_, "-t") }
+sub pp_fttext   { ftst(@_, "-T") }
 sub pp_ftbinary { ftst(@_, "-B") }
 
 sub SWAP_CHILDREN () { 1 }
 sub ASSIGN () { 2 } # has OP= variant
+sub LIST_CONTEXT () { 4 } # Assignment is in list context
 
 my(%left, %right);
 
@@ -1683,6 +1954,8 @@ sub binop {
        ($left, $right) = ($right, $left);
     }
     $left = $self->deparse_binop_left($op, $left, $prec);
+    $left = "($left)" if $flags & LIST_CONTEXT
+               && $left !~ /^(my|our|local|)[\@\(]/;
     $right = $self->deparse_binop_right($op, $right, $prec);
     return $self->maybe_parens("$left $opname$eq $right", $cx, $prec);
 }
@@ -1729,7 +2002,7 @@ sub pp_sle { binop(@_, "le", 15) }
 sub pp_scmp { binop(@_, "cmp", 14) }
 
 sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) }
-sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN) }
+sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN | LIST_CONTEXT) }
 
 # `.' is special because concats-of-concats are optimized to save copying
 # by making all but the first concat stacked. The effect is as if the
@@ -1803,13 +2076,13 @@ sub logop {
     my ($op, $cx, $lowop, $lowprec, $highop, $highprec, $blockname) = @_;
     my $left = $op->first;
     my $right = $op->first->sibling;
-    if ($cx == 0 and is_scope($right) and $blockname
+    if ($cx < 1 and is_scope($right) and $blockname
        and $self->{'expand'} < 7)
     { # if ($a) {$b}
        $left = $self->deparse($left, 1);
        $right = $self->deparse($right, 0);
        return "$blockname ($left) {\n\t$right\n\b}\cK";
-    } elsif ($cx == 0 and $blockname and not $self->{'parens'}
+    } elsif ($cx < 1 and $blockname and not $self->{'parens'}
             and $self->{'expand'} < 7) { # $b if $a
        $right = $self->deparse($right, 1);
        $left = $self->deparse($left, 1);
@@ -1821,12 +2094,13 @@ sub logop {
     } else { # $a and $b
        $left = $self->deparse_binop_left($op, $left, $lowprec);
        $right = $self->deparse_binop_right($op, $right, $lowprec);
-       return $self->maybe_parens("$left $lowop $right", $cx, $lowprec); 
+       return $self->maybe_parens("$left $lowop $right", $cx, $lowprec);
     }
 }
 
 sub pp_and { logop(@_, "and", 3, "&&", 11, "if") }
 sub pp_or  { logop(@_, "or",  2, "||", 10, "unless") }
+sub pp_dor { logop(@_, "err", 2, "//", 10, "") }
 
 # xor is syntactically a logop, but it's really a binop (contrary to
 # old versions of opcode.pl). Syntax is what matters here.
@@ -1843,7 +2117,8 @@ sub logassignop {
 }
 
 sub pp_andassign { logassignop(@_, "&&=") }
-sub pp_orassign { logassignop(@_, "||=") }
+sub pp_orassign  { logassignop(@_, "||=") }
+sub pp_dorassign { logassignop(@_, "//=") }
 
 sub listop {
     my $self = shift;
@@ -1853,6 +2128,7 @@ sub listop {
     my $kid = $op->first->sibling;
     return $name if null $kid;
     my $first;
+    $name = "socketpair" if $name eq "sockpair";
     if (defined prototype("CORE::$name")
        && prototype("CORE::$name") =~ /^;?\*/
        && $kid->name eq "rv2gv") {
@@ -1861,6 +2137,9 @@ sub listop {
     else {
        $first = $self->deparse($kid, 6);
     }
+    if ($name eq "chmod" && $first =~ /^\d+$/) {
+       $first = sprintf("%#o", $first);
+    }
     $first = "+$first" if not $parens and substr($first, 0, 1) eq "(";
     push @exprs, $first;
     $kid = $kid->sibling;
@@ -1962,7 +2241,7 @@ sub pp_glob {
     my($op, $cx) = @_;
     my $text = $self->dq($op->first->sibling);  # skip pushmark
     if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline
-       or $text =~ /[<>]/) { 
+       or $text =~ /[<>]/) {
        return 'glob(' . single_delim('qq', '"', $text) . ')';
     } else {
        return '<' . $text . '>';
@@ -2006,18 +2285,43 @@ sub indirop {
        $indir = $indir->first; # skip rv2gv
        if (is_scope($indir)) {
            $indir = "{" . $self->deparse($indir, 0) . "}";
+           $indir = "{;}" if $indir eq "{}";
+       } elsif ($indir->name eq "const" && $indir->private & OPpCONST_BARE) {
+           $indir = $self->const_sv($indir)->PV;
        } else {
            $indir = $self->deparse($indir, 24);
        }
        $indir = $indir . " ";
        $kid = $kid->sibling;
     }
+    if ($name eq "sort" && $op->private & (OPpSORT_NUMERIC | OPpSORT_INTEGER)) {
+       $indir = ($op->private & OPpSORT_REVERSE) ? '{$b <=> $a} '
+                                                 : '{$a <=> $b} ';
+    }
+    elsif ($name eq "sort" && $op->private & OPpSORT_REVERSE) {
+       $indir = '{$b cmp $a} ';
+    }
     for (; !null($kid); $kid = $kid->sibling) {
        $expr = $self->deparse($kid, 6);
        push @exprs, $expr;
     }
-    return $self->maybe_parens_func($name, $indir . join(", ", @exprs),
-                                   $cx, 5);
+    my $args = $indir . join(", ", @exprs);
+    if ($indir ne "" and $name eq "sort") {
+       # We don't want to say "sort(f 1, 2, 3)", since perl -w will
+       # give bareword warnings in that case. Therefore if context
+       # requires, we'll put parens around the outside "(sort f 1, 2,
+       # 3)". Unfortunately, we'll currently think the parens are
+       # neccessary more often that they really are, because we don't
+       # distinguish which side of an assignment we're on.
+       if ($cx >= 5) {
+           return "($name $args)";
+       } else {
+           return "$name $args";
+       }
+    } else {
+       return $self->maybe_parens_func($name, $args, $cx, 5);
+    }
+
 }
 
 sub pp_prtf { indirop(@_, "printf") }
@@ -2039,13 +2343,13 @@ sub mapop {
     $kid = $kid->sibling;
     for (; !null($kid); $kid = $kid->sibling) {
        $expr = $self->deparse($kid, 6);
-       push @exprs, $expr if $expr;
+       push @exprs, $expr if defined $expr;
     }
     return $self->maybe_parens_func($name, $code . join(", ", @exprs), $cx, 5);
 }
 
-sub pp_mapwhile { mapop(@_, "map") }   
-sub pp_grepwhile { mapop(@_, "grep") }   
+sub pp_mapwhile { mapop(@_, "map") }
+sub pp_grepwhile { mapop(@_, "grep") }
 
 sub pp_list {
     my $self = shift;
@@ -2053,21 +2357,35 @@ sub pp_list {
     my($expr, @exprs);
     my $kid = $op->first->sibling; # skip pushmark
     my $lop;
-    my $local = "either"; # could be local(...) or my(...)
+    my $local = "either"; # could be local(...), my(...) or our(...)
     for ($lop = $kid; !null($lop); $lop = $lop->sibling) {
        # This assumes that no other private flags equal 128, and that
        # OPs that store things other than flags in their op_private,
        # like OP_AELEMFAST, won't be immediate children of a list.
-       unless ($lop->private & OPpLVAL_INTRO or $lop->name eq "undef")
+       #
+       # OP_ENTERSUB can break this logic, so check for it.
+       # I suspect that open and exit can too.
+
+       if (!($lop->private & (OPpLVAL_INTRO|OPpOUR_INTRO)
+               or $lop->name eq "undef")
+           or $lop->name eq "entersub"
+           or $lop->name eq "exit"
+           or $lop->name eq "open")
        {
            $local = ""; # or not
            last;
        }
        if ($lop->name =~ /^pad[ash]v$/) { # my()
-           ($local = "", last) if $local eq "local";
+           ($local = "", last) if $local eq "local" || $local eq "our";
            $local = "my";
+       } elsif ($lop->name =~ /^(gv|rv2)[ash]v$/
+                       && $lop->private & OPpOUR_INTRO
+               or $lop->name eq "null" && $lop->first->name eq "gvsv"
+                       && $lop->first->private & OPpOUR_INTRO) { # our()
+           ($local = "", last) if $local eq "my" || $local eq "local";
+           $local = "our";
        } elsif ($lop->name ne "undef") { # local()
-           ($local = "", last) if $local eq "my";
+           ($local = "", last) if $local eq "my" || $local eq "our";
            $local = "local";
        }
     }
@@ -2109,7 +2427,7 @@ sub pp_cond_expr {
     my $true = $cond->sibling;
     my $false = $true->sibling;
     my $cuddle = $self->{'cuddle'};
-    unless ($cx == 0 and (is_scope($true) and $true->name ne "null") and
+    unless ($cx < 1 and (is_scope($true) and $true->name ne "null") and
            (is_scope($false) || is_ifelse_cont($false))
            and $self->{'expand'} < 7) {
        $cond = $self->deparse($cond, 8);
@@ -2119,7 +2437,7 @@ sub pp_cond_expr {
     }
 
     $cond = $self->deparse($cond, 1);
-    $true = $self->deparse($true, 0);    
+    $true = $self->deparse($true, 0);
     my $head = "if ($cond) {\n\t$true\n\b}";
     my @elsifs;
     while (!null($false) and is_ifelse_cont($false)) {
@@ -2131,13 +2449,13 @@ sub pp_cond_expr {
        $newtrue = $self->deparse($newtrue, 0);
        push @elsifs, "elsif ($newcond) {\n\t$newtrue\n\b}";
     }
-    if (!null($false)) {           
+    if (!null($false)) {
        $false = $cuddle . "else {\n\t" .
          $self->deparse($false, 0) . "\n\b}\cK";
     } else {
        $false = "\cK";
     }
-    return $head . join($cuddle, "", @elsifs) . $false; 
+    return $head . join($cuddle, "", @elsifs) . $false;
 }
 
 sub loop_common {
@@ -2151,10 +2469,9 @@ sub loop_common {
     my $bare = 0;
     my $body;
     my $cond = undef;
-    my $out_seq = $self->{'curcop'}->cop_seq;;
-    if ($kid->name eq "lineseq") { # bare or infinite loop 
-       if (is_state $kid->last) { # infinite
-           $head = "for (;;) "; # shorter than while (1)
+    if ($kid->name eq "lineseq") { # bare or infinite loop
+       if ($kid->last->name eq "unstack") { # infinite
+           $head = "while (1) "; # Can't use for(;;) if there's a continue
            $cond = "";
        } else {
            $bare = 1;
@@ -2176,17 +2493,14 @@ sub loop_common {
                $var = $self->pp_threadsv($enter, 1);
            } else { # regular my() variable
                $var = $self->pp_padsv($enter, 1);
-               if ($self->padname_sv($enter->targ)->IVX ==
-                   $kid->first->first->sibling->last->cop_seq)
-               {
-                   # If the scope of this variable closes at the last
-                   # statement of the loop, it must have been
-                   # declared here.
-                   $var = "my " . $var;
-               }
            }
        } elsif ($var->name eq "rv2gv") {
            $var = $self->pp_rv2sv($var, 1);
+           if ($enter->private & OPpOUR_INTRO) {
+               # our declarations don't have package names
+               $var =~ s/^(.).*::/$1/;
+               $var = "our $var";
+           }
        } elsif ($var->name eq "gv") {
            $var = "\$" . $self->deparse($var, 1);
        }
@@ -2202,18 +2516,18 @@ sub loop_common {
        return "{;}"; # {} could be a hashref
     }
     # If there isn't a continue block, then the next pointer for the loop
-    # will point to the unstack, which is kid's penultimate child, except
+    # will point to the unstack, which is kid's last child, except
     # in a bare loop, when it will point to the leaveloop. When neither of
-    # these conditions hold, then the third-to-last child in the continue
+    # these conditions hold, then the second-to-last child is the continue
     # block (or the last in a bare loop).
     my $cont_start = $enter->nextop;
     my $cont;
-    if ($$cont_start != $$op and $ {$cont_start->sibling} != $ {$body->last}) {
+    if ($$cont_start != $$op && ${$cont_start} != ${$body->last}) {
        if ($bare) {
            $cont = $body->last;
        } else {
            $cont = $body->first;
-           while (!null($cont->sibling->sibling->sibling)) {
+           while (!null($cont->sibling->sibling)) {
                $cont = $cont->sibling;
            }
        }
@@ -2223,7 +2537,7 @@ sub loop_common {
        for (; $$state != $$cont; $state = $state->sibling) {
            push @states, $state;
        }
-       $body = $self->lineseq(@states);
+       $body = $self->lineseq(undef, @states);
        if (defined $cond and not is_scope $cont and $self->{'expand'} < 3) {
            $head = "for ($init; $cond; " . $self->deparse($cont, 1) .") ";
            $cont = "\cK";
@@ -2233,13 +2547,13 @@ sub loop_common {
        }
     } else {
        return "" if !defined $body;
+       if (length $init) {
+           $head = "for ($init; $cond;) ";
+       }
        $cont = "\cK";
        $body = $self->deparse($body, 0);
     }
-    $body .= "\n";
-    # If we have say C<{my $x=2; sub x{$x}}>, the sub must go inside
-    # the loop. So we insert any subs which are due here.
-    $body .= join"", $self->seq_subs($out_seq);
+    $body =~ s/;?$/;\n/;
 
     return $head . "{\n\t" . $body . "\b}" . $cont;
 }
@@ -2250,7 +2564,7 @@ sub for_loop {
     my $self = shift;
     my($op, $cx) = @_;
     my $init = $self->deparse($op, 1);
-    return $self->loop_common($op->sibling, $cx, $init);
+    return $self->loop_common($op->sibling->first->sibling, $cx, $init);
 }
 
 sub pp_leavetry {
@@ -2260,6 +2574,8 @@ sub pp_leavetry {
 
 BEGIN { eval "sub OP_CONST () {" . opnumber("const") . "}" }
 BEGIN { eval "sub OP_STRINGIFY () {" . opnumber("stringify") . "}" }
+BEGIN { eval "sub OP_RV2SV () {" . opnumber("rv2sv") . "}" }
+BEGIN { eval "sub OP_LIST () {" . opnumber("list") . "}" }
 
 sub pp_null {
     my $self = shift;
@@ -2285,6 +2601,16 @@ sub pp_null {
        return $self->maybe_parens($self->deparse($op->first, 20) . " =~ "
                                   . $self->deparse($op->first->sibling, 20),
                                   $cx, 20);
+    } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
+       return "do {\n\t". $self->deparse($op->first, $cx) ."\n\b};";
+    } elsif (!null($op->first->sibling) and
+            $op->first->sibling->name eq "null" and
+            class($op->first->sibling) eq "UNOP" and
+            $op->first->sibling->first->flags & OPf_STACKED and
+            $op->first->sibling->first->name eq "rcatline") {
+       return $self->maybe_parens($self->deparse($op->first, 18) . " .= "
+                                  . $self->deparse($op->first->sibling, 18),
+                                  $cx, 18);
     } else {
        return $self->deparse($op->first, $cx);
     }
@@ -2324,7 +2650,7 @@ sub pp_threadsv {
     my $self = shift;
     my($op, $cx) = @_;
     return $self->maybe_local($op, $cx, "\$" .  $threadsv_names[$op->targ]);
-}    
+}
 
 sub gv_or_padgv {
     my $self = shift;
@@ -2355,17 +2681,43 @@ sub pp_aelemfast {
     my $self = shift;
     my($op, $cx) = @_;
     my $gv = $self->gv_or_padgv($op);
-    return "\$" . $self->gv_name($gv) . "[" .
+    my $name = $self->gv_name($gv);
+    $name = $self->{'curstash'}."::$name"
+       if $name !~ /::/ && $self->lex_in_scope('@'.$name);
+
+    return "\$" . $name . "[" .
                  ($op->private + $self->{'arybase'}) . "]";
 }
 
 sub rv2x {
     my $self = shift;
     my($op, $cx, $type) = @_;
+
+    if (class($op) eq 'NULL' || !$op->can("first")) {
+       carp("Unexpected op in pp_rv2x");
+       return 'XXX';
+    }
     my $kid = $op->first;
-    my $str = $self->deparse($kid, 0);
-    return $self->stash_variable($type, $str) if is_scalar($kid);
-    return $type ."{$str}";
+    if ($kid->name eq "gv") {
+       return $self->stash_variable($type, $self->deparse($kid, 0));
+    } elsif (is_scalar $kid) {
+       my $str = $self->deparse($kid, 0);
+       if ($str =~ /^\$([^\w\d])\z/) {
+           # "$$+" isn't a legal way to write the scalar dereference
+           # of $+, since the lexer can't tell you aren't trying to
+           # do something like "$$ + 1" to get one more than your
+           # PID. Either "${$+}" or "$${+}" are workable
+           # disambiguations, but if the programmer did the former,
+           # they'd be in the "else" clause below rather than here.
+           # It's not clear if this should somehow be unified with
+           # the code in dq and re_dq that also adds lexer
+           # disambiguation braces.
+           $str = '$' . "{$1}"; #'
+       }
+       return $type . $str;
+    } else {
+       return $type . "{" . $self->deparse($kid, 0) . "}";
+    }
 }
 
 sub pp_rv2sv { maybe_local(@_, rv2x(@_, "\$")) }
@@ -2385,7 +2737,35 @@ sub pp_av2arylen {
 }
 
 # skip down to the old, ex-rv2cv
-sub pp_rv2cv { $_[0]->rv2x($_[1]->first->first->sibling, $_[2], "&") }
+sub pp_rv2cv {
+    my ($self, $op, $cx) = @_;
+    if (!null($op->first) && $op->first->name eq 'null' &&
+       $op->first->targ eq OP_LIST)
+    {
+       return $self->rv2x($op->first->first->sibling, $cx, "&")
+    }
+    else {
+       return $self->rv2x($op, $cx, "")
+    }
+}
+
+sub list_const {
+    my $self = shift;
+    my($cx, @list) = @_;
+    my @a = map $self->const($_, 6), @list;
+    if (@a == 0) {
+       return "()";
+    } elsif (@a == 1) {
+       return $a[0];
+    } elsif ( @a > 2 and !grep(!/^-?\d+$/, @a)) {
+       # collapse (-1,0,1,2) into (-1..2)
+       my ($s, $e) = @a[0,-1];
+       my $i = $s;
+       return $self->maybe_parens("$s..$e", $cx, 9)
+         unless grep $i++ != $_, @a;
+    }
+    return $self->maybe_parens(join(", ", @a), $cx, 6);
+}
 
 sub pp_rv2av {
     my $self = shift;
@@ -2393,7 +2773,7 @@ sub pp_rv2av {
     my $kid = $op->first;
     if ($kid->name eq "const") { # constant list
        my $av = $self->const_sv($kid);
-       return "(" . join(", ", map(const($_), $av->ARRAY)) . ")";
+       return $self->list_const($cx, $av->ARRAY);
     } else {
        return $self->maybe_local($op, $cx, $self->rv2x($op, $cx, "\@"));
     }
@@ -2429,6 +2809,13 @@ sub elem {
        $array = $self->padany($array);
     } elsif (is_scope($array)) { # ${expr}[0]
        $array = "{" . $self->deparse($array, 0) . "}";
+    } elsif ($array->name eq "gv") {
+       $array = $self->gv_name($self->gv_or_padgv($array));
+       if ($array !~ /::/) {
+           my $prefix = ($left eq '[' ? '@' : '%');
+           $array = $self->{curstash}.'::'.$array
+               if $self->lex_in_scope($prefix . $array);
+       }
     } elsif (is_scalar $array) { # $x[0], $$x[0], ...
        $array = $self->deparse($array, 24);
     } else {
@@ -2457,6 +2844,16 @@ sub elem {
     #
     $idx =~ s/^\((.*)\)$/$1/ if $self->{'parens'};
 
+    # Hash-element braces will autoquote a bareword inside themselves.
+    # We need to make sure that C<$hash{warn()}> doesn't come out as
+    # C<$hash{warn}>, which has a quite different meaning. Currently
+    # B::Deparse will always quote strings, even if the string was a
+    # bareword in the original (i.e. the OPpCONST_BARE flag is ignored
+    # for constant strings.) So we can cheat slightly here - if we see
+    # a bareword, we know that it is supposed to be a function call.
+    #
+    $idx =~ s/^([A-Za-z_]\w*)$/$1()/;
+
     return "\$" . $array . $left . $idx . $right;
 }
 
@@ -2544,7 +2941,7 @@ sub method {
        # doesn't apply), but they make a list with OPf_PARENS set that
        # doesn't get flattened by the append_elem that adds the method,
        # making a (object, arg1, arg2, ...) list where the object
-       # usually is. This can be distinguished from 
+       # usually is. This can be distinguished from
        # `($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an
        # object) because in the later the list is in scalar context
        # as the left side of -> always is, while in the former
@@ -2560,7 +2957,8 @@ sub method {
     } else {
        $obj = $kid;
        $kid = $kid->sibling;
-       for (; not null $kid->sibling; $kid = $kid->sibling) {
+       for (; !null ($kid->sibling) && $kid->name ne "method_named";
+             $kid = $kid->sibling) {
            push @exprs, $self->deparse($kid, 6);
        }
        $meth = $kid;
@@ -2580,7 +2978,7 @@ sub method {
     }
     my $args = join(", ", @exprs);     
     $kid = $obj . "->" . $meth;
-    if ($args) {
+    if (length $args) {
        return $kid . "(" . $args . ")"; # parens mandatory
     } else {
        return $kid;
@@ -2591,14 +2989,15 @@ sub method {
 # or ("", $args_after_prototype_demunging) if it does.
 sub check_proto {
     my $self = shift;
+    return "&" if $self->{'noproto'};
     my($proto, @args) = @_;
     my($arg, $real);
     my $doneok = 0;
     my @reals;
     # An unbackslashed @ or % gobbles up the rest of the args
-    $proto =~ s/([^\\]|^)([@%])(.*)$/$1$2/;
+    1 while $proto =~ s/(?<!\\)([@%])[^\]]+$/$1/;
     while ($proto) {
-       $proto =~ s/^ *([\\]?[\$\@&%*]|;)//;
+       $proto =~ s/^(\\?[\$\@&%*]|\\\[[\$\@&%*]+\]|;)//;
        my $chr = $1;
        if ($chr eq "") {
            return "&" if @args;
@@ -2636,19 +3035,21 @@ sub check_proto {
                      return "&";
                  }
            } elsif (substr($chr, 0, 1) eq "\\") {
-               $chr = substr($chr, 1);
+               $chr =~ tr/\\[]//d;
                if ($arg->name =~ /^s?refgen$/ and
                    !null($real = $arg->first) and
-                   ($chr eq "\$" && is_scalar($real->first)
-                    or ($chr eq "\@"
+                   ($chr =~ /\$/ && is_scalar($real->first)
+                    or ($chr =~ /@/
+                        && class($real->first->sibling) ne 'NULL'
                         && $real->first->sibling->name
                         =~ /^(rv2|pad)av$/)
-                    or ($chr eq "%"
+                    or ($chr =~ /%/
+                        && class($real->first->sibling) ne 'NULL'
                         && $real->first->sibling->name
                         =~ /^(rv2|pad)hv$/)
-                    #or ($chr eq "&" # This doesn't work
+                    #or ($chr =~ /&/ # This doesn't work
                     #   && $real->first->name eq "rv2cv")
-                    or ($chr eq "*"
+                    or ($chr =~ /\*/
                         && $real->first->name eq "rv2gv")))
                  {
                      push @reals, $self->deparse($real, 6);
@@ -2670,7 +3071,7 @@ sub pp_entersub {
     my $prefix = "";
     my $amper = "";
     my($kid, @exprs);
-    if ($op->flags & OPf_SPECIAL) {
+    if ($op->flags & OPf_SPECIAL && !($op->flags & OPf_MOD)) {
        $prefix = "do ";
     } elsif ($op->private & OPpENTERSUB_AMPER) {
        $amper = "&";
@@ -2692,7 +3093,7 @@ sub pp_entersub {
        }
        $simple = 1; # only calls of named functions can be prototyped
        $kid = $self->deparse($kid, 24);
-    } elsif (is_scalar $kid->first) {
+    } elsif (is_scalar ($kid->first) && $kid->first->name ne 'rv2cv') {
        $amper = "&";
        $kid = $self->deparse($kid, 24);
     } else {
@@ -2703,7 +3104,22 @@ sub pp_entersub {
 
     # Doesn't matter how many prototypes there are, if
     # they haven't happened yet!
-    my $declared = exists $self->{'subs_declared'}{$kid};
+    my $declared;
+    {
+       no strict 'refs';
+       no warnings 'uninitialized';
+       $declared = exists $self->{'subs_declared'}{$kid}
+           || (
+                defined &{ %{$self->{'curstash'}."::"}->{$kid} }
+                && !exists
+                    $self->{'subs_deparsed'}{$self->{'curstash'}."::".$kid}
+                && defined prototype $self->{'curstash'}."::".$kid
+              );
+       if (!$declared && defined($proto)) {
+           # Avoid "too early to check prototype" warning
+           ($amper, $proto) = ('&');
+       }
+    }
 
     my $args;
     if ($declared and defined $proto and not $amper) {
@@ -2722,7 +3138,7 @@ sub pp_entersub {
        }
     } else {
        # glob() invocations can be translated into calls of
-       # CORE::GLOBAL::glob with an second parameter, a number.
+       # CORE::GLOBAL::glob with a second parameter, a number.
        # Reverse this.
        if ($kid eq "CORE::GLOBAL::glob") {
            $kid = "glob";
@@ -2734,13 +3150,18 @@ sub pp_entersub {
        # it back.
        $kid =~ s/^CORE::GLOBAL:://;
 
+       my $dproto = defined($proto) ? $proto : "undefined";
         if (!$declared) {
            return "$kid(" . $args . ")";
-       } elsif (defined $proto and $proto eq "") {
+       } elsif ($dproto eq "") {
            return $kid;
-       } elsif (defined $proto and $proto eq "\$") {
+       } elsif ($dproto eq "\$" and is_scalar($exprs[0])) {
+           # is_scalar is an excessively conservative test here:
+           # really, we should be comparing to the precedence of the
+           # top operator of $exprs[0] (ala unop()), but that would
+           # take some major code restructuring to do right.
            return $self->maybe_parens_func($kid, $args, $cx, 16);
-       } elsif (defined($proto) && $proto or $simple) {
+       } elsif ($dproto ne '$' and defined($proto) || $simple) { #'
            return $self->maybe_parens_func($kid, $args, $cx, 5);
        } else {
            return "$kid(" . $args . ")";
@@ -2754,31 +3175,138 @@ sub pp_enterwrite { unop(@_, "write") }
 # but not character escapes
 sub uninterp {
     my($str) = @_;
-    $str =~ s/(^|[^\\])([\$\@]|\\[uUlLQE])/$1\\$2/g;
+    $str =~ s/(^|\G|[^\\])((?:\\\\)*)([\$\@]|\\[uUlLQE])/$1$2\\$3/g;
     return $str;
 }
 
-# the same, but treat $|, $), and $ at the end of the string differently
+{
+my $bal;
+BEGIN {
+    use re "eval";
+    # Matches any string which is balanced with respect to {braces}
+    $bal = qr(
+      (?:
+       [^\\{}]
+      | \\\\
+      | \\[{}]
+      | \{(??{$bal})\}
+      )*
+    )x;
+}
+
+# the same, but treat $|, $), $( and $ at the end of the string differently
 sub re_uninterp {
     my($str) = @_;
-    $str =~ s/(^|[^\\])(\@|\\[uUlLQE])/$1\\$2/g;
-    $str =~ s/(^|[^\\])(\$[^)|])/$1\\$2/g;
+
+    $str =~ s/
+         ( ^|\G                  # $1
+          | [^\\]
+          )
+
+          (                       # $2
+            (?:\\\\)*
+          )
+
+          (                       # $3
+            (\(\?\??\{$bal\}\))   # $4
+          | [\$\@]
+            (?!\||\)|\(|$)
+          | \\[uUlLQE]
+          )
+
+       /defined($4) && length($4) ? "$1$2$4" : "$1$2\\$3"/xeg;
+
+    return $str;
+}
+
+# This is for regular expressions with the /x modifier
+# We have to leave comments unmangled.
+sub re_uninterp_extended {
+    my($str) = @_;
+
+    $str =~ s/
+         ( ^|\G                  # $1
+          | [^\\]
+          )
+
+          (                       # $2
+            (?:\\\\)*
+          )
+
+          (                       # $3
+            ( \(\?\??\{$bal\}\)   # $4  (skip over (?{}) and (??{}) blocks)
+            | \#[^\n]*            #     (skip over comments)
+            )
+          | [\$\@]
+            (?!\||\)|\(|$|\s)
+          | \\[uUlLQE]
+          )
+
+       /defined($4) && length($4) ? "$1$2$4" : "$1$2\\$3"/xeg;
+
     return $str;
 }
+}
+
+my %unctrl = # portable to to EBCDIC
+    (
+     "\c@" => '\c@',   # unused
+     "\cA" => '\cA',
+     "\cB" => '\cB',
+     "\cC" => '\cC',
+     "\cD" => '\cD',
+     "\cE" => '\cE',
+     "\cF" => '\cF',
+     "\cG" => '\cG',
+     "\cH" => '\cH',
+     "\cI" => '\cI',
+     "\cJ" => '\cJ',
+     "\cK" => '\cK',
+     "\cL" => '\cL',
+     "\cM" => '\cM',
+     "\cN" => '\cN',
+     "\cO" => '\cO',
+     "\cP" => '\cP',
+     "\cQ" => '\cQ',
+     "\cR" => '\cR',
+     "\cS" => '\cS',
+     "\cT" => '\cT',
+     "\cU" => '\cU',
+     "\cV" => '\cV',
+     "\cW" => '\cW',
+     "\cX" => '\cX',
+     "\cY" => '\cY',
+     "\cZ" => '\cZ',
+     "\c[" => '\c[',   # unused
+     "\c\\" => '\c\\', # unused
+     "\c]" => '\c]',   # unused
+     "\c_" => '\c_',   # unused
+    );
 
 # character escapes, but not delimiters that might need to be escaped
 sub escape_str { # ASCII, UTF8
     my($str) = @_;
-    $str =~ s/(.)/ord($1)>255 ? sprintf("\\x{%x}", ord($1)) : $1/eg;
+    $str =~ s/(.)/ord($1) > 255 ? sprintf("\\x{%x}", ord($1)) : $1/eg;
     $str =~ s/\a/\\a/g;
-#    $str =~ s/\cH/\\b/g; # \b means someting different in a regex 
+#    $str =~ s/\cH/\\b/g; # \b means something different in a regex
     $str =~ s/\t/\\t/g;
     $str =~ s/\n/\\n/g;
     $str =~ s/\e/\\e/g;
     $str =~ s/\f/\\f/g;
     $str =~ s/\r/\\r/g;
-    $str =~ s/([\cA-\cZ])/'\\c' . chr(ord('@') + ord($1))/ge;
-    $str =~ s/([\0\033-\037\177-\377])/'\\' . sprintf("%03o", ord($1))/ge;
+    $str =~ s/([\cA-\cZ])/$unctrl{$1}/ge;
+    $str =~ s/([[:^print:]])/sprintf("\\%03o", ord($1))/ge;
+    return $str;
+}
+
+# For regexes with the /x modifier.
+# Leave whitespace unmangled.
+sub escape_extended_re {
+    my($str) = @_;
+    $str =~ s/(.)/ord($1) > 255 ? sprintf("\\x{%x}", ord($1)) : $1/eg;
+    $str =~ s/([[:^print:]])/
+       ($1 =~ y! \t\n!!) ? $1 : sprintf("\\%03o", ord($1))/ge;
+    $str =~ s/\n/\n\f/g;
     return $str;
 }
 
@@ -2795,7 +3323,7 @@ sub re_unback {
     my($str) = @_;
 
     # the insane complexity here is due to the behaviour of "\c\"
-    $str =~ s/(^|[^\\]|\\c\\)(?<!\\c)\\(\\\\)*(?=[\0-\031\177-\377])/$1$2/g;
+    $str =~ s/(^|[^\\]|\\c\\)(?<!\\c)\\(\\\\)*(?=[[:^print:]])/$1$2/g;
     return $str;
 }
 
@@ -2827,10 +3355,11 @@ sub balanced_delim {
 sub single_delim {
     my($q, $default, $str) = @_;
     return "$default$str$default" if $default and index($str, $default) == -1;
-    my($succeed, $delim);
-    ($succeed, $str) = balanced_delim($str);
-    return "$q$str" if $succeed;
-    for $delim ('/', '"', '#') {
+    if ($q ne 'qr') {
+       (my $succeed, $str) = balanced_delim($str);
+       return "$q$str" if $succeed;
+    }
+    for my $delim ('/', '"', '#') {
        return "$q$delim" . $str . $delim if index($str, $delim) == -1;
     }
     if ($default) {
@@ -2842,25 +3371,147 @@ sub single_delim {
     }
 }
 
+my $max_prec;
+BEGIN { $max_prec = int(0.999 + 8*length(pack("F", 42))*log(2)/log(10)); }
+
+# Split a floating point number into an integer mantissa and a binary
+# exponent. Assumes you've already made sure the number isn't zero or
+# some weird infinity or NaN.
+sub split_float {
+    my($f) = @_;
+    my $exponent = 0;
+    if ($f == int($f)) {
+       while ($f % 2 == 0) {
+           $f /= 2;
+           $exponent++;
+       }
+    } else {
+       while ($f != int($f)) {
+           $f *= 2;
+           $exponent--;
+       }
+    }
+    my $mantissa = sprintf("%.0f", $f);
+    return ($mantissa, $exponent);
+}
+
 sub const {
-    my $sv = shift;
+    my $self = shift;
+    my($sv, $cx) = @_;
+    if ($self->{'use_dumper'}) {
+       return $self->const_dumper($sv, $cx);
+    }
     if (class($sv) eq "SPECIAL") {
-       return ('undef', '1', '0')[$$sv-1]; # sv_undef, sv_yes, sv_no
+       # sv_undef, sv_yes, sv_no
+       return ('undef', '1', $self->maybe_parens("!1", $cx, 21))[$$sv-1];
     } elsif (class($sv) eq "NULL") {
        return 'undef';
-    } elsif ($sv->FLAGS & SVf_IOK) {
-       return $sv->int_value;
+    }
+    # convert a version object into the "v1.2.3" string in its V magic
+    if ($sv->FLAGS & SVs_RMG) {
+       for (my $mg = $sv->MAGIC; $mg; $mg = $mg->MOREMAGIC) {
+           return $mg->PTR if $mg->TYPE eq 'V';
+       }
+    }
+
+    if ($sv->FLAGS & SVf_IOK) {
+       my $str = $sv->int_value;
+       $str = $self->maybe_parens($str, $cx, 21) if $str < 0;
+       return $str;
     } elsif ($sv->FLAGS & SVf_NOK) {
-       return $sv->NV;
+       my $nv = $sv->NV;
+       if ($nv == 0) {
+           if (pack("F", $nv) eq pack("F", 0)) {
+               # positive zero
+               return "0";
+           } else {
+               # negative zero
+               return $self->maybe_parens("-.0", $cx, 21);
+           }
+       } elsif (1/$nv == 0) {
+           if ($nv > 0) {
+               # positive infinity
+               return $self->maybe_parens("9**9**9", $cx, 22);
+           } else {
+               # negative infinity
+               return $self->maybe_parens("-9**9**9", $cx, 21);
+           }
+       } elsif ($nv != $nv) {
+           # NaN
+           if (pack("F", $nv) eq pack("F", sin(9**9**9))) {
+               # the normal kind
+               return "sin(9**9**9)";
+           } elsif (pack("F", $nv) eq pack("F", -sin(9**9**9))) {
+               # the inverted kind
+               return $self->maybe_parens("-sin(9**9**9)", $cx, 21);
+           } else {
+               # some other kind
+               my $hex = unpack("h*", pack("F", $nv));
+               return qq'unpack("F", pack("h*", "$hex"))';
+           }
+       }
+       # first, try the default stringification
+       my $str = "$nv";
+       if ($str != $nv) {
+           # failing that, try using more precision
+           $str = sprintf("%.${max_prec}g", $nv);
+#          if (pack("F", $str) ne pack("F", $nv)) {
+           if ($str != $nv) {
+               # not representable in decimal with whatever sprintf()
+               # and atof() Perl is using here.
+               my($mant, $exp) = split_float($nv);
+               return $self->maybe_parens("$mant * 2**$exp", $cx, 19);
+           }
+       }
+       $str = $self->maybe_parens($str, $cx, 21) if $nv < 0;
+       return $str;
     } elsif ($sv->FLAGS & SVf_ROK && $sv->can("RV")) {
-       return "\\(" . const($sv->RV) . ")"; # constant folded
-    } else {
+       my $ref = $sv->RV;
+       if (class($ref) eq "AV") {
+           return "[" . $self->list_const(2, $ref->ARRAY) . "]";
+       } elsif (class($ref) eq "HV") {
+           my %hash = $ref->ARRAY;
+           my @elts;
+           for my $k (sort keys %hash) {
+               push @elts, "$k => " . $self->const($hash{$k}, 6);
+           }
+           return "{" . join(", ", @elts) . "}";
+       } elsif (class($ref) eq "CV") {
+           return "sub " . $self->deparse_sub($ref);
+       }
+       if ($ref->FLAGS & SVs_SMG) {
+           for (my $mg = $ref->MAGIC; $mg; $mg = $mg->MOREMAGIC) {
+               if ($mg->TYPE eq 'r') {
+                   my $re = re_uninterp(escape_str(re_unback($mg->precomp)));
+                   return single_delim("qr", "", $re);
+               }
+           }
+       }
+       
+       return $self->maybe_parens("\\" . $self->const($ref, 20), $cx, 20);
+    } elsif ($sv->FLAGS & SVf_POK) {
        my $str = $sv->PV;
        if ($str =~ /[^ -~]/) { # ASCII for non-printing
            return single_delim("qq", '"', uninterp escape_str unback $str);
        } else {
            return single_delim("q", "'", unback $str);
        }
+    } else {
+       return "undef";
+    }
+}
+
+sub const_dumper {
+    my $self = shift;
+    my($sv, $cx) = @_;
+    my $ref = $sv->object_2svref();
+    my $dumper = Data::Dumper->new([$$ref], ['$v']);
+    $dumper->Purity(1)->Terse(1)->Deparse(1)->Indent(0)->Useqq(1)->Sortkeys(1);
+    my $str = $dumper->Dump();
+    if ($str =~ /^\$v/) {
+       return '${my ' . $str . ' \$v}';
+    } else {
+       return $str;
     }
 }
 
@@ -2879,13 +3530,11 @@ sub pp_const {
     if ($op->private & OPpCONST_ARYBASE) {
         return '$[';
     }
-#    if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting 
+#    if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting
 #      return $self->const_sv($op)->PV;
 #    }
     my $sv = $self->const_sv($op);
-#    return const($sv);
-    my $c = const $sv; 
-    return $c =~ /^-\d/ ? $self->maybe_parens($c, $cx, 21) : $c;
+    return $self->const($sv, $cx);
 }
 
 sub dq {
@@ -2898,13 +3547,13 @@ sub dq {
     } elsif ($type eq "concat") {
        my $first = $self->dq($op->first);
        my $last  = $self->dq($op->last);
-       # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]"
-       if ($last =~ /^[A-Z\\\^\[\]_?]/) {
-           $first =~ s/([\$@])\^$/${1}{^}/;  # "${^}W" etc
-        }
-       elsif ($last =~ /^[{\[\w]/) {
-           $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/;
-       }
+
+       # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]", "$foo\::bar"
+       ($last =~ /^[A-Z\\\^\[\]_?]/ &&
+           $first =~ s/([\$@])\^$/${1}{^}/)  # "${^}W" etc
+           || ($last =~ /^[:'{\[\w_]/ && #'
+               $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/);
+
        return $first . $last;
     } elsif ($type eq "uc") {
        return '\U' . $self->dq($op->first->sibling) . '\E';
@@ -2970,10 +3619,13 @@ sub double_delim {
     }
 }
 
+# Only used by tr///, so backslashes hyphens
 sub pchr { # ASCII
     my($n) = @_;
     if ($n == ord '\\') {
        return '\\\\';
+    } elsif ($n == ord "-") {
+       return "\\-";
     } elsif ($n >= ord(' ') and $n <= ord('~')) {
        return chr($n);
     } elsif ($n == ord "\a") {
@@ -3016,14 +3668,12 @@ sub collapse {
     return $str;
 }
 
-# XXX This has trouble with hyphens in the replacement (tr/bac/-AC/),
-# and backslashes.
-
 sub tr_decode_byte {
     my($table, $flags) = @_;
-    my(@table) = unpack("s256", $table);
+    my(@table) = unpack("s*", $table);
+    splice @table, 0x100, 1;   # Number of subsequent elements
     my($c, $tr, @from, @to, @delfrom, $delhyphen);
-    if ($table[ord "-"] != -1 and 
+    if ($table[ord "-"] != -1 and
        $table[ord("-") - 1] == -1 || $table[ord("-") + 1] == -1)
     {
        $tr = $table[ord "-"];
@@ -3035,7 +3685,7 @@ sub tr_decode_byte {
            $delhyphen = 1;
        }
     }
-    for ($c = 0; $c < 256; $c++) {
+    for ($c = 0; $c < @table; $c++) {
        $tr = $table[$c];
        if ($tr >= 0) {
            push @from, $c; push @to, $tr;
@@ -3067,6 +3717,8 @@ sub tr_chr {
     my $x = shift;
     if ($x == ord "-") {
        return "\\-";
+    } elsif ($x == ord "\\") {
+       return "\\\\";
     } else {
        return chr $x;
     }
@@ -3093,7 +3745,7 @@ sub tr_decode_utf8 {
        }
        $result = hex $result;
        if ($result == $extra) {
-           push @delfrom, [$min, $max];            
+           push @delfrom, [$min, $max];
        } else {
            push @from, [$min, $max];
            push @to, [$result, $result + $max - $min];
@@ -3163,7 +3815,7 @@ sub tr_decode_utf8 {
     }
     #$final = sprintf("%04x", $final) if defined $final;
     #$none = sprintf("%04x", $none) if defined $none;
-    #$extra = sprintf("%04x", $extra) if defined $extra;    
+    #$extra = sprintf("%04x", $extra) if defined $extra;
     #print STDERR "final: $final\n none: $none\nextra: $extra\n";
     #print STDERR $swash{'LIST'}->PV;
     return (escape_str($from), escape_str($to));
@@ -3189,32 +3841,36 @@ sub pp_trans {
 # Like dq(), but different
 sub re_dq {
     my $self = shift;
-    my $op = shift;
+    my ($op, $extended) = @_;
+
     my $type = $op->name;
     if ($type eq "const") {
        return '$[' if $op->private & OPpCONST_ARYBASE;
-       return re_uninterp(escape_str(re_unback($self->const_sv($op)->as_string)));
+       my $unbacked = re_unback($self->const_sv($op)->as_string);
+       return re_uninterp_extended(escape_extended_re($unbacked))
+           if $extended;
+       return re_uninterp(escape_str($unbacked));
     } elsif ($type eq "concat") {
-       my $first = $self->re_dq($op->first);
-       my $last  = $self->re_dq($op->last);
+       my $first = $self->re_dq($op->first, $extended);
+       my $last  = $self->re_dq($op->last,  $extended);
+
        # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]"
-       if ($last =~ /^[A-Z\\\^\[\]_?]/) {
-           $first =~ s/([\$@])\^$/${1}{^}/;
-       }
-       elsif ($last =~ /^[{\[\w]/) {
-           $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/;
-       }
+       ($last =~ /^[A-Z\\\^\[\]_?]/ &&
+           $first =~ s/([\$@])\^$/${1}{^}/)  # "${^}W" etc
+           || ($last =~ /^[{\[\w_]/ &&
+               $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/);
+
        return $first . $last;
     } elsif ($type eq "uc") {
-       return '\U' . $self->re_dq($op->first->sibling) . '\E';
+       return '\U' . $self->re_dq($op->first->sibling, $extended) . '\E';
     } elsif ($type eq "lc") {
-       return '\L' . $self->re_dq($op->first->sibling) . '\E';
+       return '\L' . $self->re_dq($op->first->sibling, $extended) . '\E';
     } elsif ($type eq "ucfirst") {
-       return '\u' . $self->re_dq($op->first->sibling);
+       return '\u' . $self->re_dq($op->first->sibling, $extended);
     } elsif ($type eq "lcfirst") {
-       return '\l' . $self->re_dq($op->first->sibling);
+       return '\l' . $self->re_dq($op->first->sibling, $extended);
     } elsif ($type eq "quotemeta") {
-       return '\Q' . $self->re_dq($op->first->sibling) . '\E';
+       return '\Q' . $self->re_dq($op->first->sibling, $extended) . '\E';
     } elsif ($type eq "join") {
        return $self->deparse($op->last, 26); # was join($", @ary)
     } else {
@@ -3222,21 +3878,68 @@ sub re_dq {
     }
 }
 
-sub pp_regcomp {
+sub pure_string {
+    my ($self, $op) = @_;
+    return 0 if null $op;
+    my $type = $op->name;
+
+    if ($type eq 'const') {
+       return 1;
+    }
+    elsif ($type =~ /^[ul]c(first)?$/ || $type eq 'quotemeta') {
+       return $self->pure_string($op->first->sibling);
+    }
+    elsif ($type eq 'join') {
+       my $join_op = $op->first->sibling;  # Skip pushmark
+       return 0 unless $join_op->name eq 'null' && $join_op->targ eq OP_RV2SV;
+
+       my $gvop = $join_op->first;
+       return 0 unless $gvop->name eq 'gvsv';
+        return 0 unless '"' eq $self->gv_name($self->gv_or_padgv($gvop));
+
+       return 0 unless ${$join_op->sibling} eq ${$op->last};
+       return 0 unless $op->last->name =~ /^(rv2|pad)av$/;
+    }
+    elsif ($type eq 'concat') {
+       return $self->pure_string($op->first)
+            && $self->pure_string($op->last);
+    }
+    elsif (is_scalar($op) || $type =~ /^[ah]elem$/) {
+       return 1;
+    }
+    elsif ($type eq "null" and not null $op->first and
+          $op->first->name eq "null" and not null $op->first->first and
+          $op->first->first->name eq "aelemfast") {
+       return 1;
+    }
+    else {
+       return 0;
+    }
+
+    return 1;
+}
+
+sub regcomp {
     my $self = shift;
-    my($op, $cx) = @_;
+    my($op, $cx, $extended) = @_;
     my $kid = $op->first;
     $kid = $kid->first if $kid->name eq "regcmaybe";
     $kid = $kid->first if $kid->name eq "regcreset";
-    return $self->re_dq($kid);
+    return ($self->re_dq($kid, $extended), 1) if $self->pure_string($kid);
+    return ($self->deparse($kid, $cx), 0);
+}
+
+sub pp_regcomp {
+    my ($self, $op, $cx) = @_;
+    return (($self->regcomp($op, $cx, 0))[0]);
 }
 
 # osmic acid -- see osmium tetroxide
 
 my %matchwords;
 map($matchwords{join "", sort split //, $_} = $_, 'cig', 'cog', 'cos', 'cogs',
-    'cox', 'go', 'is', 'ism', 'iso', 'mig', 'mix', 'osmic', 'ox', 'sic', 
-    'sig', 'six', 'smog', 'so', 'soc', 'sog', 'xi'); 
+    'cox', 'go', 'is', 'ism', 'iso', 'mig', 'mix', 'osmic', 'ox', 'sic',
+    'sig', 'six', 'smog', 'so', 'soc', 'sog', 'xi');
 
 sub matchop {
     my $self = shift;
@@ -3248,10 +3951,19 @@ sub matchop {
        $var = $self->deparse($kid, 20);
        $kid = $kid->sibling;
     }
+    my $quote = 1;
+    my $extended = ($op->pmflags & PMf_EXTENDED);
     if (null $kid) {
-       $re = re_uninterp(escape_str(re_unback($op->precomp)));
+       my $unbacked = re_unback($op->precomp);
+       if ($extended) {
+           $re = re_uninterp_extended(escape_extended_re($unbacked));
+       } else {
+           $re = re_uninterp(escape_str(re_unback($op->precomp)));
+       }
+    } elsif ($kid->name ne 'regcomp') {
+       carp("found ".$kid->name." where regcomp expected");
     } else {
-       $re = $self->deparse($kid, 1);
+       ($re, $quote) = $self->regcomp($kid, 21, $extended);
     }
     my $flags = "";
     $flags .= "c" if $op->pmflags & PMf_CONTINUE;
@@ -3265,10 +3977,10 @@ sub matchop {
     if ($op->pmflags & PMf_ONCE) { # only one kind of delimiter works here
        $re =~ s/\?/\\?/g;
        $re = "?$re?";
-    } else {
+    } elsif ($quote) {
        $re = single_delim($name, $delim, $re);
     }
-    $re = $re . $flags;
+    $re = $re . $flags if $quote;
     if ($binop) {
        return $self->maybe_parens("$var =~ $re", $cx, 20);
     } else {
@@ -3285,9 +3997,22 @@ sub pp_split {
     my($op, $cx) = @_;
     my($kid, @exprs, $ary, $expr);
     $kid = $op->first;
-    if ($ {$kid->pmreplroot}) {
-       $ary = '@' . $self->gv_name($kid->pmreplroot);
-    }
+
+    # For our kid (an OP_PUSHRE), pmreplroot is never actually the
+    # root of a replacement; it's either empty, or abused to point to
+    # the GV for an array we split into (an optimization to save
+    # assignment overhead). Depending on whether we're using ithreads,
+    # this OP* holds either a GV* or a PADOFFSET. Luckily, B.xs
+    # figures out for us which it is.
+    my $replroot = $kid->pmreplroot;
+    my $gv = 0;
+    if (ref($replroot) eq "B::GV") {
+       $gv = $replroot;
+    } elsif (!ref($replroot) and $replroot > 0) {
+       $gv = $self->padval($replroot);
+    }
+    $ary = $self->stash_variable('@', $self->gv_name($gv)) if $gv;
+
     for (; !null($kid); $kid = $kid->sibling) {
        push @exprs, $self->deparse($kid, 6);
     }
@@ -3328,7 +4053,7 @@ sub pp_subst {
        $var = $self->deparse($kid, 20);
        $kid = $kid->sibling;
     }
-    my $flags = "";    
+    my $flags = "";
     if (null($op->pmreplroot)) {
        $repl = $self->dq($kid);
        $kid = $kid->sibling;
@@ -3339,15 +4064,22 @@ sub pp_subst {
            $flags .= "e";
        }
        if ($op->pmflags & PMf_EVAL) {
-           $repl = $self->deparse($repl, 0);
+           $repl = $self->deparse($repl->first, 0);
        } else {
            $repl = $self->dq($repl);   
        }
     }
+    my $extended = ($op->pmflags & PMf_EXTENDED);
     if (null $kid) {
-       $re = re_uninterp(escape_str(re_unback($op->precomp)));
+       my $unbacked = re_unback($op->precomp);
+       if ($extended) {
+           $re = re_uninterp_extended(escape_extended_re($unbacked));
+       }
+       else {
+           $re = re_uninterp(escape_str($unbacked));
+       }
     } else {
-       $re = $self->deparse($kid, 1);
+       ($re) = $self->regcomp($kid, 1, $extended);
     }
     $flags .= "e" if $op->pmflags & PMf_EVAL;
     $flags .= "g" if $op->pmflags & PMf_GLOBAL;
@@ -3355,7 +4087,7 @@ sub pp_subst {
     $flags .= "m" if $op->pmflags & PMf_MULTILINE;
     $flags .= "o" if $op->pmflags & PMf_KEEP;
     $flags .= "s" if $op->pmflags & PMf_SINGLELINE;
-    $flags .= "x" if $op->pmflags & PMf_EXTENDED;
+    $flags .= "x" if $extended;
     $flags = $substwords{$flags} if $substwords{$flags};
     if ($binop) {
        return $self->maybe_parens("$var =~ s"
@@ -3375,7 +4107,7 @@ B::Deparse - Perl compiler backend to produce perl code
 
 =head1 SYNOPSIS
 
-B<perl> B<-MO=Deparse>[B<,-u>I<PACKAGE>][B<,-p>][B<,-q>][B<,-l>]
+B<perl> B<-MO=Deparse>[B<,-d>][B<,-f>I<FILE>][B<,-p>][B<,-q>][B<,-l>]
         [B<,-s>I<LETTERS>][B<,-x>I<LEVEL>] I<prog.pl>
 
 =head1 DESCRIPTION
@@ -3391,8 +4123,13 @@ option, the output also includes parentheses even when they are not
 required by precedence, which can make it easy to see if perl is
 parsing your expressions the way you intended.
 
-Please note that this module is mainly new and untested code and is
-still under development, so it may change in the future.
+While B::Deparse goes to some lengths to try to figure out what your
+original program was doing, some parts of the language can still trip
+it up; it still fails even on some parts of Perl's own test suite. If
+you encounter a failure other than the most common ones described in
+the BUGS section below, you can help contribute to B::Deparse's
+ongoing development by submitting a bug report with a small
+example.
 
 =head1 OPTIONS
 
@@ -3401,6 +4138,24 @@ the '-MO=Deparse', separated by a comma but not any white space.
 
 =over 4
 
+=item B<-d>
+
+Output data values (when they appear as constants) using Data::Dumper.
+Without this option, B::Deparse will use some simple routines of its
+own for the same purpose. Currently, Data::Dumper is better for some
+kinds of data (such as complex structures with sharing and
+self-reference) while the built-in routines are better for others
+(such as odd floating-point values).
+
+=item B<-f>I<FILE>
+
+Normally, B::Deparse deparses the main code of a program, and all the subs
+defined in the same file. To include subs defined in other files, pass the
+B<-f> option with the filename. You can pass the B<-f> option several times, to
+include more than one secondary file.  (Most of the time you don't want to
+use it at all.)  You can also use this option to include subs which are
+defined in the scope of a B<#line> directive with two parameters.
+
 =item B<-l>
 
 Add '#line' declarations to the output based on the line and file
@@ -3414,7 +4169,7 @@ structure of your program. With B<-p>, it uses parentheses (almost)
 whenever they would be legal. This can be useful if you are used to
 LISP, or if you want to see how perl parses your input. If you say
 
-    if ($var & 0x7f == 65) {print "Gimme an A!"} 
+    if ($var & 0x7f == 65) {print "Gimme an A!"}
     print ($which ? $a : $b), "\n";
     $name = $ENV{USER} or "Bob";
 
@@ -3429,6 +4184,22 @@ C<B::Deparse,-p> will print
 which probably isn't what you intended (the C<'???'> is a sign that
 perl optimized away a constant value).
 
+=item B<-P>
+
+Disable prototype checking. With this option, all function calls are
+deparsed as if no prototype was defined for them. In other words,
+
+    perl -MO=Deparse,-P -e 'sub foo (\@) { 1 } foo @x'
+
+will print
+
+    sub foo (\@) {
+       1;
+    }
+    &foo(\@x);
+
+making clear how the parameters are actually passed to C<foo>.
+
 =item B<-q>
 
 Expand double-quoted strings into the corresponding combinations of
@@ -3448,15 +4219,6 @@ translation that B::Deparse usually does. On the other hand, note that
 C<$x = "$y"> is not the same as C<$x = $y>: the former makes the value
 of $y into a string before doing the assignment.
 
-=item B<-f>I<FILE>
-
-Normally, B::Deparse deparses the main code of a program, and all the subs
-defined in the same file. To include subs defined in other files, pass the
-B<-f> option with the filename. You can pass the B<-f> option several times, to
-include more than one secondary file.  (Most of the time you don't want to
-use it at all.)  You can also use this option to include subs which are
-defined in the scope of a B<#line> directive with two parameters.
-
 =item B<-s>I<LETTERS>
 
 Tweak the style of B::Deparse's output. The letters should follow
@@ -3523,7 +4285,7 @@ their internal operation. I<LEVEL> should be a digit, with higher values
 meaning more expansion. As with B<-q>, this actually involves turning off
 special cases in B::Deparse's normal operations.
 
-If I<LEVEL> is at least 3, for loops will be translated into equivalent
+If I<LEVEL> is at least 3, C<for> loops will be translated into equivalent
 while loops with continue blocks; for instance
 
     for ($i = 0; $i < 10; ++$i) {
@@ -3543,8 +4305,23 @@ Note that in a few cases this translation can't be perfectly carried back
 into the source code -- if the loop's initializer declares a my variable,
 for instance, it won't have the correct scope outside of the loop.
 
-If I<LEVEL> is at least 7, if statements will be translated into equivalent
-expressions using C<&&>, C<?:> and C<do {}>; for instance
+If I<LEVEL> is at least 5, C<use> declarations will be translated into
+C<BEGIN> blocks containing calls to C<require> and C<import>; for
+instance,
+
+    use strict 'refs';
+
+turns into
+
+    sub BEGIN {
+        require strict;
+        do {
+            'strict'->import('refs')
+        };
+    }
+
+If I<LEVEL> is at least 7, C<if> statements will be translated into
+equivalent expressions using C<&&>, C<?:> and C<do {}>; for instance
 
     print 'hi' if $nice;
     if ($nice) {
@@ -3634,7 +4411,7 @@ use re;
 Ordinarily, if you use B::Deparse on a subroutine which has
 been compiled in the presence of one or more of these pragmas,
 the output will include statements to turn on the appropriate
-directives. So if you then compile the code returned by coderef2text, 
+directives. So if you then compile the code returned by coderef2text,
 it will behave the same way as the subroutine which you deparsed.
 
 However, you may know that you intend to use the results in a
@@ -3642,6 +4419,9 @@ particular context, where some pragmas are already in scope. In
 this case, you use the B<ambient_pragmas> method to describe the
 assumptions you wish to make.
 
+Not all of the options currently have any useful effect. See
+L</BUGS> for more details.
+
 The parameters it accepts are:
 
 =over 4
@@ -3695,7 +4475,7 @@ parameter twice:
        warnings => [FATAL => qw/void io/],
     );
 
-See L<perllexwarn> for more information about lexical warnings. 
+See L<perllexwarn> for more information about lexical warnings.
 
 =item hint_bits
 
@@ -3734,13 +4514,68 @@ the main:: package, the code will include a package declaration.
 
 =head1 BUGS
 
-See the 'to do' list at the beginning of the module file.
+=over 4
+
+=item *
+
+The only pragmas to be completely supported are: C<use warnings>,
+C<use strict 'refs'>, C<use bytes>, and C<use integer>. (C<$[>, which
+behaves like a pragma, is also supported.)
+
+Excepting those listed above, we're currently unable to guarantee that
+B::Deparse will produce a pragma at the correct point in the program.
+(Specifically, pragmas at the beginning of a block often appear right
+before the start of the block instead.)
+Since the effects of pragmas are often lexically scoped, this can mean
+that the pragma holds sway over a different portion of the program
+than in the input file.
+
+=item *
+
+In fact, the above is a specific instance of a more general problem:
+we can't guarantee to produce BEGIN blocks or C<use> declarations in
+exactly the right place. So if you use a module which affects compilation
+(such as by over-riding keywords, overloading constants or whatever)
+then the output code might not work as intended.
+
+This is the most serious outstanding problem, and will require some help
+from the Perl core to fix.
+
+=item *
+
+If a keyword is over-ridden, and your program explicitly calls
+the built-in version by using CORE::keyword, the output of B::Deparse
+will not reflect this. If you run the resulting code, it will call
+the over-ridden version rather than the built-in one. (Maybe there
+should be an option to B<always> print keyword calls as C<CORE::name>.)
+
+=item *
+
+Some constants don't print correctly either with or without B<-d>.
+For instance, neither B::Deparse nor Data::Dumper know how to print
+dual-valued scalars correctly, as in:
+
+    use constant E2BIG => ($!=7); $y = E2BIG; print $y, 0+$y;
+
+=item *
+
+An input file that uses source filtering probably won't be deparsed into
+runnable code, because it will still include the B<use> declaration
+for the source filtering module, even though the code that is
+produced is already ordinary Perl which shouldn't be filtered again.
+
+=item *
+
+There are probably many more bugs on non-ASCII platforms (EBCDIC).
+
+=back
 
 =head1 AUTHOR
 
-Stephen McCamant <smcc@CSUA.Berkeley.EDU>, based on an earlier
-version by Malcolm Beattie <mbeattie@sable.ox.ac.uk>, with
-contributions from Gisle Aas, James Duncan, Albert Dvornik, Hugo van
-der Sanden, Gurusamy Sarathy, and Nick Ing-Simmons.
+Stephen McCamant <smcc@CSUA.Berkeley.EDU>, based on an earlier version
+by Malcolm Beattie <mbeattie@sable.ox.ac.uk>, with contributions from
+Gisle Aas, James Duncan, Albert Dvornik, Robin Houston, Dave Mitchell,
+Hugo van der Sanden, Gurusamy Sarathy, Nick Ing-Simmons, and Rafael
+Garcia-Suarez.
 
 =cut