Shorthand for($scalar) loops and resetting pos($scalar)

C

Clint Olsen

Hi:

I'm currently using 5.8.1, and I'm writing a lexer which operates on a
scalar that has the contents of the entire file. I'm using the usual
suspects (/gc and \G) in all of my patterns to remember where I was.

However, I've noticed a technique in Parse::Yapp which does the following:

LOOP: for ($scalar) {

/whitespace/ and next LOOP;
/pattern/ and this;
/patern1/ and that;
}

What exactly is the for() loop doing that's different than $_ = $scalar?

The documentation is pretty scant on this subject - conditions under which
pos() will be reset. Generally a for loop consists of an initialization, a
test, and an optional chunk to do at the end of the code BLOCK.

Thanks,

-Clint
 
B

Ben Morrow

Clint Olsen said:
LOOP: for ($scalar) {

/whitespace/ and next LOOP;
/pattern/ and this;
/patern1/ and that;
}

What exactly is the for() loop doing that's different than $_ = $scalar?

1. Giving you a loop to 'next' to,
2. localising $_,
3. aliasing $_ rather than simply assigning it: ie. modifying $_ in
the loop will modify $scalar outside it.

The loop could be rewritten

LOOP: {
local *_ = \$scalar;
...
}

but that's a little *too* incomprehensible, even for me :).

This is quite a common idiom in Perl: it's sort-of like the 'with'
keyword in VB et al.
The documentation is pretty scant on this subject - conditions under which
pos() will be reset.

From perlop:

| A failed match normally resets the search position to the beginning
| of the string, but you can avoid that by adding the "/c" modifier
| (e.g. "m//gc"). Modifying the target string also resets the search
| position.
Generally a for loop consists of an initialization, a test, and an
optional chunk to do at the end of the code BLOCK.

That is a C-style for() loop, which is not much used in Perl and is
actually a while() loop in disguise :). The for() loop above is the
*other* type of for() loop, which some people call a 'foreach' loop to
disambiguate.

Ben
 
C

Clint Olsen

1. Giving you a loop to 'next' to,

Ok, makes sense. Although you don't really need the for keyword to do
that, as you have shown in later code.
2. localising $_,

I've never used local variables. The documentation says you should
generally avoid them in favor of lexically scoped variables.
3. aliasing $_ rather than simply assigning it: ie. modifying $_ in
the loop will modify $scalar outside it.

How is that different than references? Sorry if my globbing/aliasing
knowledge is a bit sparse. I didn't start using Perl until version 5.X.
The loop could be rewritten

LOOP: {
local *_ = \$scalar;
...

You don't mean $_?
| A failed match normally resets the search position to the beginning
| of the string, but you can avoid that by adding the "/c" modifier
| (e.g. "m//gc"). Modifying the target string also resets the search
| position.

Right, but it totally leaves out the case of when assigning a reference to
that scalar loses info or this "local" construct which appears to preserve
pos(). Obviously when you have a copy of a scalar, that scalar's pos()
should be 0 (or undef), but the conditions under which a copy is made is
obviously clouded in ths funky for() loop.
That is a C-style for() loop, which is not much used in Perl and is
actually a while() loop in disguise :). The for() loop above is the
*other* type of for() loop, which some people call a 'foreach' loop to
disambiguate.

Yeah, it's as clear as mud :) I read page on perlsyn, and the for loop
does mention some similarity between for and foreach and while, but it
doesn't go any further than that.

-Clint
 
T

Tad McClellan

Clint Olsen said:
However, I've noticed a technique in Parse::Yapp which does the following:

LOOP: for ($scalar) {

/whitespace/ and next LOOP;
/pattern/ and this;
/patern1/ and that;
}

What exactly is the for() loop doing that's different than $_ = $scalar?


Nothing.

It just saves you from typing a lot of "$scalar =~" thingies.

ie:

