Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a perl interpreter bug on line number in error message #14070

Closed
p5pRT opened this issue Sep 3, 2014 · 31 comments
Labels

Comments

@p5pRT
Copy link
Collaborator

@p5pRT p5pRT commented Sep 3, 2014

Migrated from rt.perl.org#122695 (status was 'resolved')

Searchable as RT122695$

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 3, 2014

From qj1020@yahoo.com

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from email account. See the attached file for detail.

Thanks
Jin

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 3, 2014

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 3, 2014

From @karenetheridge

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

  sub dummy {
  if ($a>3) {
  $a ++;
  }
  else {printf(1/0); }
  return 1;
  }
  dummy();

identifies the culprit as line 2, not line 5.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 3, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @cpansprout

On Wed Sep 03 13​:20​:25 2014, ether wrote​:

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

sub dummy   \{
    if \($a>3\) \{
        $a \+\+;
    \}
    else \{printf\(1/0\); \}
    return 1;
\}
dummy\(\);

identifies the culprit as line 2, not line 5.

5.8.8 is fine. 5.8.9 is not. That should make bisecting pretty quick....

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @cpansprout

On Wed Sep 03 17​:47​:32 2014, sprout wrote​:

On Wed Sep 03 13​:20​:25 2014, ether wrote​:

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

sub dummy   \{
    if \($a>3\) \{
        $a \+\+;
    \}
    else \{printf\(1/0\); \}
    return 1;
\}
dummy\(\);

identifies the culprit as line 2, not line 5.

5.8.8 is fine. 5.8.9 is not. That should make bisecting pretty quick....

Er, never mind that. perl 5.8.8 dies at compile time. If you change it to ‘die’, then it shows line 2, too.

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @pjcj

On Wed, Sep 03, 2014 at 05​:50​:30PM -0700, Father Chrysostomos via RT wrote​:

On Wed Sep 03 17​:47​:32 2014, sprout wrote​:

On Wed Sep 03 13​:20​:25 2014, ether wrote​:

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

sub dummy   \{
    if \($a>3\) \{
        $a \+\+;
    \}
    else \{printf\(1/0\); \}
    return 1;
\}
dummy\(\);

identifies the culprit as line 2, not line 5.

5.8.8 is fine. 5.8.9 is not. That should make bisecting pretty quick....

Er, never mind that. perl 5.8.8 dies at compile time. If you change it to ‘die’, then it shows line 2, too.

This is a longstanding bug/deficiency caused by having the closest COP
being the if statement on line 2.

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

--
Paul Johnson - paul@​pjcj.net
http​://www.pjcj.net

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @jkeenan

