GAAK! a surprising (to me) little bug!

  • Thread starter Thread starter Al Dunbar [MS-MVP]
  • Start date Start date
A

Al Dunbar [MS-MVP]

First, I'm not sure if this is a problem for all flavours of NT, but I have
just encountered it on XP (SP1 and SP2), and thought I would put it out
there for comment.

I have been in occasional discussion on the somewhat undocumented/incidental
use of ":::" as an alternative to "REM" for including comments in batch
script code. To my knowledge this has never caused me grief before, and I
have argued for its use as more obviously a non-executable statement.

I at first thought it must be some weird combination of delayedexpansion and
conditional blocks of code. Further testing indicates it is much more basic
than that.

Note the two cases below. Although extremely simple and virtually identical,
the first works as one would expect, displaying the following output:

testing 1
testing 2

while the second one displays only "The syntax of the command is incorrect."

1) good one:

@echo off
(
::: test
echo testing 1
)
echo testing 3


2) bad one:

@echo off
(
::: test

echo testing 1
)
echo testing 2

The only difference is the extra blank line between the ":::" comment and
the following ECHO statement.

In retrospect, I typically precede each block of code with a ":::" comment
with no intervening blank line, however, recently had the fortune (good or
bad) to opt for a bit of whitespace. This likely explains why it took so
long to get bitten by this one.

Is this a known issue? If so, I am surprised that it had not come up in the
various mentions of this form of commenting in the newsgroups. Is it perhaps
related to some other syntactical issue whose effects are more clearly
obvious?

Other than that, all I can think of to ask is: any comment?

/Al
 
:: something is not a comment at all. It's just a label, but an unusable one,
'cause you cannot goto to it. So you can safely use it instead of rem.

What your example shows is a syntax error of label inside ( )
Just why this is an error I have no idea, but it's an error even with common
label like in

(
:test

echo testing 1
)
echo testing 2

although if you have PRECEDING goto inside ( ), it'll work fine:

goto test
(
:test

echo testing 1
)
echo testing 2

Or even thus:

goto test2
(
:test

echo testing 1

:test2

echo testing 2
)

I guess it's a bug after all.
 
First, I'm not sure if this is a problem for all flavours of NT, but I have
just encountered it on XP (SP1 and SP2), and thought I would put it out
there for comment.

I have been in occasional discussion on the somewhat undocumented/incidental
use of ":::" as an alternative to "REM" for including comments in batch
script code. To my knowledge this has never caused me grief before, and I
have argued for its use as more obviously a non-executable statement. ....snip
The only difference is the extra blank line between the ":::" comment and
the following ECHO statement. ....snip
Is it perhaps
related to some other syntactical issue whose effects are more clearly
obvious?

Out of interest, if you place a valid label in that postion instead of the
InvalidatedLabelCommentIntroducer ::: , such as:

:TARGET

followed by the blank line that gives the error, does that give a syntax
error, too, and/or is the label reachable with a GOTO?

I imaging you've already checked that the "blank line" wasn't an
accidental UNIX-style LineFeed-only newline that was inserted.
 
in message
...snip

Out of interest, if you place a valid label in that postion instead of the
InvalidatedLabelCommentIntroducer ::: , such as:

:TARGET

followed by the blank line that gives the error, does that give a syntax
error, too, and/or is the label reachable with a GOTO?

You're on track with this aspect, William. I had known of a problem with
using :: instead of REM in a for in do loop and just knew to avoid it,
without investigating why. I've just checked and the following returns

) was unexpected at this time.

if the :abc line exists or is replaced by :: (in Win XP pro)

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
echo %%a
:abc
)
pause
=============================================

Yet this returns
The syntax of the command is incorrect.

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
:abc

echo %%a
)
pause
=============================================

and this correctly echos
hello world

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
:abc
echo %%a
)
pause
=============================================
 
Al Dunbar said:
First, I'm not sure if this is a problem for all flavours of NT, but I have
just encountered it on XP (SP1 and SP2), and thought I would put it out
there for comment.

I have been in occasional discussion on the somewhat undocumented/incidental
use of ":::" as an alternative to "REM" for including comments in batch
script code. To my knowledge this has never caused me grief before, and I
have argued for its use as more obviously a non-executable statement.

I at first thought it must be some weird combination of delayedexpansion and
conditional blocks of code. Further testing indicates it is much more basic
than that.

Note the two cases below. Although extremely simple and virtually identical,
the first works as one would expect, displaying the following output:

testing 1
testing 2

while the second one displays only "The syntax of the command is incorrect."

1) good one:

@echo off
(
::: test
echo testing 1
)
echo testing 3

2) bad one:

@echo off
(
::: test

echo testing 1
)
echo testing 2

