use strict; use warnings; use Data::Dumper; $^R=undef; my $re = qr/ (?{[$^R]}) # initialize a new node in the parsetree # preserving the old as the 0th element \( # match a paren (?> # atomic match ([^()]+) # capture (?{ push @{$^R},$1; # push the capture string into the current node $^R # propagate the current node }) | (?0) # recurse (?{ push @{$^R->[0]},$^R; # push the current node into the old node shift @{$^R} # and restore the old node to be the current # (while removing it from the new) }) )* \) /x; "(a(b)(c(d)e)(f)g)" =~ m/$re/x and print "matched\n"; print Dumper $^R; #### matched $VAR1 = [ undef, 'a', [ 'b' ], [ 'c', [ 'd' ], 'e' ], [ 'f' ], 'g' ];