On Thu Sep 04 02​:02​:55 2014, paul@​pjcj.net wrote​:

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage
(because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

Speaking only for myself​: I have never been bothered much by these minor inaccuracies in matching errors to line numbers. So I wouldn't want a significant increase in Perl's memory usage if that's the price we'd have to pay for such inaccuracies.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @demerphq

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

On Wed, Sep 03, 2014 at 05​:50​:30PM -0700, Father Chrysostomos via RT wrote​:

On Wed Sep 03 17​:47​:32 2014, sprout wrote​:

On Wed Sep 03 13​:20​:25 2014, ether wrote​:

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

sub dummy   \{
    if \($a>3\) \{
        $a \+\+;
    \}
    else \{printf\(1/0\); \}
    return 1;
\}
dummy\(\);

identifies the culprit as line 2, not line 5.

5.8.8 is fine. 5.8.9 is not. That should make bisecting pretty
quick....

Er, never mind that. perl 5.8.8 dies at compile time. If you change it
to ‘die’, then it shows line 2, too.

This is a longstanding bug/deficiency caused by having the closest COP
being the if statement on line 2.

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

It would be cool if we could choose at startup with an option.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @rgarcia

On 4 September 2014 13​:09, demerphq <demerphq@​gmail.com> wrote​:

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

On Wed, Sep 03, 2014 at 05​:50​:30PM -0700, Father Chrysostomos via RT
wrote​:

On Wed Sep 03 17​:47​:32 2014, sprout wrote​:

On Wed Sep 03 13​:20​:25 2014, ether wrote​:

On Wed Sep 03 09​:20​:01 2014, qj1020@​yahoo.com wrote​:

Dear perl maintainer,

perlbug couldn't send the email on its own, so I am sending it
from
email account. See the attached file for detail.

Thanks
Jin

Confirmed (darwin, 5.21.3)​: this code​:

sub dummy   \{
    if \($a>3\) \{
        $a \+\+;
    \}
    else \{printf\(1/0\); \}
    return 1;
\}
dummy\(\);

identifies the culprit as line 2, not line 5.

5.8.8 is fine. 5.8.9 is not. That should make bisecting pretty
quick....

Er, never mind that. perl 5.8.8 dies at compile time. If you change it
to ‘die’, then it shows line 2, too.

This is a longstanding bug/deficiency caused by having the closest COP
being the if statement on line 2.

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

It would be cool if we could choose at startup with an option.

I think the memory usage would increase due to the OP structure being
made larger -- so that would be a compile-time option.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @pjcj

On Thu, Sep 04, 2014 at 01​:28​:17PM +0200, Rafael Garcia-Suarez wrote​:

On 4 September 2014 13​:09, demerphq <demerphq@​gmail.com> wrote​:

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

It would be cool if we could choose at startup with an option.

I think the memory usage would increase due to the OP structure being
made larger -- so that would be a compile-time option.

And now it's starting to sound like MAD's little cousin. I suspect it's
not worth making it optional unless it can be made a runtime option.

I wonder, though, whether it might be possible to make a special OP with
line information, that is only used where it is necessary. That is,
where the COP information which would otherwise be used is incorrect.
Such a scheme, if feasible, should have a relatively low overhead, I
imagine.

--
Paul Johnson - paul@​pjcj.net
http​://www.pjcj.net

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @rgarcia

On 4 September 2014 14​:01, Paul Johnson <paul@​pjcj.net> wrote​:

I wonder, though, whether it might be possible to make a special OP with
line information, that is only used where it is necessary. That is,
where the COP information which would otherwise be used is incorrect.
Such a scheme, if feasible, should have a relatively low overhead, I
imagine.

Low memory overhead, yes, but what about the run-time overhead?
Could we skip executing this op at all (like nullified ops)?

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @timbunce

On Thu, Sep 04, 2014 at 03​:53​:42AM -0700, James E Keenan via RT wrote​:

Speaking only for myself​: I have never been bothered much by these minor inaccuracies in matching errors to line numbers. So I wouldn't want a significant increase in Perl's memory usage if that's the price we'd have to pay for such inaccuracies.

Just a reminder that the Devel​::NYTProf statement profiler uses the line
numbers to allocate timings for statements.

So optionally increasing the accuracy (perhaps via a $^P bit) would be nice.

Tim.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 4, 2014

From @cpansprout

On Thu Sep 04 05​:02​:17 2014, paul@​pjcj.net wrote​:

On Thu, Sep 04, 2014 at 01​:28​:17PM +0200, Rafael Garcia-Suarez wrote​:

On 4 September 2014 13​:09, demerphq <demerphq@​gmail.com> wrote​:

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

It was Zefram who raised the objection last time. I don’t think the memory increase would be too significant, but it’s subjective.

It would be cool if we could choose at startup with an option.

I think the memory usage would increase due to the OP structure being
made larger -- so that would be a compile-time option.

And now it's starting to sound like MAD's little cousin. I suspect it's
not worth making it optional unless it can be made a runtime option.

I wonder, though, whether it might be possible to make a special OP with
line information, that is only used where it is necessary. That is,
where the COP information which would otherwise be used is incorrect.
Such a scheme, if feasible, should have a relatively low overhead, I
imagine.

Doesn’t sound too bad. I once wondered whether just extending entersub ops to store a line number would fix most cases (i.e., caller giving the wrong line), but that would not fix this bug.

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 7, 2014

From @rurban

On 09/04/2014 10​:24 AM, Father Chrysostomos via RT wrote​:

On Thu Sep 04 05​:02​:17 2014, paul@​pjcj.net wrote​:

On Thu, Sep 04, 2014 at 01​:28​:17PM +0200, Rafael Garcia-Suarez wrote​:

On 4 September 2014 13​:09, demerphq <demerphq@​gmail.com> wrote​:

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage (because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like others
disagree. Is that still the case?

It was Zefram who raised the objection last time. I don’t think the memory increase would be too significant, but it’s subjective.

It would be cool if we could choose at startup with an option.

I think the memory usage would increase due to the OP structure being
made larger -- so that would be a compile-time option.

And now it's starting to sound like MAD's little cousin. I suspect it's
not worth making it optional unless it can be made a runtime option.

I wonder, though, whether it might be possible to make a special OP with
line information, that is only used where it is necessary. That is,
where the COP information which would otherwise be used is incorrect.
Such a scheme, if feasible, should have a relatively low overhead, I
imagine.

Doesn’t sound too bad. I once wondered whether just extending entersub ops to store a line number would fix most cases (i.e., caller giving the wrong line), but that would not fix this bug.

Looks like you cannot remember my old oplines patch from 2008, which
showed that moving the line from the COP to every OP will save ~8%
memory and a small amount (2-5%) of runtime. smaller and faster, not bigger.

There is still work to be done, which I didn't want to do alone then,
but the general idea proves the opposite to what you are talking about here.
TODO​:
1. debugging needs to add state ops, instead of just switching from
nextstate;
2. errors and warnings need to walk more back, instead of just to the
prev. line to the prev. block.

as small side-effect this little artefact would also have been fixed,
but the general improvements are much bigger than just reporting the
right line number.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 7, 2014

From @rurban

oplines1.patch
diff --git a/cop.h b/cop.h
index 39a6b01..417517b 100644
--- a/cop.h
+++ b/cop.h
@@ -134,11 +134,21 @@ typedef struct jmpenv JMPENV;
 
 #include "mydtrace.h"
 
+/* Reini Urban moved the cop_line to BASEOP.
+
+   Theory: On an average of 4 ops per line, and the reduced need for 
+   runtime nextstates of 90% - only lexstate changes and file beginning
+   and the overhead of 5 ptrs per COP, we will win 4ptrs per reduced COP.
+   On typical 10k src with 40k ops it will be a 4 ptrs(5-1)*10k memory win: 40kb 
+   (4 ops per line on average), plus the runtime win of ~about 4k ops, 8%. */
+
 struct cop {
     BASEOP
     /* On LP64 putting this here takes advantage of the fact that BASEOP isn't
        an exact multiple of 8 bytes to save structure padding.  */
+#ifndef TRY_OPLINES
     line_t      cop_line;       /* line # of this command */
+#endif
     /* label for this construct is now stored in cop_hints_hash */
 #ifdef USE_ITHREADS
     char *	cop_stashpv;	/* package line was compiled in */
@@ -226,7 +236,11 @@ struct cop {
 #define CopLABEL_alloc(pv)	((pv)?savepv(pv):NULL)
 
 #define CopSTASH_ne(c,hv)	(!CopSTASH_eq(c,hv))
+#ifdef TRY_OPLINES
+#define CopLINE(c)		((c)->op_line)
+#else
 #define CopLINE(c)		((c)->cop_line)
+#endif
 #define CopLINE_inc(c)		(++CopLINE(c))
 #define CopLINE_dec(c)		(--CopLINE(c))
 #define CopLINE_set(c,l)	(CopLINE(c) = (l))
diff --git a/op.c b/op.c
index d80aa95..1f8f204 100644
--- a/op.c
+++ b/op.c
@@ -104,6 +104,13 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
 
 #define CALL_PEEP(o) CALL_FPTR(PL_peepp)(aTHX_ o)
 
+#ifdef TRY_OPLINES
+# define STORE_COPLINE(op) CopLINE_set(op, PL_parser ? PL_parser->copline : PL_curcop);
+#else
+# define STORE_COPLINE(op)
+#endif
+
+
 #if defined(PL_OP_SLAB_ALLOC)
 
 #ifdef PERL_DEBUG_READONLY_OPS
@@ -837,12 +844,23 @@ S_scalarboolean(pTHX_ OP *o)
 
     if (o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST) {
 	if (ckWARN(WARN_SYNTAX)) {
+#ifdef TRY_OPLINES
+	    OP* op;
+	    op = PL_op ? PL_op : PL_curcop;
+	    const line_t oldline = CopLINE(op);
+
+	    if (PL_parser && PL_parser->copline != NOLINE)
+		CopLINE_set(PL_curcop, PL_parser->copline);
+	    Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Found = in conditional, should be ==");
+	    CopLINE_set(op, oldline);
+#else
 	    const line_t oldline = CopLINE(PL_curcop);
 
 	    if (PL_parser && PL_parser->copline != NOLINE)
 		CopLINE_set(PL_curcop, PL_parser->copline);
 	    Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Found = in conditional, should be ==");
 	    CopLINE_set(PL_curcop, oldline);
+#endif
 	}
     }
     return scalar(o);
@@ -1435,7 +1453,8 @@ Perl_mod(pTHX_ OP *o, I32 type)
 			newop->op_type = OP_RV2CV;
 			newop->op_ppaddr = PL_ppaddr[OP_RV2CV];
 			newop->op_first = NULL;
-                        newop->op_next = (OP*)newop;
+			newop->op_next = (OP*)newop;
+			STORE_COPLINE(newop);
 			kid->op_sibling = (OP*)newop;
 			newop->op_private |= OPpLVAL_INTRO;
 			newop->op_private &= ~1;
@@ -3000,6 +3019,7 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
 
     listop->op_type = (OPCODE)type;
     listop->op_ppaddr = PL_ppaddr[type];
+    STORE_COPLINE(listop);
     if (first || last)
 	flags |= OPf_KIDS;
     listop->op_flags = (U8)flags;
@@ -3014,6 +3034,7 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     listop->op_last = last;
     if (type == OP_LIST) {
 	OP* const pushop = newOP(OP_PUSHMARK, 0);
+	STORE_COPLINE(pushop);
 	pushop->op_sibling = first;
 	listop->op_first = pushop;
 	listop->op_flags |= OPf_KIDS;
@@ -3036,6 +3057,7 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
     o->op_latefree = 0;
     o->op_latefreed = 0;
     o->op_attached = 0;
+    STORE_COPLINE(o);
 
     o->op_next = o;
     o->op_private = (U8)(0 | (flags >> 8));
@@ -3063,6 +3085,7 @@ Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
     unop->op_first = first;
     unop->op_flags = (U8)(flags | OPf_KIDS);
     unop->op_private = (U8)(1 | (flags >> 8));
+    STORE_COPLINE(unop);
     unop = (UNOP*) CHECKOP(type, unop);
     if (unop->op_next)
 	return (OP*)unop;
@@ -3084,6 +3107,7 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     binop->op_ppaddr = PL_ppaddr[type];
     binop->op_first = first;
     binop->op_flags = (U8)(flags | OPf_KIDS);
+    STORE_COPLINE(binop);
     if (!last) {
 	last = first;
 	binop->op_private = (U8)(1 | (flags >> 8));
@@ -3476,6 +3500,7 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
     pmop->op_ppaddr = PL_ppaddr[type];
     pmop->op_flags = (U8)flags;
     pmop->op_private = (U8)(0 | (flags >> 8));
+    STORE_COPLINE(pmop);
 
     if (PL_hints & HINT_RE_TAINT)
 	pmop->op_pmflags |= PMf_RETAINT;
@@ -3608,6 +3633,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
 			    | (reglist ? OPf_STACKED : 0);
 	rcop->op_private = 1;
 	rcop->op_other = o;
+        STORE_COPLINE(rcop);
 	if (reglist)
 	    rcop->op_targ = pad_alloc(rcop->op_type, SVs_PADTMP);
 
@@ -3721,6 +3747,7 @@ Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
     svop->op_sv = sv;
     svop->op_next = (OP*)svop;
     svop->op_flags = (U8)flags;
+    STORE_COPLINE(svop);
     if (PL_opargs[type] & OA_RETSCALAR)
 	scalar((OP*)svop);
     if (PL_opargs[type] & OA_TARGET)
@@ -3741,6 +3768,7 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
     padop->op_type = (OPCODE)type;
     padop->op_ppaddr = PL_ppaddr[type];
     padop->op_padix = pad_alloc(type, SVs_PADTMP);
+    STORE_COPLINE(padop);
     SvREFCNT_dec(PAD_SVl(padop->op_padix));
     PAD_SETSV(padop->op_padix, sv);
     assert(sv);
@@ -3781,6 +3809,7 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
     pvop->op_pv = pv;
     pvop->op_next = (OP*)pvop;
     pvop->op_flags = (U8)flags;
+    STORE_COPLINE(pvop);
     if (PL_opargs[type] & OA_RETSCALAR)
 	scalar((OP*)pvop);
     if (PL_opargs[type] & OA_TARGET)
diff --git a/op.h b/op.h
index dad6016..15f9e73 100644
--- a/op.h
+++ b/op.h
@@ -30,6 +30,7 @@
  *	op_attached	this op (sub)tree has been attached to a CV
  *
  *	op_spare	three spare bits!
+ *	op_line         Current line number of this op (previously cop_line)
  *	op_flags	Flags common to all operations.  See OPf_* below.
  *	op_private	Flags peculiar to a particular operation (BUT,
  *			by default, set to the number of children until
@@ -50,6 +51,13 @@ typedef PERL_BITFIELD16 Optype;
 #ifdef BASEOP_DEFINITION
 #define BASEOP BASEOP_DEFINITION
 #else
+
+#ifdef TRY_OPLINES
+#   define TRY_OPLINES_IN_BASEOP    line_t      op_line;
+#else
+#   define TRY_OPLINES_IN_BASEOP
+#endif
+
 #define BASEOP				\
     OP*		op_next;		\
     OP*		op_sibling;		\
@@ -62,6 +70,7 @@ typedef PERL_BITFIELD16 Optype;
     PERL_BITFIELD16 op_latefreed:1;	\
     PERL_BITFIELD16 op_attached:1;	\
     PERL_BITFIELD16 op_spare:3;		\
+    TRY_OPLINES_IN_BASEOP               \
     U8		op_flags;		\
     U8		op_private;
 #endif
diff --git a/perly.act b/perly.act
index 5a908c3..12d2d35 100644
--- a/perly.act
+++ b/perly.act
@@ -1,10 +1,10 @@
 case 2:
-#line 137 "perly.y"
+#line 142 "perly.y"
     { (yyval.ival) = (ps[(1) - (2)].val.ival); newPROG(block_end((ps[(1) - (2)].val.ival),(ps[(2) - (2)].val.opval))); ;}
     break;
 
   case 3:
-#line 142 "perly.y"
+#line 147 "perly.y"
     { if (PL_parser->copline > (line_t)IVAL((ps[(1) - (4)].val.i_tkval)))
 			      PL_parser->copline = (line_t)IVAL((ps[(1) - (4)].val.i_tkval));
 			  (yyval.opval) = block_end((ps[(2) - (4)].val.ival), (ps[(3) - (4)].val.opval));
@@ -14,24 +14,24 @@ case 2:
     break;
 
   case 4:
-#line 151 "perly.y"
+#line 156 "perly.y"
     { (yyval.ival) = block_start(TRUE); ;}
     break;
 
   case 5:
-#line 155 "perly.y"
+#line 160 "perly.y"
     { (yyval.ival) = (I32) allocmy("$_"); ;}
     break;
 
   case 6:
-#line 159 "perly.y"
+#line 164 "perly.y"
     {
 		    PL_parser->expect = XSTATE; (yyval.ival) = block_start(TRUE);
 		;}
     break;
 
   case 7:
-#line 166 "perly.y"
+#line 171 "perly.y"
     { if (PL_parser->copline > (line_t)IVAL((ps[(1) - (4)].val.i_tkval)))
 			      PL_parser->copline = (line_t)IVAL((ps[(1) - (4)].val.i_tkval));
 			  (yyval.opval) = block_end((ps[(2) - (4)].val.ival), (ps[(3) - (4)].val.opval));
@@ -41,17 +41,17 @@ case 2:
     break;
 
   case 8:
-#line 175 "perly.y"
+#line 180 "perly.y"
     { (yyval.ival) = block_start(FALSE); ;}
     break;
 
   case 9:
-#line 180 "perly.y"
+#line 185 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 10:
-#line 182 "perly.y"
+#line 187 "perly.y"
     {
 			(yyval.opval) = IF_MAD(
 				append_list(OP_LINESEQ,
@@ -61,7 +61,7 @@ case 2:
     break;
 
   case 11:
-#line 189 "perly.y"
+#line 194 "perly.y"
     {   (yyval.opval) = append_list(OP_LINESEQ,
 				(LISTOP*)(ps[(1) - (2)].val.opval), (LISTOP*)(ps[(2) - (2)].val.opval));
 			    PL_pad_reset_pending = TRUE;
@@ -71,23 +71,23 @@ case 2:
     break;
 
   case 12:
-#line 199 "perly.y"
+#line 204 "perly.y"
     { (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (2)].val.p_tkval)), (ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.p_tkval),((LISTOP*)(yyval.opval))->op_first,'L'); ;}
     break;
 
   case 14:
-#line 203 "perly.y"
+#line 208 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 15:
-#line 205 "perly.y"
+#line 210 "perly.y"
     { (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (2)].val.p_tkval)), (ps[(2) - (2)].val.opval)); ;}
     break;
 
   case 16:
-#line 207 "perly.y"
+#line 212 "perly.y"
     {
 			  if (PVAL((ps[(1) - (2)].val.p_tkval))) {
 			      (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (2)].val.p_tkval)), newOP(OP_NULL, 0));
@@ -107,7 +107,7 @@ case 2:
     break;
 
   case 17:
-#line 224 "perly.y"
+#line 229 "perly.y"
     {
 			  (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (3)].val.p_tkval)), (ps[(2) - (3)].val.opval));
 			  PL_parser->expect = XSTATE;
@@ -126,45 +126,45 @@ case 2:
     break;
 
   case 18:
-#line 243 "perly.y"
+#line 248 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 19:
-#line 245 "perly.y"
+#line 250 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 20:
-#line 247 "perly.y"
+#line 252 "perly.y"
     { (yyval.opval) = newLOGOP(OP_AND, 0, (ps[(3) - (3)].val.opval), (ps[(1) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'i');
 			;}
     break;
 
   case 21:
-#line 251 "perly.y"
+#line 256 "perly.y"
     { (yyval.opval) = newLOGOP(OP_OR, 0, (ps[(3) - (3)].val.opval), (ps[(1) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'i');
 			;}
     break;
 
   case 22:
-#line 255 "perly.y"
+#line 260 "perly.y"
     { (yyval.opval) = newLOOPOP(OPf_PARENS, 1, scalar((ps[(3) - (3)].val.opval)), (ps[(1) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'w');
 			;}
     break;
 
   case 23:
-#line 259 "perly.y"
+#line 264 "perly.y"
     { (yyval.opval) = newLOOPOP(OPf_PARENS, 1, (ps[(3) - (3)].val.opval), (ps[(1) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'w');
 			;}
     break;
 
   case 24:
-#line 263 "perly.y"
+#line 268 "perly.y"
     { (yyval.opval) = newFOROP(0, NULL, (line_t)IVAL((ps[(2) - (3)].val.i_tkval)),
 					(OP*)NULL, (ps[(3) - (3)].val.opval), (ps[(1) - (3)].val.opval), (OP*)NULL);
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),((LISTOP*)(yyval.opval))->op_first->op_sibling,'w');
@@ -172,19 +172,19 @@ case 2:
     break;
 
   case 25:
-#line 271 "perly.y"
+#line 276 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 26:
-#line 273 "perly.y"
+#line 278 "perly.y"
     { ((ps[(2) - (2)].val.opval))->op_flags |= OPf_PARENS; (yyval.opval) = scope((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 27:
-#line 277 "perly.y"
+#line 282 "perly.y"
     { PL_parser->copline = (line_t)IVAL((ps[(1) - (6)].val.i_tkval));
 			    (yyval.opval) = newCONDOP(0, newSTATEOP(OPf_SPECIAL,NULL,(ps[(3) - (6)].val.opval)), scope((ps[(5) - (6)].val.opval)), (ps[(6) - (6)].val.opval));
 			    PL_hints |= HINT_BLOCK_SCOPE;
@@ -195,7 +195,7 @@ case 2:
     break;
 
   case 28:
-#line 288 "perly.y"
+#line 293 "perly.y"
     { PL_parser->copline = (line_t)IVAL((ps[(1) - (7)].val.i_tkval));
 			    (yyval.opval) = block_end((ps[(3) - (7)].val.ival),
 				   newCONDOP(0, (ps[(4) - (7)].val.opval), scope((ps[(6) - (7)].val.opval)), (ps[(7) - (7)].val.opval)));
@@ -206,7 +206,7 @@ case 2:
     break;
 
   case 29:
-#line 296 "perly.y"
+#line 301 "perly.y"
     { PL_parser->copline = (line_t)IVAL((ps[(1) - (7)].val.i_tkval));
 			    (yyval.opval) = block_end((ps[(3) - (7)].val.ival),
 				   newCONDOP(0, (ps[(4) - (7)].val.opval), scope((ps[(6) - (7)].val.opval)), (ps[(7) - (7)].val.opval)));
@@ -217,36 +217,50 @@ case 2:
     break;
 
   case 30:
-#line 307 "perly.y"
+#line 312 "perly.y"
     { (yyval.opval) = block_end((ps[(3) - (6)].val.ival),
 		newWHENOP((ps[(4) - (6)].val.opval), scope((ps[(6) - (6)].val.opval)))); ;}
     break;
 
   case 31:
-#line 310 "perly.y"
+#line 315 "perly.y"
     { (yyval.opval) = newWHENOP(0, scope((ps[(2) - (2)].val.opval))); ;}
     break;
 
   case 32:
-#line 315 "perly.y"
+#line 320 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 33:
-#line 317 "perly.y"
+#line 322 "perly.y"
     { (yyval.opval) = scope((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 34:
-#line 324 "perly.y"
+#line 329 "perly.y"
     { OP *innerop;
 			  PL_parser->copline = (line_t)(ps[(2) - (9)].val.i_tkval);
-			    (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+#ifdef TRY_OPLINES
+			  if (PVAL((ps[(1) - (9)].val.p_tkval))) {
+			      (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+				       newSTATEOP(0, PVAL((ps[(1) - (9)].val.p_tkval)),
+						  innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						            IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival))));
+			  } 
+			  else {
+			      (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+				        innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					          IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival)));
+			  }
+#else
+			  (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
 				   newSTATEOP(0, PVAL((ps[(1) - (9)].val.p_tkval)),
-				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
-						IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival))));
+				       innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival))));
+#endif
 			  TOKEN_GETMAD((ps[(1) - (9)].val.p_tkval),innerop,'L');
 			  TOKEN_GETMAD((ps[(2) - (9)].val.i_tkval),innerop,'W');
 			  TOKEN_GETMAD((ps[(3) - (9)].val.i_tkval),innerop,'(');
@@ -255,13 +269,26 @@ case 2:
     break;
 
   case 35:
-#line 337 "perly.y"
+#line 356 "perly.y"
     { OP *innerop;
 			  PL_parser->copline = (line_t)(ps[(2) - (9)].val.i_tkval);
-			    (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+#ifdef TRY_OPLINES
+			  if (PVAL((ps[(1) - (9)].val.p_tkval))) {
+				(yyval.opval) = block_end((ps[(4) - (9)].val.ival),
 				   newSTATEOP(0, PVAL((ps[(1) - (9)].val.p_tkval)),
 				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
 						IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival))));
+			  } else {
+				(yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+				        innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival)));
+			  }
+#else
+			  (yyval.opval) = block_end((ps[(4) - (9)].val.ival),
+				   newSTATEOP(0, PVAL((ps[(1) - (9)].val.p_tkval)),
+				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						IVAL((ps[(2) - (9)].val.i_tkval)), (ps[(5) - (9)].val.opval), (ps[(8) - (9)].val.opval), (ps[(9) - (9)].val.opval), (ps[(7) - (9)].val.ival))));
+#endif
 			  TOKEN_GETMAD((ps[(1) - (9)].val.p_tkval),innerop,'L');
 			  TOKEN_GETMAD((ps[(2) - (9)].val.i_tkval),innerop,'W');
 			  TOKEN_GETMAD((ps[(3) - (9)].val.i_tkval),innerop,'(');
@@ -270,7 +297,7 @@ case 2:
     break;
 
   case 36:
-#line 349 "perly.y"
+#line 381 "perly.y"
     { OP *innerop;
 			  (yyval.opval) = block_end((ps[(4) - (10)].val.ival),
 			     innerop = newFOROP(0, PVAL((ps[(1) - (10)].val.p_tkval)), (line_t)IVAL((ps[(2) - (10)].val.i_tkval)),
@@ -284,7 +311,7 @@ case 2:
     break;
 
   case 37:
-#line 360 "perly.y"
+#line 392 "perly.y"
     { OP *innerop;
 			  (yyval.opval) = block_end((ps[(5) - (9)].val.ival),
 			     innerop = newFOROP(0, PVAL((ps[(1) - (9)].val.p_tkval)), (line_t)IVAL((ps[(2) - (9)].val.i_tkval)),
@@ -297,11 +324,11 @@ case 2:
     break;
 
   case 38:
-#line 370 "perly.y"
+#line 402 "perly.y"
     { OP *innerop;
 			  (yyval.opval) = block_end((ps[(4) - (8)].val.ival),
 			     innerop = newFOROP(0, PVAL((ps[(1) - (8)].val.p_tkval)), (line_t)IVAL((ps[(2) - (8)].val.i_tkval)),
-						    (OP*)NULL, (ps[(5) - (8)].val.opval), (ps[(7) - (8)].val.opval), (ps[(8) - (8)].val.opval)));
+						(OP*)NULL, (ps[(5) - (8)].val.opval), (ps[(7) - (8)].val.opval), (ps[(8) - (8)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (8)].val.p_tkval),((LISTOP*)innerop)->op_first,'L');
 			  TOKEN_GETMAD((ps[(2) - (8)].val.i_tkval),((LISTOP*)innerop)->op_first->op_sibling,'W');
 			  TOKEN_GETMAD((ps[(3) - (8)].val.i_tkval),((LISTOP*)innerop)->op_first->op_sibling,'(');
@@ -310,13 +337,26 @@ case 2:
     break;
 
   case 39:
-#line 382 "perly.y"
+#line 414 "perly.y"
     { OP *forop;
 			  PL_parser->copline = (line_t)IVAL((ps[(2) - (12)].val.i_tkval));
+#ifdef TRY_OPLINES
+			  if (PVAL((ps[(1) - (12)].val.p_tkval))) {
+			      forop = newSTATEOP(0, PVAL((ps[(1) - (12)].val.p_tkval)),
+				          newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						     IVAL((ps[(2) - (12)].val.i_tkval)), scalar((ps[(7) - (12)].val.opval)),
+						     (ps[(12) - (12)].val.opval), (ps[(10) - (12)].val.opval), (ps[(9) - (12)].val.ival)));
+			  } else {
+			      forop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL((ps[(2) - (12)].val.i_tkval)), scalar((ps[(7) - (12)].val.opval)),
+						 (ps[(12) - (12)].val.opval), (ps[(10) - (12)].val.opval), (ps[(9) - (12)].val.ival));
+			  }
+#else
 			  forop = newSTATEOP(0, PVAL((ps[(1) - (12)].val.p_tkval)),
-					    newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
-						IVAL((ps[(2) - (12)].val.i_tkval)), scalar((ps[(7) - (12)].val.opval)),
-						(ps[(12) - (12)].val.opval), (ps[(10) - (12)].val.opval), (ps[(9) - (12)].val.ival)));
+				      newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL((ps[(2) - (12)].val.i_tkval)), scalar((ps[(7) - (12)].val.opval)),
+						 (ps[(12) - (12)].val.opval), (ps[(10) - (12)].val.opval), (ps[(9) - (12)].val.ival)));
+#endif
 #ifdef MAD
 			  forop = newUNOP(OP_NULL, 0, append_elem(OP_LINESEQ,
 				newSTATEOP(0,
@@ -337,69 +377,94 @@ case 2:
 					forop);
 			  }
 
-
 #endif
 			  (yyval.opval) = block_end((ps[(4) - (12)].val.ival), forop); ;}
     break;
 
   case 40:
-#line 412 "perly.y"
-    { (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (3)].val.p_tkval)),
+#line 456 "perly.y"
+    { 
+#ifdef TRY_OPLINES
+			   if (PVAL((ps[(1) - (3)].val.p_tkval))) {
+				(yyval.opval) = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					    NOLINE, (OP*)NULL, (ps[(2) - (3)].val.opval), (ps[(3) - (3)].val.opval), 0);
+			   } else {
+				(yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (3)].val.p_tkval)),
 				 newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
 					    NOLINE, (OP*)NULL, (ps[(2) - (3)].val.opval), (ps[(3) - (3)].val.opval), 0));
+			   }
+#else
+			   (yyval.opval) = newSTATEOP(0, PVAL((ps[(1) - (3)].val.p_tkval)),
+				 newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					    NOLINE, (OP*)NULL, (ps[(2) - (3)].val.opval), (ps[(3) - (3)].val.opval), 0));
+#endif
 			  TOKEN_GETMAD((ps[(1) - (3)].val.p_tkval),((LISTOP*)(yyval.opval))->op_first,'L'); ;}
     break;
 
   case 41:
-#line 420 "perly.y"
+#line 476 "perly.y"
     { PL_parser->copline = (line_t) (ps[(2) - (8)].val.i_tkval);
+#ifdef TRY_OPLINES
+			  if (PVAL((ps[(1) - (8)].val.p_tkval))) {
 			    (yyval.opval) = block_end((ps[(4) - (8)].val.ival),
 				newSTATEOP(0, PVAL((ps[(1) - (8)].val.p_tkval)),
 				    newGIVENOP((ps[(6) - (8)].val.opval), scope((ps[(8) - (8)].val.opval)),
-					(PADOFFSET) (ps[(5) - (8)].val.ival)) )); ;}
+					(PADOFFSET) (ps[(5) - (8)].val.ival)) ));
+			   } else {
+			    (yyval.opval) = block_end((ps[(4) - (8)].val.ival),
+					newGIVENOP((ps[(6) - (8)].val.opval), scope((ps[(8) - (8)].val.opval)),
+					(PADOFFSET) (ps[(5) - (8)].val.ival)));
+			   }
+#else
+			    (yyval.opval) = block_end((ps[(4) - (8)].val.ival),
+				newSTATEOP(0, PVAL((ps[(1) - (8)].val.p_tkval)),
+				    newGIVENOP((ps[(6) - (8)].val.opval), scope((ps[(8) - (8)].val.opval)),
+					(PADOFFSET) (ps[(5) - (8)].val.ival)) ));
+#endif
+			;}
     break;
 
   case 42:
