Examination of Linefeeds with CALL
Posted: 20 Mar 2017 03:17
Hi,
this is a split of the thread Delayed expansion fails in some cases.
As there are multiple different strange things to examine.
Here I want to examine the strange behaviour of linefeeds with CALL statements.
There exists the rule, that an unescaped line feed in the special charater phase will skip the remaining charaters of a line.
That's explains the following behaviour
When using CALL, we know that the parser do a second round up to the special charater phase.
The previous tests can be simply modified for CALL by doubling the percent signs.
The caret needs a simple trick to transfer it to the second parse round by defining a variable.
This is all known for a long time.
The line feeds shouldn't stop the parser, as they are escaped in the second round.
First, I thought that prior to the percent expansion there could be "reader phase" that stops at line feeds.
That would be invisible without CALL, as there a line feed is the definition of the end of line.
0.5) Phase(Read line):
Read the line up to the first line feed or end of file
1) Phase(Percent):
A double %% is replaced by a single %
Expansion of argument variables (%1, %2, etc.)
Expansion of %var%, if var does not exists replace it with nothing
For a complete explanation read this from dbenham Same thread: percent expansion
But then I made some more tests, they contradict the idea of phase 0.5
The parser in the second round should see something like this
This should also stops the parser in phase 0.5 at the linefeed.
But it's even possible to build something like this
A phase 0.5 can't exists, but my best guess is that the percent phase must be combined with phase 0.5
1) Phase(Percent):
S1: Read next character from input stream (File or CALL-Buffer)
S2: If the character is a line feed stop reading
S3: If the character is a percent goto percent expansion parser
S4: If a carriage return is found goto S1
S5: For any other character put it into the line buffer
(Percent parser): See the explanation of Dave
But additional: Even line feeds can be used here.
But there must be a little difference for the source of characters, as linefeeds are only allowed when they are read from the CALL-line-buffer.
Any other ideas?
jeb
this is a split of the thread Delayed expansion fails in some cases.
As there are multiple different strange things to examine.
Here I want to examine the strange behaviour of linefeeds with CALL statements.
There exists the rule, that an unescaped line feed in the special charater phase will skip the remaining charaters of a line.
That's explains the following behaviour
@echo off
setlocal EnableDelayedExpansion
(set \n=^
%=empty=%
)
echo Test1 fail: %\n% line2
echo Test2 fail: ^%\n% line2
echo Test3 okay: ^%\n%%\n% line2
echo Test4 okay: !\n! line2
When using CALL, we know that the parser do a second round up to the special charater phase.
The previous tests can be simply modified for CALL by doubling the percent signs.
The caret needs a simple trick to transfer it to the second parse round by defining a variable.
Code: Select all
@echo off
(set \n=^
%=empty=%
)
set "caret=^"
call echo Test5 fail: %%\n%% line2
call echo Test6 fail: %%caret%%%%\n%% line2
call echo Test7 okay: %%caret%%%%\n%%%%\n%% line2
This is all known for a long time.
dbenham wrote:The thing that bothers me is that it seems I should be able to expand the newlines above with delayed expansion, and the late appearing caret should protect the newline during the 2nd round of phase 2, thus resulting in the newline being passed. But it doesn't work
Code: Select all
call echo Test8 fail: %%caret%%!\n!!\n! line2
The line feeds shouldn't stop the parser, as they are escaped in the second round.
First, I thought that prior to the percent expansion there could be "reader phase" that stops at line feeds.
That would be invisible without CALL, as there a line feed is the definition of the end of line.
0.5) Phase(Read line):
Read the line up to the first line feed or end of file
1) Phase(Percent):
A double %% is replaced by a single %
Expansion of argument variables (%1, %2, etc.)
Expansion of %var%, if var does not exists replace it with nothing
For a complete explanation read this from dbenham Same thread: percent expansion
But then I made some more tests, they contradict the idea of phase 0.5
Code: Select all
set "var=#"
call echo Test9 okay: %%var:X=!\n!%% remaing
The parser in the second round should see something like this
echo Test9 okay: %var:X=<linefeed>% remaing
This should also stops the parser in phase 0.5 at the linefeed.
But it's even possible to build something like this
Code: Select all
set "var=#"
call echo Test10 okay: %%caret%%%%var:#=!\n!%%%%var:#=!\n!%% line2
call echo Test11 okay: %%caret%%%%\n:!\n!=!\n!%%%%\n:!\n!=!\n!%% line2
A phase 0.5 can't exists, but my best guess is that the percent phase must be combined with phase 0.5
1) Phase(Percent):
S1: Read next character from input stream (File or CALL-Buffer)
S2: If the character is a line feed stop reading
S3: If the character is a percent goto percent expansion parser
S4: If a carriage return is found goto S1
S5: For any other character put it into the line buffer
(Percent parser): See the explanation of Dave
But additional: Even line feeds can be used here.
But there must be a little difference for the source of characters, as linefeeds are only allowed when they are read from the CALL-line-buffer.
Any other ideas?
jeb