Delicious Perl bug

  • Thread starter Ilya Zakharevich
  • Start date
I

Ilya Zakharevich

perl -wlpe "s[\w]"

Probably it is there from Perl v1 (or v2???). I have no clue how to
fix it (if what I suspect is causing this holds — well, what I suspect
does not match how this program BEHAVES).

Enjoy,
Ilya

P.S. BTW, I cannot get -d go past line 1 (even with v). Why?
 
P

Peter J. Holzer

perl -wlpe "s[\w]"

Probably it is there from Perl v1 (or v2???). I have no clue how to
fix it (if what I suspect is causing this holds — well, what I suspect
does not match how this program BEHAVES).

perl -MO=Deparse -wlpe "s[\w]" shows:

LINE: while (defined($_ = <ARGV>)) {
chomp $_;
s/\w/}continue{print or die qq(-p destination: $!\n)/;
}

It's pretty clear what happens and why it behaves as it does:

s[\w] is wrapped in the loop:

LINE: while (defined($_ = <ARGV>)) { chomp $_; s[\w];}continue{print or die qq(-p destination: $!\n);}

and when that is parsed, the ; after s[\w] is taken as the start of the
substitution pattern. That ends at the next ; and the final } closes the
loop. Perfectly valid perl, but not what was intended.

That's the kind of gotchas that happens with pure text substitution. The
C preprocessor has similar issues.

Theoretically that could be fixed by first compiling the perl fragment
on the command line and then inserting the finished optree into the
loop. But I'm not sure if this is possible without unduly restricting
the semantics.

I'm also not sure whether it is worthwhile fixing. -e should IMHO only be
used for very simple programs where an error like this is easy to catch.
P.S. BTW, I cannot get -d go past line 1 (even with v). Why?

Because there is only one line?

hp
 
T

Tim McDaniel

perl -wlpe "s[\w]"

You were being way too cute in being too brief and not describing what
you are thinking.

perl
-w warnings
-l enables automatic line-ending processing: chomp() and set $\
-p autoprint the result
-e the program is the next argument

s[\w]: it took me a moment to realize that you're expecting it to
cause an error about a bad s///, but it works as a substitute.

$ perl -wlpe 's[\w]; FROG FROG'
s3333
FROG FROG
3333

But it works only with ;. Aha!

$ perl -wlpe 's[\w]! FROG FROG'
Backslash found where operator expected at -e line 2, near
";}continue{print or die qq(-p destination: $!\"
(Missing operator before \?)
Unquoted string "n" may clash with future reserved word at -e
line 2.
Final $ should be \$ or $name at -e line 1, within string
syntax error at -e line 2, near ";}continue{print or die qq(-p
destination: $!"
(Might be a runaway multi-line !! string starting on line 1)
Execution of -e aborted due to compilation errors.

Apparently, where "man perlrun" says

-p causes Perl to assume the following loop around your program, which
makes it iterate over filename arguments somewhat like sed:

LINE:
while (<>) {
... # your program goes here
} continue {
print or die "-p destination: $!\n";
}

it doesn't mean "it'll be treated like that", it means "it bloody well
IS wrapped in that, in a very real and literal sense". Similarly

$ perl -wlpe 's[\w]{ FROG FROG'
Having no space between pattern and following word is deprecated at -e
line 2.
Use of /c modifier is meaningless in s/// at -e line 2.
Bareword found where operator expected at -e line 2, near ";}continue"
(Might be a runaway multi-line {} string starting on line 1)
(Missing operator before ntinue?)
syntax error at -e line 2, near ";}continue"
Missing right curly or square bracket at -e line 2, at end of line
Execution of -e aborted due to compilation errors.

Is there any way to fix this in general? That is, is there any way to
have an arbitrary set of Perl code and interpolate it into a code
skeleton where the interpolation can't break the skeleton somehow?
 
R

Rainer Weikusat

perl -wlpe "s[\w]"
[...]

Apparently, where "man perlrun" says

-p causes Perl to assume the following loop around your program, which
makes it iterate over filename arguments somewhat like sed:

LINE:
while (<>) {
... # your program goes here
} continue {
print or die "-p destination: $!\n";
}

it doesn't mean "it'll be treated like that", it means "it bloody well
IS wrapped in that, in a very real and literal sense".

The documentation actually says so.

[...]
Is there any way to fix this in general?

The good question is "What is 'fix' supposed to mean here?", eg this
code

perl -lpe '} while (1) { ++$_'

behaves exactly like the documentation says it would (when running it
without an input file, it will 'read something' from stdin and then
print an endless sequence of ascending numbers).
 
I

Ilya Zakharevich

Because there is only one line?

Wrong. What `perl -d' reports is

main::(-e:0): BEGIN { require 'perl5db.pl' };LINE: while (<>) {chomp;
DB<1> v
1: s[a]
DB<1>

So not only `v' does not report anything on the line 0 (which we KNOW
debugger KNOWS about), but it also does not report anyting for lines 2
etc.

Morevoer, doing
/cont
locks the debugger more-or-less hard.

Ilya
 
C

Charles DeRykus

perl -wlpe "s[\w]"

Probably it is there from Perl v1 (or v2???). I have no clue how to
fix it (if what I suspect is causing this holds — well, what I suspect
does not match how this program BEHAVES).

perl -MO=Deparse -wlpe "s[\w]" shows:

LINE: while (defined($_ = <ARGV>)) {
chomp $_;
s/\w/}continue{print or die qq(-p destination: $!\n)/;
}

It's pretty clear what happens and why it behaves as it does:

s[\w] is wrapped in the loop:

LINE: while (defined($_ = <ARGV>)) { chomp $_; s[\w];}continue{print or die qq(-p destination: $!\n);}

and when that is parsed, the ; after s[\w] is taken as the start of the
substitution pattern. That ends at the next ; and the final } closes the
loop. Perfectly valid perl, but not what was intended.

That's the kind of gotchas that happens with pure text substitution. The
C preprocessor has similar issues.

Theoretically that could be fixed by first compiling the perl fragment
on the command line and then inserting the finished optree into the
loop. But I'm not sure if this is possible without unduly restricting
the semantics.

I'm also not sure whether it is worthwhile fixing. -e should IMHO only be
used for very simple programs where an error like this is easy to catch

An inner eval{} wrapping the fragment causes an error to reappear. But
this bit of micro-managing may not make much sense either...

perl -E ' LINE: while (defined($_ = <ARGV>)) { chomp $_; eval{s[\w];1}
or die $@;}continue{print or die qq(-p destination: $!\n);}'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top