The only difference is the extra blank line between the ":::" comment and
the following ECHO statement.

In retrospect, I typically precede each block of code with a ":::" comment
with no intervening blank line, however, recently had the fortune (good or
bad) to opt for a bit of whitespace. This likely explains why it took so
long to get bitten by this one.

Is this a known issue? If so, I am surprised that it had not come up in the
various mentions of this form of commenting in the newsgroups. Is it perhaps
related to some other syntactical issue whose effects are more clearly
obvious?

Other than that, all I can think of to ask is: any comment?

/Al

I have always used just two colons as : : blah.....
(Colon space colon space).
Never noticed anything weird, but never looked.

LB
 
Hello, Al:
On Mon, 4 Apr 2005 23:00:37 -0600: you wrote...

ADM> Is this a known issue? If so, I am surprised that it had not come up

I've mentioned it in one post.

Regards, Paul R. Sadowski [MVP].
 
You're on track with this aspect, William. I had known of a problem with
using :: instead of REM in a for in do loop and just knew to avoid it,
without investigating why. I've just checked and the following returns

) was unexpected at this time.

if the :abc line exists or is replaced by :: (in Win XP pro)

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
echo %%a
:abc
)
pause
=============================================

Yet this returns
The syntax of the command is incorrect.

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
:abc

echo %%a
)
pause
=============================================

and this correctly echos
hello world

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
:abc
echo %%a
)
pause
=============================================

I think this is due to the way line continuation is handled: the
presence of a label in a () construct, whether one line or more,
should mask out everything following the colon, including the closing
')' as part of the label. In short, it makes no more sense to put
labels inside () line continuation constructs than it does to put one
inside a single line command.
 
You're on track with this aspect, William. I had known of a problem with
using :: instead of REM in a for in do loop and just knew to avoid it,
without investigating why. I've just checked and the following returns ....snip

Yet this returns
The syntax of the command is incorrect.

=============================================
@echo off
for /f "delims=" %%a in ("hello world") do (
:abc

echo %%a
)
pause
=============================================

Thanks, foxidrive, that's useful to know. It confirms there is a problem
with labels in a (bracket-scoped) FOR IN DO statement. Ted Davis
has a point that a Label inside a (bracket-scoped) statement is a
problematic idea. It's a bit like JMPing into the body of a Subroutine
- the sort of thing that High-Level languages don't like and assembler
is perfectly happy to let you do (and it's often handy although care
is needed with the RETurn).

--
William Allen
Free interactive Batch Course http://www.allenware.com/icsw/icswidx.htm
For example Batch Files see: http://www.allenware.com/find?BatchLibrary
Creative Technical Writing - Allen & Company: http://www.allenware.com/
Header email is rarely checked. Contact us at http://www.allenware.com/
 
William Allen said:
Out of interest, if you place a valid label in that postion instead of the
InvalidatedLabelCommentIntroducer ::: , such as:

:TARGET

followed by the blank line that gives the error, does that give a syntax
error, too,

Yes, that DOES give an error as well.
and/or is the label reachable with a GOTO?

It might if it did not give an error.
I imaging you've already checked that the "blank line" wasn't an
accidental UNIX-style LineFeed-only newline that was inserted.

Considering I have consistently used the same editor for years, I did not
think that it would do this odd thing in this particular context, and only
in this context. Anyway, I checked with DEBUG and found that all lines were
terminated with CRLF.

/Al
 
foxidrive said:
You're on track with this aspect, William. I had known of a problem with
using :: instead of REM in a for in do loop and just knew to avoid it,
without investigating why.

Turns out that it is not the FOR loop specifically, but ANY context where
multiple statements are grouped as one by enclosing them in parenthesis - or
at least that is how it seems to me.

/Al
 
Ted Davis said:
I think this is due to the way line continuation is handled: the
presence of a label in a () construct, whether one line or more,
should mask out everything following the colon, including the closing
')' as part of the label.

Now that I see the same problem happens with otherwise syntactically valid
labels, I suspect that the problem may indeed be how lines starting with ":"
are parsed in a compound statement.

But I disagree somewhat with your analysis. First, if it "masks" all
characters up to and including the terminating ")", one would think that
adding an additional ")" would solve the problem, but it doesn't. Second,
why does it only do this "masking" only when the ":" line is followed by a
blank line?
In short, it makes no more sense to put
labels inside () line continuation constructs than it does to put one
inside a single line command.

The issue is not limited to labels, but includes also pseudo-comments using
"::" or ":::" as the comment code, and I see no reason why one need avoid
comments within a compound statement.

As to using labels, even though a compound statement has many somewhat
quirky issues, to a programmer whose conscience allows the use of labels in
other languages there is no particular issue with using them in statement
blocks, for example in an if-block.