-#line 429 "perly.y"
+#line 499 "perly.y"
     { (yyval.ival) = (PL_min_intro_pending &&
 			    PL_max_intro_pending >=  PL_min_intro_pending);
 			  intro_my(); ;}
     break;
 
   case 43:
-#line 435 "perly.y"
+#line 505 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 45:
-#line 441 "perly.y"
+#line 511 "perly.y"
     { YYSTYPE tmplval;
 			  (void)scan_num("1", &tmplval);
 			  (yyval.opval) = tmplval.opval; ;}
     break;
 
   case 47:
-#line 449 "perly.y"
+#line 519 "perly.y"
     { (yyval.opval) = invert(scalar((ps[(1) - (1)].val.opval))); ;}
     break;
 
   case 48:
-#line 454 "perly.y"
+#line 524 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); intro_my(); ;}
     break;
 
   case 49:
-#line 458 "perly.y"
+#line 528 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); intro_my(); ;}
     break;
 
   case 50:
-#line 462 "perly.y"
+#line 532 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); intro_my(); ;}
     break;
 
   case 51:
-#line 467 "perly.y"
+#line 537 "perly.y"
     {
 #ifdef MAD
 			  YYSTYPE tmplval;
@@ -412,44 +477,44 @@ case 2:
     break;
 
   case 53:
-#line 481 "perly.y"
+#line 551 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 54:
-#line 483 "perly.y"
+#line 553 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 55:
-#line 485 "perly.y"
+#line 555 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 56:
-#line 487 "perly.y"
+#line 557 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 57:
-#line 489 "perly.y"
+#line 559 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 58:
-#line 494 "perly.y"
+#line 564 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 59:
-#line 498 "perly.y"
+#line 568 "perly.y"
     { (yyval.opval) = newOP(OP_NULL,0);
 			  TOKEN_GETMAD((ps[(1) - (1)].val.i_tkval),(yyval.opval),'p');
 			;}
     break;
 
   case 60:
-#line 504 "perly.y"
+#line 574 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 #ifdef MAD
 			  (yyval.opval) = newFORM((ps[(2) - (4)].val.ival), (ps[(3) - (4)].val.opval), (ps[(4) - (4)].val.opval));
@@ -464,17 +529,17 @@ case 2:
     break;
 
   case 61:
-#line 517 "perly.y"
+#line 587 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 62:
-#line 518 "perly.y"
+#line 588 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 63:
-#line 523 "perly.y"
+#line 593 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 #ifdef MAD
 			  (yyval.opval) = newMYSUB((ps[(2) - (6)].val.ival), (ps[(3) - (6)].val.opval), (ps[(4) - (6)].val.opval), (ps[(5) - (6)].val.opval), (ps[(6) - (6)].val.opval));
@@ -487,7 +552,7 @@ case 2:
     break;
 
   case 64:
-#line 536 "perly.y"
+#line 606 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 #ifdef MAD
 			  {
@@ -510,25 +575,25 @@ case 2:
     break;
 
   case 65:
-#line 558 "perly.y"
+#line 628 "perly.y"
     { (yyval.ival) = start_subparse(FALSE, 0);
 			    SAVEFREESV(PL_compcv); ;}
     break;
 
   case 66:
-#line 564 "perly.y"
+#line 634 "perly.y"
     { (yyval.ival) = start_subparse(FALSE, CVf_ANON);
 			    SAVEFREESV(PL_compcv); ;}
     break;
 
   case 67:
-#line 569 "perly.y"
+#line 639 "perly.y"
     { (yyval.ival) = start_subparse(TRUE, 0);
 			    SAVEFREESV(PL_compcv); ;}
     break;
 
   case 68:
-#line 574 "perly.y"
+#line 644 "perly.y"
     { const char *const name = SvPV_nolen_const(((SVOP*)(ps[(1) - (1)].val.opval))->op_sv);
 			  if (strEQ(name, "BEGIN") || strEQ(name, "END")
 			      || strEQ(name, "INIT") || strEQ(name, "CHECK")
@@ -538,24 +603,24 @@ case 2:
     break;
 
   case 69:
-#line 584 "perly.y"
+#line 654 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 71:
-#line 590 "perly.y"
+#line 660 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 72:
-#line 592 "perly.y"
+#line 662 "perly.y"
     { (yyval.opval) = (ps[(2) - (2)].val.opval);
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),':');
 			;}
     break;
 
   case 73:
-#line 596 "perly.y"
+#line 666 "perly.y"
     { (yyval.opval) = IF_MAD(
 				    newOP(OP_NULL, 0),
 				    (OP*)NULL
@@ -565,14 +630,14 @@ case 2:
     break;
 
   case 74:
-#line 606 "perly.y"
+#line 676 "perly.y"
     { (yyval.opval) = (ps[(2) - (2)].val.opval);
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),':');
 			;}
     break;
 
   case 75:
-#line 610 "perly.y"
+#line 680 "perly.y"
     { (yyval.opval) = IF_MAD(
 				    newOP(OP_NULL, 0),
 				    (OP*)NULL
@@ -582,12 +647,12 @@ case 2:
     break;
 
   case 76:
-#line 619 "perly.y"
+#line 689 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 77:
-#line 620 "perly.y"
+#line 690 "perly.y"
     { (yyval.opval) = IF_MAD(
 				    newOP(OP_NULL,0),
 				    (OP*)NULL
@@ -598,7 +663,7 @@ case 2:
     break;
 
   case 78:
-#line 630 "perly.y"
+#line 700 "perly.y"
     {
 #ifdef MAD
 			  (yyval.opval) = package((ps[(2) - (3)].val.opval));
@@ -612,12 +677,12 @@ case 2:
     break;
 
   case 79:
-#line 643 "perly.y"
+#line 713 "perly.y"
     { CvSPECIAL_on(PL_compcv); /* It's a BEGIN {} */ ;}
     break;
 
   case 80:
-#line 645 "perly.y"
+#line 715 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 #ifdef MAD
 			  (yyval.opval) = utilize(IVAL((ps[(1) - (7)].val.i_tkval)), (ps[(2) - (7)].val.ival), (ps[(4) - (7)].val.opval), (ps[(5) - (7)].val.opval), (ps[(6) - (7)].val.opval));
@@ -634,28 +699,28 @@ case 2:
     break;
 
   case 81:
-#line 662 "perly.y"
+#line 732 "perly.y"
     { (yyval.opval) = newLOGOP(OP_AND, 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 82:
-#line 666 "perly.y"
+#line 736 "perly.y"
     { (yyval.opval) = newLOGOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 83:
-#line 670 "perly.y"
+#line 740 "perly.y"
     { (yyval.opval) = newLOGOP(OP_DOR, 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 85:
-#line 678 "perly.y"
+#line 748 "perly.y"
     {
 #ifdef MAD
 			  OP* op = newNULLLIST();
@@ -668,7 +733,7 @@ case 2:
     break;
 
   case 86:
-#line 688 "perly.y"
+#line 758 "perly.y"
     { 
 			  OP* term = (ps[(3) - (3)].val.opval);
 			  DO_MAD(
@@ -680,7 +745,7 @@ case 2:
     break;
 
   case 88:
-#line 701 "perly.y"
+#line 771 "perly.y"
     { (yyval.opval) = convert(IVAL((ps[(1) - (3)].val.i_tkval)), OPf_STACKED,
 				prepend_elem(OP_LIST, newGVREF(IVAL((ps[(1) - (3)].val.i_tkval)),(ps[(2) - (3)].val.opval)), (ps[(3) - (3)].val.opval)) );
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'o');
@@ -688,7 +753,7 @@ case 2:
     break;
 
   case 89:
-#line 706 "perly.y"
+#line 776 "perly.y"
     { (yyval.opval) = convert(IVAL((ps[(1) - (5)].val.i_tkval)), OPf_STACKED,
 				prepend_elem(OP_LIST, newGVREF(IVAL((ps[(1) - (5)].val.i_tkval)),(ps[(3) - (5)].val.opval)), (ps[(4) - (5)].val.opval)) );
 			  TOKEN_GETMAD((ps[(1) - (5)].val.i_tkval),(yyval.opval),'o');
@@ -698,7 +763,7 @@ case 2:
     break;
 
   case 90:
-#line 713 "perly.y"
+#line 783 "perly.y"
     { (yyval.opval) = convert(OP_ENTERSUB, OPf_STACKED,
 				append_elem(OP_LIST,
 				    prepend_elem(OP_LIST, scalar((ps[(1) - (6)].val.opval)), (ps[(5) - (6)].val.opval)),
@@ -710,7 +775,7 @@ case 2:
     break;
 
   case 91:
-#line 722 "perly.y"
+#line 792 "perly.y"
     { (yyval.opval) = convert(OP_ENTERSUB, OPf_STACKED,
 				append_elem(OP_LIST, scalar((ps[(1) - (3)].val.opval)),
 				    newUNOP(OP_METHOD, 0, (ps[(3) - (3)].val.opval))));
@@ -719,7 +784,7 @@ case 2:
     break;
 
   case 92:
-#line 728 "perly.y"
+#line 798 "perly.y"
     { (yyval.opval) = convert(OP_ENTERSUB, OPf_STACKED,
 				append_elem(OP_LIST,
 				    prepend_elem(OP_LIST, (ps[(2) - (3)].val.opval), (ps[(3) - (3)].val.opval)),
@@ -728,7 +793,7 @@ case 2:
     break;
 
   case 93:
-#line 734 "perly.y"
+#line 804 "perly.y"
     { (yyval.opval) = convert(OP_ENTERSUB, OPf_STACKED,
 				append_elem(OP_LIST,
 				    prepend_elem(OP_LIST, (ps[(2) - (5)].val.opval), (ps[(4) - (5)].val.opval)),
@@ -739,14 +804,14 @@ case 2:
     break;
 
   case 94:
-#line 742 "perly.y"
+#line 812 "perly.y"
     { (yyval.opval) = convert(IVAL((ps[(1) - (2)].val.i_tkval)), 0, (ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 95:
-#line 746 "perly.y"
+#line 816 "perly.y"
     { (yyval.opval) = convert(IVAL((ps[(1) - (4)].val.i_tkval)), 0, (ps[(3) - (4)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (4)].val.i_tkval),(yyval.opval),'o');
 			  TOKEN_GETMAD((ps[(2) - (4)].val.i_tkval),(yyval.opval),'(');
@@ -755,13 +820,13 @@ case 2:
     break;
 
   case 96:
-#line 752 "perly.y"
+#line 822 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 			  (yyval.opval) = newANONATTRSUB((ps[(2) - (3)].val.ival), 0, (OP*)NULL, (ps[(3) - (3)].val.opval)); ;}
     break;
 
   case 97:
-#line 755 "perly.y"
+#line 825 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				 append_elem(OP_LIST,
 				   prepend_elem(OP_LIST, (ps[(4) - (5)].val.opval), (ps[(5) - (5)].val.opval)), (ps[(1) - (5)].val.opval)));
@@ -769,7 +834,7 @@ case 2:
     break;
 
   case 100:
-#line 770 "perly.y"
+#line 840 "perly.y"
     { (yyval.opval) = newBINOP(OP_GELEM, 0, (ps[(1) - (5)].val.opval), scalar((ps[(3) - (5)].val.opval)));
 			    PL_parser->expect = XOPERATOR;
 			  TOKEN_GETMAD((ps[(2) - (5)].val.i_tkval),(yyval.opval),'{');
@@ -779,7 +844,7 @@ case 2:
     break;
 
   case 101:
-#line 777 "perly.y"
+#line 847 "perly.y"
     { (yyval.opval) = newBINOP(OP_AELEM, 0, oopsAV((ps[(1) - (4)].val.opval)), scalar((ps[(3) - (4)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (4)].val.i_tkval),(yyval.opval),'[');
 			  TOKEN_GETMAD((ps[(4) - (4)].val.i_tkval),(yyval.opval),']');
@@ -787,7 +852,7 @@ case 2:
     break;
 
   case 102:
-#line 782 "perly.y"
+#line 852 "perly.y"
     { (yyval.opval) = newBINOP(OP_AELEM, 0,
 					ref(newAVREF((ps[(1) - (5)].val.opval)),OP_RV2AV),
 					scalar((ps[(4) - (5)].val.opval)));
@@ -798,7 +863,7 @@ case 2:
     break;
 
   case 103:
-#line 790 "perly.y"
+#line 860 "perly.y"
     { (yyval.opval) = newBINOP(OP_AELEM, 0,
 					ref(newAVREF((ps[(1) - (4)].val.opval)),OP_RV2AV),
 					scalar((ps[(3) - (4)].val.opval)));
@@ -808,7 +873,7 @@ case 2:
     break;
 
   case 104:
-#line 797 "perly.y"
+#line 867 "perly.y"
     { (yyval.opval) = newBINOP(OP_HELEM, 0, oopsHV((ps[(1) - (5)].val.opval)), jmaybe((ps[(3) - (5)].val.opval)));
 			    PL_parser->expect = XOPERATOR;
 			  TOKEN_GETMAD((ps[(2) - (5)].val.i_tkval),(yyval.opval),'{');
@@ -818,7 +883,7 @@ case 2:
     break;
 
   case 105:
-#line 804 "perly.y"
+#line 874 "perly.y"
     { (yyval.opval) = newBINOP(OP_HELEM, 0,
 					ref(newHVREF((ps[(1) - (6)].val.opval)),OP_RV2HV),
 					jmaybe((ps[(4) - (6)].val.opval)));
@@ -831,7 +896,7 @@ case 2:
     break;
 
   case 106:
-#line 814 "perly.y"
+#line 884 "perly.y"
     { (yyval.opval) = newBINOP(OP_HELEM, 0,
 					ref(newHVREF((ps[(1) - (5)].val.opval)),OP_RV2HV),
 					jmaybe((ps[(3) - (5)].val.opval)));
@@ -843,7 +908,7 @@ case 2:
     break;
 
   case 107:
-#line 823 "perly.y"
+#line 893 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				   newCVREF(0, scalar((ps[(1) - (4)].val.opval))));
 			  TOKEN_GETMAD((ps[(2) - (4)].val.i_tkval),(yyval.opval),'a');
@@ -853,7 +918,7 @@ case 2:
     break;
 
   case 108:
-#line 830 "perly.y"
+#line 900 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				   append_elem(OP_LIST, (ps[(4) - (5)].val.opval),
 				       newCVREF(0, scalar((ps[(1) - (5)].val.opval)))));
@@ -864,7 +929,7 @@ case 2:
     break;
 
   case 109:
-#line 839 "perly.y"
+#line 909 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				   append_elem(OP_LIST, (ps[(3) - (4)].val.opval),
 					       newCVREF(0, scalar((ps[(1) - (4)].val.opval)))));
@@ -874,7 +939,7 @@ case 2:
     break;
 
   case 110:
-#line 846 "perly.y"
+#line 916 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				   newCVREF(0, scalar((ps[(1) - (3)].val.opval))));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'(');
@@ -883,7 +948,7 @@ case 2:
     break;
 
   case 111:
-#line 852 "perly.y"
+#line 922 "perly.y"
     { (yyval.opval) = newSLICEOP(0, (ps[(5) - (6)].val.opval), (ps[(2) - (6)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (6)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(3) - (6)].val.i_tkval),(yyval.opval),')');
@@ -893,7 +958,7 @@ case 2:
     break;
 
   case 112:
-#line 859 "perly.y"
+#line 929 "perly.y"
     { (yyval.opval) = newSLICEOP(0, (ps[(4) - (5)].val.opval), (OP*)NULL);
 			  TOKEN_GETMAD((ps[(1) - (5)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(2) - (5)].val.i_tkval),(yyval.opval),')');
@@ -903,21 +968,21 @@ case 2:
     break;
 
   case 113:
-#line 869 "perly.y"
+#line 939 "perly.y"
     { (yyval.opval) = newASSIGNOP(OPf_STACKED, (ps[(1) - (3)].val.opval), IVAL((ps[(2) - (3)].val.i_tkval)), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 114:
-#line 873 "perly.y"
+#line 943 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 115:
-#line 877 "perly.y"
+#line 947 "perly.y"
     {   if (IVAL((ps[(2) - (3)].val.i_tkval)) != OP_REPEAT)
 				scalar((ps[(1) - (3)].val.opval));
 			    (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, (ps[(1) - (3)].val.opval), scalar((ps[(3) - (3)].val.opval)));
@@ -926,49 +991,49 @@ case 2:
     break;
 
   case 116:
-#line 883 "perly.y"
+#line 953 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 117:
-#line 887 "perly.y"
+#line 957 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 118:
-#line 891 "perly.y"
+#line 961 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 119:
-#line 895 "perly.y"
+#line 965 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 120:
-#line 899 "perly.y"
+#line 969 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 121:
-#line 903 "perly.y"
+#line 973 "perly.y"
     { (yyval.opval) = newBINOP(IVAL((ps[(2) - (3)].val.i_tkval)), 0, scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 122:
-#line 907 "perly.y"
+#line 977 "perly.y"
     {
 			  (yyval.opval) = newRANGE(IVAL((ps[(2) - (3)].val.i_tkval)), scalar((ps[(1) - (3)].val.opval)), scalar((ps[(3) - (3)].val.opval)));
 			  DO_MAD({
@@ -983,28 +1048,28 @@ case 2:
     break;
 
   case 123:
-#line 919 "perly.y"
+#line 989 "perly.y"
     { (yyval.opval) = newLOGOP(OP_AND, 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 124:
-#line 923 "perly.y"
+#line 993 "perly.y"
     { (yyval.opval) = newLOGOP(OP_OR, 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 125:
-#line 927 "perly.y"
+#line 997 "perly.y"
     { (yyval.opval) = newLOGOP(OP_DOR, 0, (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 126:
-#line 931 "perly.y"
+#line 1001 "perly.y"
     { (yyval.opval) = bind_match(IVAL((ps[(2) - (3)].val.i_tkval)), (ps[(1) - (3)].val.opval), (ps[(3) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),
 				((yyval.opval)->op_type == OP_NOT
@@ -1014,14 +1079,14 @@ case 2:
     break;
 
   case 127:
-#line 941 "perly.y"
+#line 1011 "perly.y"
     { (yyval.opval) = newUNOP(OP_NEGATE, 0, scalar((ps[(2) - (2)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 128:
-#line 945 "perly.y"
+#line 1015 "perly.y"
     { (yyval.opval) = IF_MAD(
 				    newUNOP(OP_NULL, 0, (ps[(2) - (2)].val.opval)),
 				    (ps[(2) - (2)].val.opval)
@@ -1031,21 +1096,21 @@ case 2:
     break;
 
   case 129:
-#line 952 "perly.y"
+#line 1022 "perly.y"
     { (yyval.opval) = newUNOP(OP_NOT, 0, scalar((ps[(2) - (2)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 130:
-#line 956 "perly.y"
+#line 1026 "perly.y"
     { (yyval.opval) = newUNOP(OP_COMPLEMENT, 0, scalar((ps[(2) - (2)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 131:
-#line 960 "perly.y"
+#line 1030 "perly.y"
     { (yyval.opval) = newUNOP(OP_POSTINC, 0,
 					mod(scalar((ps[(1) - (2)].val.opval)), OP_POSTINC));
 			  TOKEN_GETMAD((ps[(2) - (2)].val.i_tkval),(yyval.opval),'o');
@@ -1053,7 +1118,7 @@ case 2:
     break;
 
   case 132:
-#line 965 "perly.y"
+#line 1035 "perly.y"
     { (yyval.opval) = newUNOP(OP_POSTDEC, 0,
 					mod(scalar((ps[(1) - (2)].val.opval)), OP_POSTDEC));
 			  TOKEN_GETMAD((ps[(2) - (2)].val.i_tkval),(yyval.opval),'o');
@@ -1061,7 +1126,7 @@ case 2:
     break;
 
   case 133:
-#line 970 "perly.y"
+#line 1040 "perly.y"
     { (yyval.opval) = newUNOP(OP_PREINC, 0,
 					mod(scalar((ps[(2) - (2)].val.opval)), OP_PREINC));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
@@ -1069,7 +1134,7 @@ case 2:
     break;
 
   case 134:
-#line 975 "perly.y"
+#line 1045 "perly.y"
     { (yyval.opval) = newUNOP(OP_PREDEC, 0,
 					mod(scalar((ps[(2) - (2)].val.opval)), OP_PREDEC));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
@@ -1077,7 +1142,7 @@ case 2:
     break;
 
   case 135:
-#line 984 "perly.y"
+#line 1054 "perly.y"
     { (yyval.opval) = newANONLIST((ps[(2) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'[');
 			  TOKEN_GETMAD((ps[(3) - (3)].val.i_tkval),(yyval.opval),']');
@@ -1085,7 +1150,7 @@ case 2:
     break;
 
   case 136:
-#line 989 "perly.y"
+#line 1059 "perly.y"
     { (yyval.opval) = newANONLIST((OP*)NULL);
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'[');
 			  TOKEN_GETMAD((ps[(2) - (2)].val.i_tkval),(yyval.opval),']');
@@ -1093,7 +1158,7 @@ case 2:
     break;
 
   case 137:
-#line 994 "perly.y"
+#line 1064 "perly.y"
     { (yyval.opval) = newANONHASH((ps[(2) - (4)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (4)].val.i_tkval),(yyval.opval),'{');
 			  TOKEN_GETMAD((ps[(3) - (4)].val.i_tkval),(yyval.opval),';');
@@ -1102,7 +1167,7 @@ case 2:
     break;
 
   case 138:
-#line 1000 "perly.y"
+#line 1070 "perly.y"
     { (yyval.opval) = newANONHASH((OP*)NULL);
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'{');
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),';');
@@ -1111,7 +1176,7 @@ case 2:
     break;
 
   case 139:
-#line 1006 "perly.y"
+#line 1076 "perly.y"
     { SvREFCNT_inc_simple_void(PL_compcv);
 			  (yyval.opval) = newANONATTRSUB((ps[(2) - (5)].val.ival), (ps[(3) - (5)].val.opval), (ps[(4) - (5)].val.opval), (ps[(5) - (5)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (5)].val.i_tkval),(yyval.opval),'o');
@@ -1121,21 +1186,21 @@ case 2:
     break;
 
   case 140:
-#line 1017 "perly.y"
+#line 1087 "perly.y"
     { (yyval.opval) = dofile((ps[(2) - (2)].val.opval), IVAL((ps[(1) - (2)].val.i_tkval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 141:
-#line 1021 "perly.y"
+#line 1091 "perly.y"
     { (yyval.opval) = newUNOP(OP_NULL, OPf_SPECIAL, scope((ps[(2) - (2)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'D');
 			;}
     break;
 
   case 142:
-#line 1025 "perly.y"
+#line 1095 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB,
 			    OPf_SPECIAL|OPf_STACKED,
 			    prepend_elem(OP_LIST,
@@ -1150,7 +1215,7 @@ case 2:
     break;
 
   case 143:
-#line 1037 "perly.y"
+#line 1107 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB,
 			    OPf_SPECIAL|OPf_STACKED,
 			    append_elem(OP_LIST,
@@ -1166,7 +1231,7 @@ case 2:
     break;
 
   case 144:
-#line 1050 "perly.y"
+#line 1120 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
 			    prepend_elem(OP_LIST,
 				scalar(newCVREF(0,scalar((ps[(2) - (4)].val.opval)))), (OP*)NULL)); dep();
@@ -1177,7 +1242,7 @@ case 2:
     break;
 
   case 145:
-#line 1058 "perly.y"
+#line 1128 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
 			    prepend_elem(OP_LIST,
 				(ps[(4) - (5)].val.opval),
@@ -1189,7 +1254,7 @@ case 2:
     break;
 
   case 150:
-#line 1074 "perly.y"
+#line 1144 "perly.y"
     { (yyval.opval) = newCONDOP(0, (ps[(1) - (5)].val.opval), (ps[(3) - (5)].val.opval), (ps[(5) - (5)].val.opval));
 			  TOKEN_GETMAD((ps[(2) - (5)].val.i_tkval),(yyval.opval),'?');
 			  TOKEN_GETMAD((ps[(4) - (5)].val.i_tkval),(yyval.opval),':');
@@ -1197,26 +1262,26 @@ case 2:
     break;
 
   case 151:
-#line 1079 "perly.y"
+#line 1149 "perly.y"
     { (yyval.opval) = newUNOP(OP_REFGEN, 0, mod((ps[(2) - (2)].val.opval),OP_REFGEN));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 152:
-#line 1083 "perly.y"
+#line 1153 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 153:
-#line 1085 "perly.y"
+#line 1155 "perly.y"
     { (yyval.opval) = localize((ps[(2) - (2)].val.opval),IVAL((ps[(1) - (2)].val.i_tkval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'k');
 			;}
     break;
 
   case 154:
-#line 1089 "perly.y"
+#line 1159 "perly.y"
     { (yyval.opval) = sawparens(IF_MAD(newUNOP(OP_NULL,0,(ps[(2) - (3)].val.opval)), (ps[(2) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(3) - (3)].val.i_tkval),(yyval.opval),')');
@@ -1224,7 +1289,7 @@ case 2:
     break;
 
   case 155:
-#line 1094 "perly.y"
+#line 1164 "perly.y"
     { (yyval.opval) = sawparens(newNULLLIST());
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(2) - (2)].val.i_tkval),(yyval.opval),')');
@@ -1232,37 +1297,37 @@ case 2:
     break;
 
   case 156:
-#line 1099 "perly.y"
+#line 1169 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 157:
-#line 1101 "perly.y"
+#line 1171 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 158:
-#line 1103 "perly.y"
+#line 1173 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 159:
-#line 1105 "perly.y"
+#line 1175 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 160:
-#line 1107 "perly.y"
+#line 1177 "perly.y"
     { (yyval.opval) = newUNOP(OP_AV2ARYLEN, 0, ref((ps[(1) - (1)].val.opval), OP_AV2ARYLEN));;}
     break;
 
   case 161:
-#line 1109 "perly.y"
+#line 1179 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 162:
-#line 1111 "perly.y"
+#line 1181 "perly.y"
     { (yyval.opval) = prepend_elem(OP_ASLICE,
 				newOP(OP_PUSHMARK, 0),
 				    newLISTOP(OP_ASLICE, 0,
@@ -1274,7 +1339,7 @@ case 2:
     break;
 
   case 163:
-#line 1120 "perly.y"
+#line 1190 "perly.y"
     { (yyval.opval) = prepend_elem(OP_HSLICE,
 				newOP(OP_PUSHMARK, 0),
 				    newLISTOP(OP_HSLICE, 0,
@@ -1288,17 +1353,17 @@ case 2:
     break;
 
   case 164:
-#line 1131 "perly.y"
+#line 1201 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 165:
-#line 1133 "perly.y"
+#line 1203 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, 0, scalar((ps[(1) - (1)].val.opval))); ;}
     break;
 
   case 166:
-#line 1135 "perly.y"
+#line 1205 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED, scalar((ps[(1) - (3)].val.opval)));
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(3) - (3)].val.i_tkval),(yyval.opval),')');
@@ -1306,7 +1371,7 @@ case 2:
     break;
 
   case 167:
-#line 1140 "perly.y"
+#line 1210 "perly.y"
     {
 			  (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				append_elem(OP_LIST, (ps[(3) - (4)].val.opval), scalar((ps[(1) - (4)].val.opval))));
@@ -1322,7 +1387,7 @@ case 2:
     break;
 
   case 168:
-#line 1153 "perly.y"
+#line 1223 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 			    append_elem(OP_LIST, (ps[(3) - (3)].val.opval), scalar((ps[(2) - (3)].val.opval))));
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'o');
@@ -1330,7 +1395,7 @@ case 2:
     break;
 
   case 169:
-#line 1158 "perly.y"
+#line 1228 "perly.y"
     { (yyval.opval) = newOP(IVAL((ps[(1) - (1)].val.i_tkval)), OPf_SPECIAL);
 			    PL_hints |= HINT_BLOCK_SCOPE;
 			  TOKEN_GETMAD((ps[(1) - (1)].val.i_tkval),(yyval.opval),'o');
@@ -1338,74 +1403,74 @@ case 2:
     break;
 
   case 170:
-#line 1163 "perly.y"
+#line 1233 "perly.y"
     { (yyval.opval) = newLOOPEX(IVAL((ps[(1) - (2)].val.i_tkval)),(ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 171:
-#line 1167 "perly.y"
+#line 1237 "perly.y"
     { (yyval.opval) = newUNOP(OP_NOT, 0, scalar((ps[(2) - (2)].val.opval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 172:
-#line 1171 "perly.y"
+#line 1241 "perly.y"
     { (yyval.opval) = newOP(IVAL((ps[(1) - (1)].val.i_tkval)), 0);
 			  TOKEN_GETMAD((ps[(1) - (1)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 173:
-#line 1175 "perly.y"
+#line 1245 "perly.y"
     { (yyval.opval) = newUNOP(IVAL((ps[(1) - (2)].val.i_tkval)), 0, (ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 174:
-#line 1179 "perly.y"
+#line 1249 "perly.y"
     { (yyval.opval) = newUNOP(IVAL((ps[(1) - (2)].val.i_tkval)), 0, (ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 175:
-#line 1183 "perly.y"
+#line 1253 "perly.y"
     { (yyval.opval) = newOP(OP_REQUIRE, (ps[(1) - (1)].val.i_tkval) ? OPf_SPECIAL : 0);
 			  TOKEN_GETMAD((ps[(1) - (1)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 176:
-#line 1187 "perly.y"
+#line 1257 "perly.y"
     { (yyval.opval) = newUNOP(OP_REQUIRE, (ps[(1) - (2)].val.i_tkval) ? OPf_SPECIAL : 0, (ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 177:
-#line 1191 "perly.y"
+#line 1261 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED, scalar((ps[(1) - (1)].val.opval))); ;}
     break;
 
   case 178:
-#line 1193 "perly.y"
+#line 1263 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 			    append_elem(OP_LIST, (ps[(2) - (2)].val.opval), scalar((ps[(1) - (2)].val.opval)))); ;}
     break;
 
   case 179:
-#line 1196 "perly.y"
+#line 1266 "perly.y"
     { (yyval.opval) = newOP(IVAL((ps[(1) - (1)].val.i_tkval)), 0);
 			  TOKEN_GETMAD((ps[(1) - (1)].val.i_tkval),(yyval.opval),'o');
 			;}
     break;
 
   case 180:
-#line 1200 "perly.y"
+#line 1270 "perly.y"
     { (yyval.opval) = newOP(IVAL((ps[(1) - (3)].val.i_tkval)), 0);
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'o');
 			  TOKEN_GETMAD((ps[(2) - (3)].val.i_tkval),(yyval.opval),'(');
@@ -1414,13 +1479,13 @@ case 2:
     break;
 
   case 181:
-#line 1206 "perly.y"
+#line 1276 "perly.y"
     { (yyval.opval) = newUNOP(OP_ENTERSUB, OPf_STACKED,
 				scalar((ps[(1) - (1)].val.opval))); ;}
     break;
 
   case 182:
-#line 1209 "perly.y"
+#line 1279 "perly.y"
     { (yyval.opval) = (IVAL((ps[(1) - (3)].val.i_tkval)) == OP_NOT)
 			    ? newUNOP(IVAL((ps[(1) - (3)].val.i_tkval)), 0, newSVOP(OP_CONST, 0, newSViv(0)))
 			    : newOP(IVAL((ps[(1) - (3)].val.i_tkval)), OPf_SPECIAL);
@@ -1432,7 +1497,7 @@ case 2:
     break;
 
   case 183:
-#line 1218 "perly.y"
+#line 1288 "perly.y"
     { (yyval.opval) = newUNOP(IVAL((ps[(1) - (4)].val.i_tkval)), 0, (ps[(3) - (4)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (4)].val.i_tkval),(yyval.opval),'o');
 			  TOKEN_GETMAD((ps[(2) - (4)].val.i_tkval),(yyval.opval),'(');
@@ -1441,7 +1506,7 @@ case 2:
     break;
 
   case 184:
-#line 1224 "perly.y"
+#line 1294 "perly.y"
     { (yyval.opval) = pmruntime((ps[(1) - (4)].val.opval), (ps[(3) - (4)].val.opval), 1);
 			  TOKEN_GETMAD((ps[(2) - (4)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(4) - (4)].val.i_tkval),(yyval.opval),')');
@@ -1449,7 +1514,7 @@ case 2:
     break;
 
   case 187:
-#line 1231 "perly.y"
+#line 1301 "perly.y"
     {
 			  (yyval.opval) = newLISTOP(OP_DIE, 0, newOP(OP_PUSHMARK, 0),
 				newSVOP(OP_CONST, 0, newSVpvs("Unimplemented")));
@@ -1457,7 +1522,7 @@ case 2:
     break;
 
   case 188:
-#line 1239 "perly.y"
+#line 1309 "perly.y"
     { (yyval.opval) = my_attrs((ps[(2) - (3)].val.opval),(ps[(3) - (3)].val.opval));
 			  DO_MAD(
 			      token_getmad((ps[(1) - (3)].val.i_tkval),(yyval.opval),'d');
@@ -1468,14 +1533,14 @@ case 2:
     break;
 
   case 189:
-#line 1247 "perly.y"
+#line 1317 "perly.y"
     { (yyval.opval) = localize((ps[(2) - (2)].val.opval),IVAL((ps[(1) - (2)].val.i_tkval)));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'d');
 			;}
     break;
 
   case 190:
-#line 1254 "perly.y"
+#line 1324 "perly.y"
     { (yyval.opval) = sawparens((ps[(2) - (3)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (3)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(3) - (3)].val.i_tkval),(yyval.opval),')');
@@ -1483,7 +1548,7 @@ case 2:
     break;
 
   case 191:
-#line 1259 "perly.y"
+#line 1329 "perly.y"
     { (yyval.opval) = sawparens(newNULLLIST());
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'(');
 			  TOKEN_GETMAD((ps[(2) - (2)].val.i_tkval),(yyval.opval),')');
@@ -1491,42 +1556,42 @@ case 2:
     break;
 
   case 192:
-#line 1264 "perly.y"
+#line 1334 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 193:
-#line 1266 "perly.y"
+#line 1336 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 194:
-#line 1268 "perly.y"
+#line 1338 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 195:
-#line 1273 "perly.y"
+#line 1343 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 196:
-#line 1275 "perly.y"
+#line 1345 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 197:
-#line 1279 "perly.y"
+#line 1349 "perly.y"
     { (yyval.opval) = (OP*)NULL; ;}
     break;
 
   case 198:
-#line 1281 "perly.y"
+#line 1351 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
   case 199:
-#line 1283 "perly.y"
+#line 1353 "perly.y"
     {
 #ifdef MAD
 			  OP* op = newNULLLIST();
@@ -1540,69 +1605,69 @@ case 2:
     break;
 
   case 200:
-#line 1298 "perly.y"
+#line 1368 "perly.y"
     { PL_parser->in_my = 0; (yyval.opval) = my((ps[(1) - (1)].val.opval)); ;}
     break;
 
   case 201:
-#line 1302 "perly.y"
+#line 1372 "perly.y"
     { (yyval.opval) = newCVREF(IVAL((ps[(1) - (2)].val.i_tkval)),(ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'&');
 			;}
     break;
 
   case 202:
-#line 1308 "perly.y"
+#line 1378 "perly.y"
     { (yyval.opval) = newSVREF((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'$');
 			;}
     break;
 
   case 203:
-#line 1314 "perly.y"
+#line 1384 "perly.y"
     { (yyval.opval) = newAVREF((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'@');
 			;}
     break;
 
   case 204:
-#line 1320 "perly.y"
+#line 1390 "perly.y"
     { (yyval.opval) = newHVREF((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'%');
 			;}
     break;
 
   case 205:
-#line 1326 "perly.y"
+#line 1396 "perly.y"
     { (yyval.opval) = newAVREF((ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'l');
 			;}
     break;
 
   case 206:
-#line 1332 "perly.y"
+#line 1402 "perly.y"
     { (yyval.opval) = newGVREF(0,(ps[(2) - (2)].val.opval));
 			  TOKEN_GETMAD((ps[(1) - (2)].val.i_tkval),(yyval.opval),'*');
 			;}
     break;
 
   case 207:
-#line 1339 "perly.y"
+#line 1409 "perly.y"
     { (yyval.opval) = scalar((ps[(1) - (1)].val.opval)); ;}
     break;
 
   case 208:
-#line 1341 "perly.y"
+#line 1411 "perly.y"
     { (yyval.opval) = scalar((ps[(1) - (1)].val.opval)); ;}
     break;
 
   case 209:
-#line 1343 "perly.y"
+#line 1413 "perly.y"
     { (yyval.opval) = scope((ps[(1) - (1)].val.opval)); ;}
     break;
 
   case 210:
-#line 1346 "perly.y"
+#line 1416 "perly.y"
     { (yyval.opval) = (ps[(1) - (1)].val.opval); ;}
     break;
 
diff --git a/perly.tab b/perly.tab
index 85c70a0..c8fef77 100644
--- a/perly.tab
+++ b/perly.tab
@@ -167,28 +167,28 @@ static const yytype_int16 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   135,   135,   141,   151,   155,   159,   165,   175,   180,
-     181,   188,   198,   201,   202,   204,   206,   223,   242,   244,
-     246,   250,   254,   258,   262,   271,   272,   276,   287,   295,
-     306,   309,   315,   316,   323,   336,   348,   359,   369,   379,
-     411,   419,   429,   435,   436,   441,   444,   448,   453,   457,
-     461,   467,   476,   480,   482,   484,   486,   488,   493,   497,
-     503,   517,   518,   522,   535,   558,   564,   569,   574,   584,
-     585,   590,   591,   595,   605,   609,   619,   620,   629,   643,
-     642,   661,   665,   669,   673,   677,   687,   696,   700,   705,
-     712,   721,   727,   733,   741,   745,   752,   751,   762,   763,
-     767,   776,   781,   789,   796,   803,   813,   822,   829,   838,
-     845,   851,   858,   868,   872,   876,   882,   886,   890,   894,
-     898,   902,   906,   918,   922,   926,   930,   940,   944,   951,
-     955,   959,   964,   969,   974,   983,   988,   993,   999,  1005,
-    1016,  1020,  1024,  1036,  1049,  1057,  1069,  1070,  1071,  1072,
-    1073,  1078,  1082,  1084,  1088,  1093,  1098,  1100,  1102,  1104,
-    1106,  1108,  1110,  1119,  1130,  1132,  1134,  1139,  1152,  1157,
-    1162,  1166,  1170,  1174,  1178,  1182,  1186,  1190,  1192,  1195,
-    1199,  1205,  1208,  1217,  1223,  1228,  1229,  1230,  1238,  1246,
-    1253,  1258,  1263,  1265,  1267,  1272,  1274,  1279,  1280,  1282,
-    1297,  1301,  1307,  1313,  1319,  1325,  1331,  1338,  1340,  1342,
-    1345
+       0,   140,   140,   146,   156,   160,   164,   170,   180,   185,
+     186,   193,   203,   206,   207,   209,   211,   228,   247,   249,
+     251,   255,   259,   263,   267,   276,   277,   281,   292,   300,
+     311,   314,   320,   321,   328,   355,   380,   391,   401,   411,
+     455,   475,   499,   505,   506,   511,   514,   518,   523,   527,
+     531,   537,   546,   550,   552,   554,   556,   558,   563,   567,
+     573,   587,   588,   592,   605,   628,   634,   639,   644,   654,
+     655,   660,   661,   665,   675,   679,   689,   690,   699,   713,
+     712,   731,   735,   739,   743,   747,   757,   766,   770,   775,
+     782,   791,   797,   803,   811,   815,   822,   821,   832,   833,
+     837,   846,   851,   859,   866,   873,   883,   892,   899,   908,
+     915,   921,   928,   938,   942,   946,   952,   956,   960,   964,
+     968,   972,   976,   988,   992,   996,  1000,  1010,  1014,  1021,
+    1025,  1029,  1034,  1039,  1044,  1053,  1058,  1063,  1069,  1075,
+    1086,  1090,  1094,  1106,  1119,  1127,  1139,  1140,  1141,  1142,
+    1143,  1148,  1152,  1154,  1158,  1163,  1168,  1170,  1172,  1174,
+    1176,  1178,  1180,  1189,  1200,  1202,  1204,  1209,  1222,  1227,
+    1232,  1236,  1240,  1244,  1248,  1252,  1256,  1260,  1262,  1265,
+    1269,  1275,  1278,  1287,  1293,  1298,  1299,  1300,  1308,  1316,
+    1323,  1328,  1333,  1335,  1337,  1342,  1344,  1349,  1350,  1352,
+    1367,  1371,  1377,  1383,  1389,  1395,  1401,  1408,  1410,  1412,
+    1415
 };
 #endif
 
diff --git a/perly.y b/perly.y
old mode 100644
new mode 100755
index aad4dd7..9d2afe5
--- a/perly.y
+++ b/perly.y
@@ -1,7 +1,7 @@
 /*    perly.y
  *
  *    Copyright (c) 1991-2002, 2003, 2004, 2005, 2006 Larry Wall
- *    Copyright (c) 2007, 2008 by Larry Wall and others
+ *    Copyright (c) 2007, 2008, 2009 by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -328,10 +328,24 @@ cont	:	/* NULL */
 loop	:	label WHILE '(' remember texpr ')' mintro mblock cont
 			{ OP *innerop;
 			  PL_parser->copline = (line_t)$2;
-			    $$ = block_end($4,
+#ifdef TRY_OPLINES
+			  if (PVAL($1)) {
+			      $$ = block_end($4,
+				       newSTATEOP(0, PVAL($1),
+						  innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						            IVAL($2), $5, $8, $9, $7)));
+			  } 
+			  else {
+			      $$ = block_end($4,
+				        innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					          IVAL($2), $5, $8, $9, $7));
+			  }
+#else
+			  $$ = block_end($4,
 				   newSTATEOP(0, PVAL($1),
-				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
-						IVAL($2), $5, $8, $9, $7)));
+				       innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL($2), $5, $8, $9, $7)));
+#endif
 			  TOKEN_GETMAD($1,innerop,'L');
 			  TOKEN_GETMAD($2,innerop,'W');
 			  TOKEN_GETMAD($3,innerop,'(');
@@ -341,10 +355,23 @@ loop	:	label WHILE '(' remember texpr ')' mintro mblock cont
 	|	label UNTIL '(' remember iexpr ')' mintro mblock cont
 			{ OP *innerop;
 			  PL_parser->copline = (line_t)$2;
-			    $$ = block_end($4,
+#ifdef TRY_OPLINES
+			  if (PVAL($1)) {
+				$$ = block_end($4,
 				   newSTATEOP(0, PVAL($1),
 				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
 						IVAL($2), $5, $8, $9, $7)));
+			  } else {
+				$$ = block_end($4,
+				        innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						IVAL($2), $5, $8, $9, $7));
+			  }
+#else
+			  $$ = block_end($4,
+				   newSTATEOP(0, PVAL($1),
+				     innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						IVAL($2), $5, $8, $9, $7)));
+#endif
 			  TOKEN_GETMAD($1,innerop,'L');
 			  TOKEN_GETMAD($2,innerop,'W');
 			  TOKEN_GETMAD($3,innerop,'(');
@@ -375,7 +402,7 @@ loop	:	label WHILE '(' remember texpr ')' mintro mblock cont
 			{ OP *innerop;
 			  $$ = block_end($4,
 			     innerop = newFOROP(0, PVAL($1), (line_t)IVAL($2),
-						    (OP*)NULL, $5, $7, $8));
+						(OP*)NULL, $5, $7, $8));
 			  TOKEN_GETMAD($1,((LISTOP*)innerop)->op_first,'L');
 			  TOKEN_GETMAD($2,((LISTOP*)innerop)->op_first->op_sibling,'W');
 			  TOKEN_GETMAD($3,((LISTOP*)innerop)->op_first->op_sibling,'(');
@@ -386,10 +413,23 @@ loop	:	label WHILE '(' remember texpr ')' mintro mblock cont
 			/* basically fake up an initialize-while lineseq */
 			{ OP *forop;
 			  PL_parser->copline = (line_t)IVAL($2);
+#ifdef TRY_OPLINES
+			  if (PVAL($1)) {
+			      forop = newSTATEOP(0, PVAL($1),
+				          newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						     IVAL($2), scalar($7),
+						     $12, $10, $9));
+			  } else {
+			      forop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL($2), scalar($7),
+						 $12, $10, $9);
+			  }
+#else
 			  forop = newSTATEOP(0, PVAL($1),
-					    newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
-						IVAL($2), scalar($7),
-						$12, $10, $9));
+				      newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+						 IVAL($2), scalar($7),
+						 $12, $10, $9));
+#endif
 #ifdef MAD
 			  forop = newUNOP(OP_NULL, 0, append_elem(OP_LINESEQ,
 				newSTATEOP(0,
@@ -410,23 +450,48 @@ loop	:	label WHILE '(' remember texpr ')' mintro mblock cont
 					forop);
 			  }
 
-
 #endif
 			  $$ = block_end($4, forop); }
 	|	label block cont  /* a block is a loop that happens once */
-			{ $$ = newSTATEOP(0, PVAL($1),
+			{ 
+#ifdef TRY_OPLINES
+			   if (PVAL($1)) {
+				$$ = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					    NOLINE, (OP*)NULL, $2, $3, 0);
+			   } else {
+				$$ = newSTATEOP(0, PVAL($1),
+				 newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+					    NOLINE, (OP*)NULL, $2, $3, 0));
+			   }
+#else
+			   $$ = newSTATEOP(0, PVAL($1),
 				 newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
 					    NOLINE, (OP*)NULL, $2, $3, 0));
+#endif
 			  TOKEN_GETMAD($1,((LISTOP*)$$)->op_first,'L'); }
 	;
 
 /* Switch blocks */
 switch	:	label GIVEN '(' remember mydefsv mexpr ')' mblock
 			{ PL_parser->copline = (line_t) $2;
+#ifdef TRY_OPLINES
+			  if (PVAL($1)) {
 			    $$ = block_end($4,
 				newSTATEOP(0, PVAL($1),
 				    newGIVENOP($6, scope($8),
-					(PADOFFSET) $5) )); }
+					(PADOFFSET) $5) ));
+			   } else {
+			    $$ = block_end($4,
+					newGIVENOP($6, scope($8),
+					(PADOFFSET) $5));
+			   }
+#else
+			    $$ = block_end($4,
+				newSTATEOP(0, PVAL($1),
+				    newGIVENOP($6, scope($8),
+					(PADOFFSET) $5) ));
+#endif
+			}
 	;
 
 /* determine whether there are any new my declarations */
diff --git a/run.c b/run.c
index be280ee..58be2c7 100644
--- a/run.c
+++ b/run.c
@@ -39,6 +39,16 @@ Perl_runops_standard(pTHX)
     dVAR;
     while ((PL_op = CALL_FPTR(PL_op->op_ppaddr)(aTHX))) {
 	PERL_ASYNC_CHECK();
+	/* Idea from Ben Morrow:
+	   For each formerly nextstates clear the temp stack. So we put an op_line only 
+           in the place of former nextstates? */
+#ifdef TRY_OPLINES_NOT
+	if (PL_op->op_line) {
+	    TAINT_NOT;          /* Each statement is presumed innocent */
+	    PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
+	    FREETMPS;
+	}
+#endif
     }
 
     TAINT_NOT;
@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 7, 2014

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @cpansprout

On Sun Sep 07 14​:33​:30 2014, rurban wrote​:

Looks like you cannot remember my old oplines patch from 2008, which
showed that moving the line from the COP to every OP will save ~8%
memory and a small amount (2-5%) of runtime. smaller and faster, not
bigger.

Do you have a message id?

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @iabyn

On Sun, Sep 07, 2014 at 04​:32​:33PM -0500, Reini Urban wrote​:

Looks like you cannot remember my old oplines patch from 2008, which showed
that moving the line from the COP to every OP will save ~8% memory and a
small amount (2-5%) of runtime. smaller and faster, not bigger.

From the comments in your patch, you assume 4 ops per line. This seems
somewhat low. A quick run of regen/opcode.pl (I just picked it because
it happens to be something I've worked on recently) shows nextstates
represent about 1 in 11 compiled ops (as shown by -Dx), and 1 in 8 op
executions (as shown by -Dt).

There is still work to be done, which I didn't want to do alone then, but
the general idea proves the opposite to what you are talking about here.

Its not clear to me from this diff how you intend handle the nextstate
actions (e.g. resetting PL_stack_sp) in the absence of nextstate ops. You
seem to be moving that into the runops loop; in that case I would expect a
larger overhead for having to check for a "nextstateish" action for every
op, rather than just doing the nextstate when needed.

--
Please note that ash-trays are provided for the use of smokers,
whereas the floor is provided for the use of all patrons.
  -- Bill Royston

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @ikegami

On Thu, Sep 4, 2014 at 11​:24 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Sep 04 05​:02​:17 2014, paul@​pjcj.net wrote​:

On Thu, Sep 04, 2014 at 01​:28​:17PM +0200, Rafael Garcia-Suarez wrote​:

On 4 September 2014 13​:09, demerphq <demerphq@​gmail.com> wrote​:

On 4 September 2014 11​:02, Paul Johnson <paul@​pjcj.net> wrote​:

Father C, you noted in the roadmap thread that fixing this (and
incorrect line numbers in general) would increase memory usage
(because
of the need to store file/line information in more places). I think
it's a price that I would be willing to pay, but it sounds like
others
disagree. Is that still the case?

It was Zefram who raised the objection last time. I don’t think the
memory increase would be too significant, but it’s subjective.

Hold on. Like the OP said, you get the right line number if you add a space
in front of the printf. Why would the fix require more memory that if the
user had inserted a space?

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @cpansprout

On Mon Sep 08 06​:58​:48 2014, ikegami@​adaelis.com wrote​:

On Thu, Sep 4, 2014 at 11​:24 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

It was Zefram who raised the objection last time. I don’t think the
memory increase would be too significant, but it’s subjective.

Hold on. Like the OP said, you get the right line number if you add a
space
in front of the printf. Why would the fix require more memory that if
the
user had inserted a space?

Whitespace differences can change which line number is stored for a multi-line statement, but ultimately the underlying problem still exists​: only one line number per statement. So if you have die() twice in the same statement, on different lines, one of them will give the wrong number.

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @ikegami

On Mon, Sep 8, 2014 at 11​:33 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

but ultimately the underlying problem still exists​: only one line number
per statement. So if you have die() twice in the same statement, on
different lines, one of them will give the wrong number.

I'm quite aware of that, but that's a different problem (and one I can live
with).

In this case, it's the opposite problem. We have two statements and one
line number.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @rurban

On Mon, Sep 8, 2014 at 7​:11 AM, Dave Mitchell <davem@​iabyn.com> wrote​:

On Sun, Sep 07, 2014 at 04​:32​:33PM -0500, Reini Urban wrote​:

Looks like you cannot remember my old oplines patch from 2008, which showed
that moving the line from the COP to every OP will save ~8% memory and a
small amount (2-5%) of runtime. smaller and faster, not bigger.

From the comments in your patch, you assume 4 ops per line. This seems
somewhat low. A quick run of regen/opcode.pl (I just picked it because
it happens to be something I've worked on recently) shows nextstates
represent about 1 in 11 compiled ops (as shown by -Dx), and 1 in 8 op
executions (as shown by -Dt).

See the 2nd attached file oplines1.pl which creates a simple test
module to calculate
the respective changes.
It's measured, not assumed.

There is still work to be done, which I didn't want to do alone then, but
the general idea proves the opposite to what you are talking about here.

Its not clear to me from this diff how you intend handle the nextstate
actions (e.g. resetting PL_stack_sp) in the absence of nextstate ops. You
seem to be moving that into the runops loop; in that case I would expect a
larger overhead for having to check for a "nextstateish" action for every
op, rather than just doing the nextstate when needed.

Yes. cops for stack resets and more are preserved in perly.y and op.c.
I haven't checked it exactly yet, but I was assuming only scope enter, exits
and entersub need the nextstate actions (stack reset, TAINT_NOT,
FREETMPS).
I played with it in B​::CC some years ago. See
http​://blogs.perl.org/users/rurban/2012/10/optimizing-compiler-benchmarks-part-4.html

I updated my oplines patch to blead at my github, in case anyone wants
to continue.
https://github.com/rurban/perl/tree/oplines
Make test passes.
--
Reini Urban
http​://cpanel.net/ http​://www.perl-compiler.org/

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 8, 2014

From @cpansprout

On Mon Sep 08 11​:49​:30 2014, rurban wrote​:

I haven't checked it exactly yet, but I was assuming only scope enter,
exits
and entersub need the nextstate actions (stack reset, TAINT_NOT,
FREETMPS).

Most ops still push on to the stack even in void context. Does that affect your statement?

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 9, 2014

From @iabyn

On Mon, Sep 08, 2014 at 01​:49​:07PM -0500, Reini Urban wrote​:

From the comments in your patch, you assume 4 ops per line. This seems
somewhat low. A quick run of regen/opcode.pl (I just picked it because
it happens to be something I've worked on recently) shows nextstates
represent about 1 in 11 compiled ops (as shown by -Dx), and 1 in 8 op
executions (as shown by -Dt).

See the 2nd attached file oplines1.pl which creates a simple test
module to calculate
the respective changes.
It's measured, not assumed.

So you have a test file which measures at 4 ops/line, while I have a perl
file that measures at 8-11 ops/line. Both are of course correct. But its
not clear which one of the two is more typical. So you can't conclude from
that data that 4 is typical.

Its not clear to me from this diff how you intend handle the nextstate
actions (e.g. resetting PL_stack_sp) in the absence of nextstate ops. You
seem to be moving that into the runops loop; in that case I would expect a
larger overhead for having to check for a "nextstateish" action for every
op, rather than just doing the nextstate when needed.

Yes. cops for stack resets and more are preserved in perly.y and op.c.
I haven't checked it exactly yet, but I was assuming only scope enter, exits
and entersub need the nextstate actions (stack reset, TAINT_NOT,
FREETMPS).

That's very wrong. In the following examples, removing the nextstate
marked by <;> will give​:

  #!perl -T
  $x = $^X <;>
  $y = $z+1; # $y now tainted

  sub DESTROY { print "DESTROY\n" }
  $r = bless [ 1,2,3 ];
  $r = $r->[0] <;>
  print "ok\n"; # "DESTROY" now printed *after* "ok"

I can't immediately think of any behavioural changes from not resetting the
stack, but it *will* cause the stack to be unnecessarily extended, as it
accumulates any detritus from *every* statement in the block.

--
Monto Blanco... scorchio!

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Sep 9, 2014

From @bulk88

Dave Mitchell wrote​:

That's very wrong. In the following examples, removing the nextstate
marked by <;> will give​:

\#\!perl \-T
$x = $^X \<;>
$y = $z\+1;       \# $y now tainted


sub DESTROY \{ print "DESTROY\\n" \}
$r = bless \[ 1\,2\,3 \];
$r = $r\->\[0\] \<;>
print "ok\\n";    \# "DESTROY" now printed \*after\* "ok"

I can't immediately think of any behavioural changes from not resetting the
stack, but it *will* cause the stack to be unnecessarily extended, as it
accumulates any detritus from *every* statement in the block.

IIRC the stack is extended by a couple hundreds of ptrs by the time run
phase is reached. Therefore there is plenty of space to collect a couple
non list context statements onto it.

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Oct 22, 2014

From @cpansprout

On Mon Sep 08 10​:02​:50 2014, ikegami@​adaelis.com wrote​:

On Mon, Sep 8, 2014 at 11​:33 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

but ultimately the underlying problem still exists​: only one line number
per statement. So if you have die() twice in the same statement, on
different lines, one of them will give the wrong number.

I'm quite aware of that, but that's a different problem (and one I can live
with).

In this case, it's the opposite problem. We have two statements and one
line number.

Sorry. I was so stuck on the harder problem, I didn’t see the obvious. Something is probably up with copline. I’ll look into this.

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Oct 23, 2014

From @cpansprout

Fixed in 51a82aa.

--

Father Chrysostomos

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Oct 23, 2014

@cpansprout - Status changed from 'open' to 'pending release'

@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Jun 2, 2015

From @khwilliamson

Thanks for submitting this ticket

The issue should be resolved with the release today of Perl v5.22. If you find that the problem persists, feel free to reopen this ticket

--
Karl Williamson for the Perl 5 porters team

@p5pRT p5pRT closed this Jun 2, 2015
@p5pRT

This comment has been minimized.

Copy link
Collaborator Author

@p5pRT p5pRT commented Jun 2, 2015

@khwilliamson - Status changed from 'pending release' to 'resolved'

@p5pRT p5pRT added the Severity Low label Oct 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.