$scalar =~ /whitespace/ and next LOOP;
$scalar =~ /pattern/ and this;
$scalar =~ /patern1/ and that;

Generally a for loop consists of an initialization, a
test, and an optional chunk to do at the end of the code BLOCK.


The "for" and "foreach" keywords are interchangeable in Perl,
so the above is the same as:

LOOP: foreach ($scalar) {

only with less typing.
 
J

Jeff 'japhy' Pinyan

[posted & mailed (maybe?)]

I've never used local variables. The documentation says you should
generally avoid them in favor of lexically scoped variables.

Yes, but there are some variables that CANNOT be lexically scoped; these
are generally punctuation variables, like $_ and @_ and $/.
How is that different than references? Sorry if my globbing/aliasing
knowledge is a bit sparse. I didn't start using Perl until version 5.X.

An alias is another name for a variable, whereas a reference is another
name for the LOCATION of a variable.

$foo = 'blah';
@foo = qw( fee fie foe fum );
*bar = \@foo;
$bar = 'boo';

print "$foo $bar[2]"; # blah foe

The second line makes @bar an alias for @foo; that is, any changes to @foo
change @bar, and vice-versa. If we had written

*bar = \*foo;

instead, then the print() line would have read 'boo foe', because ALL
'bar' variables would be aliases for ALL 'foo' variables. What's
important to realize here is that, because of the use of glob notation,
'bar' here is a global variable; it cannot be lexical, because lexical
variables are not related to each other -- they have no concept of a glob.
You don't mean $_?

No, that would make $_ a REFERENCE to $scalar. This way makes it an alias
to $scalar. See above.
Right, but it totally leaves out the case of when assigning a reference to
that scalar loses info or this "local" construct which appears to preserve
pos(). Obviously when you have a copy of a scalar, that scalar's pos()
should be 0 (or undef), but the conditions under which a copy is made is
obviously clouded in ths funky for() loop.

It's not funky, it's a Perl-style loop, also known as 'foreach'. I don't
know what you mean, though:

$x = "jeff";
pos($x) = 2;
for ($x) {
print pos($x), " " , pos($_), "\n"; # 2 2
}
 
C

Clint Olsen

I did get your email as well. Was there a problem initially sending it?

Yes, but there are some variables that CANNOT be lexically scoped; these
are generally punctuation variables, like $_ and @_ and $/.

Right. I never tried to make them lexically scoped.
$foo = 'blah';
@foo = qw( fee fie foe fum );
*bar = \@foo;
$bar = 'boo';

print "$foo $bar[2]"; # blah foe

If we had written

*bar = \*foo;

instead, then the print() line would have read 'boo foe', because ALL
'bar' variables would be aliases for ALL 'foo' variables.

[some snipping]

Ahh, this is an excellent explanation, thanks.
No, that would make $_ a REFERENCE to $scalar. This way makes it an alias
to $scalar. See above.

Ok, makes much more sense now.
It's not funky, it's a Perl-style loop, also known as 'foreach'. I don't
know what you mean, though:

$x = "jeff";
pos($x) = 2;
for ($x) {
print pos($x), " " , pos($_), "\n"; # 2 2
}

What I meant was it wasn't entirely obvious how $_ is being set in the
for() loop, and this is the key to preserving pos() for $x in and out of
the loop. Any attempt to assign $_ without using globbing wouldn't have
worked, right?

Thanks,

-Clint
 
J

Jeff 'japhy' Pinyan

[posted & mailed]

I did get your email as well. Was there a problem initially sending it?

I couldn't be sure if the email address was valid (and was too lazy to
check out olsen.net).
What I meant was it wasn't entirely obvious how $_ is being set in the
for() loop, and this is the key to preserving pos() for $x in and out of
the loop. Any attempt to assign $_ without using globbing wouldn't have
worked, right?

Right; just copying the contents of $x to $y doesn't transfer $x's pos()
to $y.
 

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

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top