Perhaps the lesson here is that batch limitations and quirkiness are still
aspects that we need to deal with, and deal with carefully. Even though I
know of no generaly principle by which certain forms of comments that work
outside of such blocks should not work inside then, the practical result of
this exercise could either be that I will studiously avoid "::" comments in
compound statements, or change my commenting style altogether in order to
avoid this problem.


/Al
 
William Allen said:
in message

Thanks, foxidrive, that's useful to know. It confirms there is a problem
with labels in a (bracket-scoped) FOR IN DO statement. Ted Davis
has a point that a Label inside a (bracket-scoped) statement is a
problematic idea. It's a bit like JMPing into the body of a Subroutine

No, having a label within a compound statement (if it would work, of course)
is not the same as JMPing into the body of a Subroutine; only actually
attempting to GOTO or CALL the label inside from outside would be
equivalent.

You are making it sound as if this behaviour has been designed in order to
discourage a particular bad practice; if that is indeed the case they should
have gone whole hog and removed labels and the goto statement. Rather, I
think it is a case of batch never having been designed to be a mature,
robust, general purpose programming platform.
- the sort of thing that High-Level languages don't like and assembler
is perfectly happy to let you do (and it's often handy although care
is needed with the RETurn).

Although we disagree somewhat, I think we are both tending towards the same
result: avoid these things.

/Al
 
I have always used just two colons as : : blah.....
(Colon space colon space).
Never noticed anything weird, but never looked.

Seems to have the same effect...

/Al
 
Paul R. Sadowski said:
Hello, Al:
On Mon, 4 Apr 2005 23:00:37 -0600: you wrote...

ADM> Is this a known issue? If so, I am surprised that it had not come up

I've mentioned it in one post.

Thanks, do you recall how long ago? Also, how did it come to your attention,
and can you shed any light on our discussions about the whys and wherefores
of it all?


/Al
 
Turns out that it is not the FOR loop specifically, but ANY context where
multiple statements are grouped as one by enclosing them in parenthesis - or
at least that is how it seems to me.

/Al

Yes, as your initial example showed. We might have to go back to using REM
<g>
 
foxidrive said:
Yes, as your initial example showed. We might have to go back to using REM
<g>

Perhaps, unfortunately, I *hate* the REM. Trying to easily discern which
lines are comment and which actually do something makes me dizzy, in much
the same way as Rapid Eye Movement sleep can tire you out.

But seriously, in the batch script that discovered the issue for me, I have
just changed the syntax from:

::: this is a comment

to:

REM ::: this is a comment

Another method might be to make the entire line a reference to a
non-existent environment variable. Try putting this in your batch file pipe
and smoking it:

% what / the , heck is this %
% what / the , (heck) is this %
% what / the%% , & heck is this %

Unfortunately this chokes as well in a compound statement.

Some other things I have tried:
nul echo/this is my comment

How this is better than REM is anyone's guess.

But I finally did run across one possibility that might have some appeal for
C afficionados and jscripters, and it appears to work in a compound
statement:

