This patch adds support to precise information about $&, $`, $', and
$<digit> by a way to find offsets in the string, and which match is $+.
The start/end offsets are available in @- and @+.

(Note that this info may be used to remove overhead associated to $&
and friends - by modifications to the scripts on the level of Perl.)

Note the last chunk: it makes $#- and $#+ legal.  While this patch as
a whole cannot go into 5.005, I can make a tiny modification to the
last chunk to produce -w-warnings if $#- and $#+ are seen (say, in
$#-1).

Enjoy,
Ilya

P.S.  Thinking of it, maybe it would be better to put these guys on 
      @` and @', but that would contaminate things via sawampersand.

P.P.S.  It may better to keep offsets directly in startp[] and endp[],
	instead of having pointers there.

diff -pru perl5.004_76/av.c perl5.004_76.my/av.c
--- perl5.004_76/av.c	Tue Jul 21 01:05:29 1998
+++ perl5.004_76.my/av.c	Tue Jul 21 21:20:33 1998
@@ -162,7 +162,7 @@ av_fetch(register AV *av, I32 key, I32 l
     }
 
     if (SvRMAGICAL(av)) {
-	if (mg_find((SV*)av,'P')) {
+	if (mg_find((SV*)av,'P') || mg_find((SV*)av,'D')) {
 	    dTHR;
 	    sv = sv_newmortal();
 	    mg_copy((SV*)av, sv, 0, key);
diff -pru perl5.004_76/embed.h perl5.004_76.my/embed.h
--- perl5.004_76/embed.h	Sun Jul 19 21:09:57 1998
+++ perl5.004_76.my/embed.h	Tue Jul 21 22:40:43 1998
@@ -294,6 +294,8 @@
 #define magic_len		Perl_magic_len
 #define magic_mutexfree		Perl_magic_mutexfree
 #define magic_nextpack		Perl_magic_nextpack
+#define magic_regdata_cnt	Perl_magic_regdata_cnt
+#define magic_regdatum_get	Perl_magic_regdatum_get
 #define magic_set		Perl_magic_set
 #define magic_set_all_env	Perl_magic_set_all_env
 #define magic_setamagic		Perl_magic_setamagic
diff -pru perl5.004_76/global.sym perl5.004_76.my/global.sym
--- perl5.004_76/global.sym	Sat Jul 18 00:28:29 1998
+++ perl5.004_76.my/global.sym	Tue Jul 21 22:40:14 1998
@@ -393,6 +393,8 @@ magic_getvec
 magic_len
 magic_mutexfree
 magic_nextpack
+magic_regdata_cnt
+magic_regdatum_get
 magic_set
 magic_set_all_env
 magic_setamagic
diff -pru perl5.004_76/gv.c perl5.004_76.my/gv.c
--- perl5.004_76/gv.c	Mon Jul 20 04:20:08 1998
+++ perl5.004_76.my/gv.c	Tue Jul 21 21:35:57 1998
@@ -734,6 +734,14 @@ gv_fetchpv(char *nambeg, I32 add, I32 sv
 	    }
 	}
 	goto magicalize;
+    case '-':
+	if (len > 1)
+	    break;
+	else {
+            AV* av = GvAVn(gv);
+            sv_magic((SV*)av, Nullsv, 'D', Nullch, 0);
+        }
+	goto magicalize;
     case '#':
     case '*':
 	if (PL_dowarn && len == 1 && sv_type == SVt_PV)
@@ -743,7 +751,6 @@ gv_fetchpv(char *nambeg, I32 add, I32 sv
     case '^':
     case '~':
     case '=':
-    case '-':
     case '%':
     case '.':
     case '(':
@@ -767,8 +774,19 @@ gv_fetchpv(char *nambeg, I32 add, I32 sv
 	if (len > 1)
 	    break;
 	goto magicalize;
+    case '\023':
+	if (len > 1)
+	    break;
+	goto ro_magicalize;
 
     case '+':
+	if (len > 1)
+	    break;
+	else {
+            AV* av = GvAVn(gv);
+            sv_magic((SV*)av, (SV*)av, 'D', Nullch, 0);
+        }
+	/* FALL THROUGH */
     case '1':
     case '2':
     case '3':
@@ -778,7 +796,6 @@ gv_fetchpv(char *nambeg, I32 add, I32 sv
     case '7':
     case '8':
     case '9':
-    case '\023':
       ro_magicalize:
 	SvREADONLY_on(GvSV(gv));
       magicalize:
diff -pru perl5.004_76/mg.c perl5.004_76.my/mg.c
--- perl5.004_76/mg.c	Mon Jul 20 04:20:09 1998
+++ perl5.004_76.my/mg.c	Tue Jul 21 22:22:48 1998
@@ -282,6 +282,48 @@ mg_free(SV *sv)
 #include <signal.h>
 #endif
 
+int
+magic_regdata_cnt(SV *sv, MAGIC *mg)
+{
+    dTHR;
+    register char *s;
+    register I32 i;
+    register REGEXP *rx;
+    char *t;
+
+    if (PL_curpm && (rx = PL_curpm->op_pmregexp))
+	return rx->lastparen;
+    return -1;
+}
+
+int
+magic_regdatum_get(SV *sv, MAGIC *mg)
+{
+    dTHR;
+    register I32 paren;
+    register char *s;
+    register I32 i;
+    register REGEXP *rx;
+    char *t;
+
+    if (PL_curpm && (rx = PL_curpm->op_pmregexp)) {
+	paren = mg->mg_len;
+	if (paren < 0)
+	    return 0;
+	if (paren <= rx->nparens &&
+	    (s = rx->startp[paren]) &&
+	    (t = rx->endp[paren]))
+	    {
+		if (mg->mg_obj)		/* @+ */
+		    i = t - rx->subbase;
+		else			/* @- */
+		    i = s - rx->subbase;
+		sv_setiv(sv,i);
+	    }
+    }
+    return 0;
+}
+
 U32
 magic_len(SV *sv, MAGIC *mg)
 {
diff -pru perl5.004_76/perl.h perl5.004_76.my/perl.h
--- perl5.004_76/perl.h	Tue Jul 21 01:45:30 1998
+++ perl5.004_76.my/perl.h	Tue Jul 21 19:43:40 1998
@@ -2081,6 +2081,8 @@ EXT MGVTBL vtbl_defelem = {magic_getdefe
 					0,	0,	0};
 
 EXT MGVTBL vtbl_regexp = {0,0,0,0, magic_freeregexp};
+EXT MGVTBL vtbl_regdata = {0, 0, magic_regdata_cnt, 0, 0};
+EXT MGVTBL vtbl_regdatum = {magic_regdatum_get, 0, 0, 0, 0};
 
 #ifdef USE_LOCALE_COLLATE
 EXT MGVTBL vtbl_collxfrm = {0,
@@ -2125,6 +2127,8 @@ EXT MGVTBL vtbl_mutex;
 
 EXT MGVTBL vtbl_defelem;
 EXT MGVTBL vtbl_regexp;
+EXT MGVTBL vtbl_regdata;
+EXT MGVTBL vtbl_regdatum;
 
 #ifdef USE_LOCALE_COLLATE
 EXT MGVTBL vtbl_collxfrm;
diff -pru perl5.004_76/pod/perlvar.pod perl5.004_76.my/pod/perlvar.pod
--- perl5.004_76/pod/perlvar.pod	Wed Jun 24 08:30:10 1998
+++ perl5.004_76.my/pod/perlvar.pod	Tue Jul 21 22:43:43 1998
@@ -164,6 +164,18 @@ example:
 (Mnemonic: be positive and forward looking.)
 This variable is read-only.
 
+=item @+
+
+$+[0] is the offset of the end of the last successfull match.
+C<$+[>I<n>C<]> is the offset of the end of the substring matched by
+I<n>-th subpattern.  
+
+Thus after a match against $_, $& coincides with C<substr $_, $-[0],
+$+[0]>.  Similarly, C<$>I<n> coincides with C<substr $_, $-[>I<n>C<],
+$+[>I<0>C<]> if C<$-[>I<n>C<]> is defined, and $+ conincides with
+C<substr $_, $-[-1], $+[-1]>.  One can use C<$#+> to find the last
+matched subgroup in the last successful match.  Compare with L<"@-">.
+
 =item $MULTILINE_MATCHING
 
 =item $*
@@ -372,6 +384,18 @@ output channel.  Default is 60.  (Mnemon
 
 The number of lines left on the page of the currently selected output
 channel.  (Mnemonic: lines_on_page - lines_printed.)
+
+=item @-
+
+$-[0] is the offset of the start of the last successfull match.
+C<$-[>I<n>C<]> is the offset of the start of the substring matched by
+I<n>-th subpattern.  
+
+Thus after a match against $_, $& coincides with C<substr $_, $-[0],
+$+[0]>.  Similarly, C<$>I<n> coincides with C<substr $_, $-[>I<n>C<],
+$+[>I<0>C<]> if C<$-[>I<n>C<]> is defined, and $+ conincides with
+C<substr $_, $-[-1], $+[-1]>.  One can use C<$#-> to find the last
+matched subgroup in the last successful match.  Compare with L<"@+">.
 
 =item format_name HANDLE EXPR
 
diff -pru perl5.004_76/proto.h perl5.004_76.my/proto.h
--- perl5.004_76/proto.h	Tue Jul 21 03:21:09 1998
+++ perl5.004_76.my/proto.h	Tue Jul 21 19:42:37 1998
@@ -227,6 +227,8 @@ VIRTUAL U32	magic_len	_((SV* sv, MAGIC* 
 VIRTUAL int	magic_mutexfree	_((SV* sv, MAGIC* mg));
 #endif /* USE_THREADS */
 VIRTUAL int	magic_nextpack	_((SV* sv, MAGIC* mg, SV* key));
+VIRTUAL int	magic_regdata_cnt	_((SV* sv, MAGIC* mg));
+VIRTUAL int	magic_regdatum_get	_((SV* sv, MAGIC* mg));
 VIRTUAL int	magic_set	_((SV* sv, MAGIC* mg));
 #ifdef OVERLOAD
 VIRTUAL int	magic_setamagic	_((SV* sv, MAGIC* mg));
diff -pru perl5.004_76/regnodes.h perl5.004_76.my/regnodes.h
--- perl5.004_76/regnodes.h	Sun Jun 28 17:13:41 1998
+++ perl5.004_76.my/regnodes.h	Tue Jul 21 22:40:44 1998
@@ -3,7 +3,7 @@
    Any changes made here will be lost!
 */
 
-#define	END	0	/*    0 End of program. */
+#define	END	0	/*  0x0 End of program. */
 #define	SUCCEED	1	/*  0x1 Return from a subroutine, basically. */
 #define	BOL	2	/*  0x2 Match "" at beginning of line. */
 #define	MBOL	3	/*  0x3 Same, assuming multiline. */
diff -pru perl5.004_76/sv.c perl5.004_76.my/sv.c
--- perl5.004_76/sv.c	Tue Jul 21 01:05:30 1998
+++ perl5.004_76.my/sv.c	Tue Jul 21 21:24:41 1998
@@ -2587,6 +2587,12 @@ sv_magic(register SV *sv, SV *obj, int h
     case 'B':
 	mg->mg_virtual = &vtbl_bm;
 	break;
+    case 'D':
+	mg->mg_virtual = &vtbl_regdata;
+	break;
+    case 'd':
+	mg->mg_virtual = &vtbl_regdatum;
+	break;
     case 'E':
 	mg->mg_virtual = &vtbl_env;
 	break;
diff -pru perl5.004_76/t/op/pat.t perl5.004_76.my/t/op/pat.t
--- perl5.004_76/t/op/pat.t	Tue Jul 21 01:01:06 1998
+++ perl5.004_76.my/t/op/pat.t	Tue Jul 21 22:32:09 1998
@@ -4,7 +4,7 @@
 # the format supported by op/regexp.t.  If you want to add a test
 # that does fit that format, add it to op/re_tests, not here.
 
-print "1..141\n";
+print "1..158\n";
 
 BEGIN {
     chdir 't' if -d 't';
@@ -592,6 +592,82 @@ $test++;
 
 @_ = /(bbb)/g;
 print "not " if @_;
+print "ok $test\n";
+$test++;
+
+/a(?=.$)/;
+print "not " if $#+ != 0 or $#- != 0;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[0] != 2 or $-[0] != 1;
+print "ok $test\n";
+$test++;
+
+print "not " 
+   if defined $+[1] or defined $-[1] or defined $+[2] or defined $-[2];
+print "ok $test\n";
+$test++;
+
+/a(a)(a)/;
+print "not " if $#+ != 2 or $#- != 2;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[0] != 3 or $-[0] != 0;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[1] != 2 or $-[1] != 1;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[2] != 3 or $-[2] != 2;
+print "ok $test\n";
+$test++;
+
+print "not " 
+   if defined $+[3] or defined $-[3] or defined $+[4] or defined $-[4];
+print "ok $test\n";
+$test++;
+
+/.(a)(b)?(a)/;
+print "not " if $#+ != 3 or $#- != 3;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[0] != 3 or $-[0] != 0;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[1] != 2 or $-[1] != 1;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[3] != 3 or $-[3] != 2;
+print "ok $test\n";
+$test++;
+
+print "not " 
+   if defined $+[2] or defined $-[2] or defined $+[4] or defined $-[4];
+print "ok $test\n";
+$test++;
+
+/.(a)/;
+print "not " if $#+ != 1 or $#- != 1;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[0] != 2 or $-[0] != 0;
+print "ok $test\n";
+$test++;
+
+print "not " if $+[1] != 2 or $-[1] != 1;
+print "ok $test\n";
+$test++;
+
+print "not " 
+   if defined $+[2] or defined $-[2] or defined $+[3] or defined $-[3];
 print "ok $test\n";
 $test++;
 
diff -pru perl5.004_76/toke.c perl5.004_76.my/toke.c
--- perl5.004_76/toke.c	Tue Jul 21 01:57:44 1998
+++ perl5.004_76.my/toke.c	Tue Jul 21 21:44:05 1998
@@ -2493,7 +2493,7 @@ yylex(void)
 	    }
 	}
 
-	if (s[1] == '#' && (isALPHA(s[2]) || strchr("_{$:", s[2]))) {
+	if (s[1] == '#' && (isALPHA(s[2]) || strchr("_{$:+-", s[2]))) {
 	    if (PL_expect == XOPERATOR)
 		no_op("Array length", PL_bufptr);
 	    PL_tokenbuf[0] = '@';