@echo off
(set //=REM )
(

%//% this is a nice little comment
%//%another

echo ok

)

The value of the "//" variable has a trailing blank in order to prevent the
second comment above from transmogrifying into:

REManother

This has one possibly useful side effect, namely that you can cause the
comments to be displayed for debugging purposes by changing the value of the
"//" variable from "REM " to "ECHO/".

Still not regally elegant. If it weren't for the debugging opportunity, I
think I'd stick with "REM ::: comment". If I was into the debug idea, I
would change "//" to something more easily typed between percent signs, and
parameterize it as in:

@echo off

(set debug=off)
set #=%debug%==on
if /i %#% (
(set #=ECHO/)
) else (
(set #=REM )
)

(

%#% this is a nice little comment
%#%another

echo ok

)

To quickly enable debug mode, you could just change the value of the debug
variable from off to on.

And, finally, I'll leave you to guess at this one:


@echo off

set dbgflag= #
(set #=call:comment %dbgflag% )

(
echo/start
%#% 0 debug comment set 0
%#% 1 debug comment set 1
%#% 2 debug comment set 2
%#% 3 debug comment set 3
echo/end
)

goto:eof
:comment
if "%1" EQU "%2" echo %3 %4 %5 %6 %7 %8 %9
goto:eof


Then change the "#" to a "2" in the first set statement...


/Al
 
Hello, Al:
On Wed, 06 Apr 2005 02:37:59 GMT: you wrote...

AD>
AD> ??>> Hello, Al:
??>> On Mon, 4 Apr 2005 23:00:37 -0600: you wrote...
??>>
ADM>>> Is this a known issue? If so, I am surprised that it had not come up
??>>
??>> I've mentioned it in one post.
AD>
AD> Thanks, do you recall how long ago? Also, how did it come to your
AD> attention, and can you shed any light on our discussions about the whys
AD> and wherefores of it all?

It appears I posted this code (or something very close to it - I may have
changed the free space line) on or about 10/7/2004 without cleaning it up. I
then followed-up as I recall explaining the "::Dummy line..."

I stumbled on it while writing code like this where you have to exit some
processing based upon a condition. Frankly, I just assumed everyone knew
about it but me. :)

Created: Thursday, October 07, 2004, 6:53:50 PM
Modified: Thursday, October 07, 2004, 7:55:15 PM

@echo off & setlocal ENABLEEXTENSIONS

for /f "usebackq tokens=1-10" %%a in (`dir /-p /-s /-c \\firecat\c$ ^|
findstr /i /C:" Bytes Free"`) do set FreeSpace=%%c

if %FreeSpace% LEQ 10000000000 (
for /f "tokens=*" %%a in ('dir . /ad /b /od') do (
if NOT "%%a"=="" (
@echo rd /s /q "%%a"
goto JumpOut
)
)
:JumpOut
::Dummy line - leave in to keep error from happening
)
Regards, Paul R. Sadowski [MVP].
 
On Wed, 06 Apr 2005 02:28:24 GMT, "Al Dunbar"
The issue is not limited to labels, but includes also pseudo-comments using
"::" or ":::" as the comment code, and I see no reason why one need avoid
comments within a compound statement.

Those *are* labels, just broken ones.
As to using labels, even though a compound statement has many somewhat
quirky issues, to a programmer whose conscience allows the use of labels in
other languages there is no particular issue with using them in statement
blocks, for example in an if-block.

A () construct in FOR is not a conventional block - it is more an
instance of line continuation with automatic separation of commands
.... in effect, the () encloses the argument list for the function.
Actually, I can't think of any language in which it would be proper to
include a label in an argument list.
Perhaps the lesson here is that batch limitations and quirkiness are still
aspects that we need to deal with, and deal with carefully. Even though I
know of no generaly principle by which certain forms of comments that work
outside of such blocks should not work inside then, the practical result of
this exercise could either be that I will studiously avoid "::" comments in
compound statements, or change my commenting style altogether in order to
avoid this problem.

There's still too much added on to too much left over parsing code.
 
On Wed, 06 Apr 2005 02:28:24 GMT, "Al Dunbar"


Those *are* labels, just broken ones.

A () construct in FOR is not a conventional block - it is more an
instance of line continuation with automatic separation of commands
... in effect, the () encloses the argument list for the function.
Actually, I can't think of any language in which it would be proper to
include a label in an argument list.
[snip]

One consideration is to ask yourself whether the avoidance of the REM
command is done for performance reasons or for aesthetic reasons?

If it's the former, the comments should precede the FOR loop and quote
enough of it to indicate what the remarks are about. Keeping
unnecessary stuff outside any loops will speed up the loops anyway
and is a standard optimisation tactic.

If it's the latter, why not just create a program named !.COM or
!.EXE that does nothing except ignore its command line parameters
and exit with no error? Then you could just use '!' as a substitute
for REM in the batch file. '!' seems more appropriate to me to
indicate a comment anyway.
 
On Wed, 06 Apr 2005 02:28:24 GMT, "Al Dunbar"


Those *are* labels, just broken ones.

A () construct in FOR is not a conventional block - it is more an
instance of line continuation with automatic separation of commands
... in effect, the () encloses the argument list for the function.
Actually, I can't think of any language in which it would be proper to
include a label in an argument list.
[snip]

One consideration is to ask yourself whether the avoidance of the REM
command is done for performance reasons or for aesthetic reasons?

If it's the former, the comments should precede the FOR loop and quote
enough of it to indicate what the remarks are about. Keeping
unnecessary stuff outside any loops will speed up the loops anyway
and is a standard optimisation tactic.

If it's the latter, why not just create a program named !.COM or
!.EXE that does nothing except ignore its command line parameters
and exit with no error? Then you could just use '!' as a substitute
for REM in the batch file. '!' seems more appropriate to me to
indicate a comment anyway.

Using a broken label to comment mark a line became popular because
there were so many things that couldn't be in a REM line - things like
redirection and pipe characters. As it happened, COMMAND.COM actually
parsed lines for redirection before it checked to see if the line was
a command to be executed, but it parsed labels before it parsed for
redirection, so :: was actually a more useful way to comment a line,
as well as being faster (in those days, every CPU cycle counted
because there weren't very many of them per second by today's
standards - I seem to remember finding out about it when I was using a
15 MHz 286 (maybe 386) screamer).
 
Back
Top