 |
infinite loop with break condition
| Author |
Message |
|
dbenham
Expert
Joined: 12 Feb 2011 21:02 Posts: 889 Location: United States (east coast)
|
 Re: infinite loop with break condition
aGerman wrote: It seems the cmd is parsing the syntax of IF even if it is not executed yet. Is there a way to avoid that "early parsing" by any kind of escape sequence?
The IF statement MUST be parsed prior to execution. The comparison operator is needed at parse time, so delayed expansion cannot be used. The same is true for the IF /I option, and also for FOR options. I can think of 2 solutions. 1) Dynamically build the macro prior to each execution, substituting the actual operator in the definition. 2) Anticipate all possible operators with considerably more code. Code: ... if /i !_c2! == lss (%\n% if not !%%K! lss !_c3! exit !%%L!%\n% ) else if /i !_c2! == leq (%\n% if not !%%K! leq !_c3! exit !%%L!%\n% ) else etc. ...
Dave Benham
|
| 29 Dec 2011 09:44 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
Thanks Dave. Now I understand that behaviour. Code: @echo off &setlocal DisableDelayedExpansion
%$initWhile% :test call :macros
cmd /c "%~f0" test num lss 50 ret num 5 ret 6 echo Macro returned %errorlevel% pause goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::
:test %$While% set /a num+=1 set /a ret+=num echo !num! !ret! %$Wend%
:::::::::::::::::::::::::::::::::::::::::::::::::
:macros set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"&rem TWO EMPTY LINES ABOVE REQUIRED!
set $initWhile=for /l %%I in (1 1 2) do if %%I==2 (%\n% if defined _arg (%\n% for /f %%J in ("!_arg!") do endlocal^&call %%J %%*%\n% ) else exit%\n% ) else setlocal EnableDelayedExpansion ^&set _arg=
set $While=(%\n% setlocal EnableDelayedExpansion%\n% call set "_args=%%*"%\n% if "!_args!"=="" exit 1%\n% for %%J in (!_args:* ^^=!) do if not defined _c1 (set "_c1=%%J") else (%\n% if not defined _c2 (set "_c2=%%J") else (%\n% if not defined _c3 (set "_c3=%%J") else (%\n% if not defined _ret (set "_ret=%%J") else (%\n% if not defined _var (set "_var=%%J") else (set "!_var!=%%J"^&set "_var=")%\n% ))))%\n% for /l %%J in (0) do (%\n% for /f "tokens=1,2" %%K in ("!_c1! !_ret!") do (%\n% if /i !_c2!==equ if not !%%K! equ !_c3! exit !%%L!%\n% if /i !_c2!==leq if not !%%K! leq !_c3! exit !%%L!%\n% if /i !_c2!==lss if not !%%K! lss !_c3! exit !%%L!%\n% if /i !_c2!==geq if not !%%K! geq !_c3! exit !%%L!%\n% if /i !_c2!==gtr if not !%%K! gtr !_c3! exit !%%L!%\n% if /i !_c2!==neq if not !%%K! neq !_c3! exit !%%L!%\n% )%\n%
set $Wend=))
goto :eof
Regards aGerman
|
| 29 Dec 2011 10:18 |
|
 |
|
Aacini
Expert
Joined: 06 Dec 2011 22:15 Posts: 408 Location: México City, México
|
 Re: infinite loop with break condition
Thanks a lot Dave, it works now! Code: set while=for %%n in (1 2) do if %%n==2 (%\n% call :StrLen argv argvLen=%\n% set "body=!argv:*do=!"%\n% call :StrLen body bodyLen=%\n% set /A condLen=argvLen-bodyLen-2%\n% for %%a in (!condLen!) do set "cond=!argv:~0,%%a!"%\n% echo for /L %%%%w in (1,0,1^^) do if !cond! !body! else exit ^^^^!whileResult^^^^!^> whileBody.bat%\n% cmd /V:ON /Q /C whileBody%\n% endlocal ^& set whileResult=^!errorlevel^!%\n% ) else setlocal EnableDelayedExpansion ^& set argv=
EDIT: I added /V:ON switch to avoid an error described below. WHILE macro is used this way: Code: %WHILE% condition DO ( commands ) The condition is exactly the same of IF command. To include multiple commands, terminate each line with %\n% (macro style). EDIT: Parentheses are mandatory. To get a variable value in the condition or while body, enclose its name between %!%; this method is easier to remember than multiple ^^^^... and looks balanced (and I like it!) "whileResult" variable preserve its (numeric) value after the while ends. Some examples: Code: :factorial N R= setlocal set num=1 set whileResult=1 %while% %!%num%!% leq %1 do ( set /A whileResult*=num, num+=1 ) endlocal & if "%2" neq "" (set %2=%whileResult%) else echo %whileResult% exit /B
:lcm n1 n2 lcm= setlocal set /a "whileResult=%1, j=%2" %while% %!%j%!% neq 0 do ( set /a k=j, j=whileResult%%%%j, whileResult=k ) set /a j=%1*%2/whileResult endlocal & if "%3" neq "" (set %3=%j%) else echo %j% exit /B
call :factorial 10 factor= echo Factorial of 10: %factor% echo/
call :lcm 3527 3784 var= echo Least common multiple of 3527 and 3784: %var% echo/
echo Calculation of e: set /A digits=6, one=1 for /L %%i in (1,1,%digits%) do set one=!one!0 set /A num=0, fact=1, factXone=fact*one, whileResult=0 echo #- #%!% term summation %while% %!%factXone%!% gtr 0 do ( %\n% set /A term=one/fact, whileResult+=term %\n% echo %!%num%!%- %!%fact%!% %!%term%!% %!%whileResult%!% %\n% set /A num+=1, fact*=num, factXone=fact*one %\n% ) echo Number e = !whileResult:~0,-%DIGITS%!.!whileResult:~-%DIGITS%! echo/
Results: Code: Factorial of 10: 3628800
Least common multiple of 3527 and 3784: 13346168
Calculation of e: #- #! term summation 0- 1 1000000 1000000 1- 1 1000000 2000000 2- 2 500000 2500000 3- 6 166666 2666666 4- 24 41666 2708332 5- 120 8333 2716665 6- 720 1388 2718053 7- 5040 198 2718251 8- 40320 24 2718275 9- 362880 2 2718277 Number e = 2.718277
Last edited by Aacini on 14 Jan 2012 11:40, edited 2 times in total.
|
| 29 Dec 2011 12:08 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
Hi Aacini. I like your syntax more than mine but I dont get it run. Have a look at what I thought you did to create the output. What's wrong? Code: @echo off setlocal DisableDelayedExpansion set LF=^
::Above 2 blank lines are required - do not remove set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set while=for %%n in (1 2) do if %%n==2 (%\n% call :StrLen argv argvLen=%\n% set "body=!argv:*do=!"%\n% call :StrLen body bodyLen=%\n% set /A condLen=argvLen-bodyLen-2%\n% for %%a in (!condLen!) do set "cond=!argv:~0,%%a!"%\n% echo for /L %%%%w in (1,0,1^^) do if !cond! !body! else exit ^^^^!whileResult^^^^!^> whileBody.bat%\n% cmd /Q /C whileBody%\n% endlocal ^& set whileResult=^!errorlevel^!%\n% ) else setlocal EnableDelayedExpansion ^& set argv=
set !=^^^^!
setlocal EnableDelayedExpansion
call :factorial 10 factor= echo Factorial of 10: %factor% echo/
call :lcm 3527 3784 var= echo Least common multiple of 3527 and 3784: %var% echo/
echo Calculation of e: set /A digits=6, one=1 for /L %%i in (1,1,%digits%) do set one=!one!0 set /A num=0, fact=1, factXone=fact*one, whileResult=0 echo #- #%!% term summation %while% %!%factXone%!% gtr 0 do ( %\n% set /A term=one/fact, whileResult+=term %\n% echo %!%num%!%- %!%fact%!% %!%term%!% %!%whileResult%!% %\n% set /A num+=1, fact*=num, factXone=fact*one %\n% ) echo Number e = !whileResult:~0,-%DIGITS%!.!whileResult:~-%DIGITS%! echo/ pause goto :eof
:factorial N R= setlocal set num=1 set whileResult=1 %while% %!%num%!% leq %1 do ( set /A whileResult*=num, num+=1 ) endlocal & if "%2" neq "" (set %2=%whileResult%) else echo %whileResult% exit /B
:lcm n1 n2 lcm= setlocal set /a "whileResult=%1, j=%2" %while% %!%j%!% neq 0 do ( set /a k=j, j=whileResult%%%%j, whileResult=k ) set /a j=%1*%2/whileResult endlocal & if "%3" neq "" (set %3=%j%) else echo %j% exit /B
:StrLen string [result=[adjust]] setlocal EnableDelayedExpansion set str=%1 set str=!str:"= ! if "!str:~0,1!" == " " ( set "str=0%~1" ) else ( set "str=0!%1!" ) set len=0 for /L %%A in (12,-1,0) do ( set /A "len|=1<<%%A" for %%B in (!len!) do if "!str:~%%B,1!" == "" set /A "len&=~1<<%%A" ) for %%v in (!len!) do endlocal&if not "%2" == "" (set /A "%2=%%v%3") else echo %%v exit /B
Regards aGerman
|
| 29 Dec 2011 15:57 |
|
 |
|
Aacini
Expert
Joined: 06 Dec 2011 22:15 Posts: 408 Location: México City, México
|
 Re: infinite loop with break condition
It looks good to me, I don't understand what can be wrong... You may include ECHO's at several points to try to discover what the problem is.
|
| 29 Dec 2011 17:47 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
Thanks. Just to tell you what happen: - The factorial algorithm results in an infinte loop. - The lcm comes up with an endless Division By 0 error. - The calculation of e displays Code: Calculation of e: #- #! term summation Number e = .0 Regards aGerman
|
| 29 Dec 2011 18:06 |
|
 |
|
Aacini
Expert
Joined: 06 Dec 2011 22:15 Posts: 408 Location: México City, México
|
 Re: infinite loop with break condition
I am posting again my complete WHILE macro test program: Code: @echo off setlocal DisableDelayedExpansion set LF=^
::Above 2 blank lines are required - do not remove set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set while=for %%n in (1 2) do if %%n==2 (%\n% call :StrLen argv argvLen=%\n% set "body=!argv:*do=!"%\n% call :StrLen body bodyLen=%\n% set /A condLen=argvLen-bodyLen-2%\n% for %%a in (!condLen!) do set "cond=!argv:~0,%%a!"%\n% echo for /L %%%%w in (1,0,1^^) do if !cond! !body! else exit ^^^^!whileResult^^^^!^> whileBody.bat%\n% cmd /Q /C whileBody%\n% endlocal ^& set whileResult=^!errorlevel^!%\n% ) else setlocal EnableDelayedExpansion ^& set argv=
set !=^^^^!
setlocal EnableDelayedExpansion
call :factorial 10 factor= echo Factorial of 10: %factor% echo/ echo/
call :lcm 3527 3784 var= echo Least common multiple of 3527 and 3784: %var% echo/ echo/
echo Calculation of e: echo/ set /A digits=8, one=1 for /L %%i in (1,1,%digits%) do set one=!one!0 set /A num=0, fact=1, term=1, whileResult=0 echo #- #%!% term=1/#%!% summation %while% %!%term%!% gtr 0 do ( %\n% set /A term=one/fact, whileResult+=term %\n% echo %!%num%!%- %!%fact%!% %!%term%!% %!%whileResult%!% %\n% set /A num+=1, fact*=num %\n% ) echo/ echo Number e = !whileResult:~0,-%DIGITS%!.!whileResult:~-%DIGITS%! echo/ echo/
goto :EOF
:factorial N R= setlocal set num=1 set whileResult=1 %while% %!%num%!% leq %1 do ( set /A whileResult*=num, num+=1 ) endlocal & if "%2" neq "" (set %2=%whileResult%) else echo %whileResult% exit /B
:lcm n1 n2 lcm= setlocal set /a "whileResult=%1, j=%2" %while% %!%j%!% neq 0 do ( set /a k=j, j=whileResult%%%%j, whileResult=k ) set /a j=%1*%2/whileResult endlocal & if "%3" neq "" (set %3=%j%) else echo %j% exit /B
:StrLen string [result=[adjust]] setlocal EnableDelayedExpansion set str=%1 set str=!str:"= ! if "!str:~0,1!" == " " ( set "str=0%~1" ) else ( set "str=0!%1!" ) set len=0 for /L %%A in (12,-1,0) do ( set /A "len|=1<<%%A" for %%B in (!len!) do if "!str:~%%B,1!" == "" set /A "len&=~1<<%%A" ) for %%v in (!len!) do endlocal&if not "%2" == "" (set /A "%2=%%v%3") else echo %%v exit /B
Results: Code: Factorial of 10: 3628800
Least common multiple of 3527 and 3784: 13346168
Calculation of e:
#- #! term=1/#! summation 0- 1 100000000 100000000 1- 1 100000000 200000000 2- 2 50000000 250000000 3- 6 16666666 266666666 4- 24 4166666 270833332 5- 120 833333 271666665 6- 720 138888 271805553 7- 5040 19841 271825394 8- 40320 2480 271827874 9- 362880 275 271828149 10- 3628800 27 271828176 11- 39916800 2 271828178 12- 479001600 0 271828178
Number e = 2.71828178
Please test it and report what happened... 
|
| 29 Dec 2011 20:55 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
Still wont work. The same behaviour like before Regards aGerman
|
| 30 Dec 2011 08:21 |
|
 |
|
Aacini
Expert
Joined: 06 Dec 2011 22:15 Posts: 408 Location: México City, México
|
 Re: infinite loop with break condition
I don't understand what is happening.  Are you using Win XP? Perhaps someone may have another idea? 
|
| 30 Dec 2011 15:37 |
|
 |
|
dbenham
Expert
Joined: 12 Feb 2011 21:02 Posts: 889 Location: United States (east coast)
|
 Re: infinite loop with break condition
I get the exact same results as aGerman on both Vista and XP.
Dave Benham
|
| 30 Dec 2011 16:36 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
I'm on Win7. I figured out what we have to do: Code: cmd /V:ON /Q /C whileBody%\n% /V:ON ! But why  Why does it not inherit the delayed expansion? Regards aGerman
|
| 30 Dec 2011 17:02 |
|
 |
|
dbenham
Expert
Joined: 12 Feb 2011 21:02 Posts: 889 Location: United States (east coast)
|
 Re: infinite loop with break condition
aGerman wrote: Code: cmd /V:ON /Q /C whileBody%\n% /V:ON ! But why  Why does it not inherit the delayed expansion? I've run into this before. About the only thing that is inherited upon instantiation of a new CMD are the environment variable values. Delayed expansion state, Command extension state, Echo state - they all revert back to the default state based on the registry. This is also true for implicit instantiation of CMD that occurs with FOR /F %%A IN ('some command'), and also on both sides of a pipe. I learned the significance of this at Why does delayed expansion fail when inside a piped block of code?Now that you've got Aacini's code working, I'll have to try to figure out how it works. Dave Benham
|
| 30 Dec 2011 18:44 |
|
 |
|
Aacini
Expert
Joined: 06 Dec 2011 22:15 Posts: 408 Location: México City, México
|
 Re: infinite loop with break condition
WHILE macro is simple to use because it resemble an original Batch command, like IF or FOR. However, it is slow when it is repeatedly executed because the complete while-body is created again each time it is executed. I slightly modified WHILE macro, and renamed it to WHILEBODY, so it just create the whileBody.bat file, so it can be directly executed several times via CMD /V:ON /Q /C in a faster way. This modification also allows to execute whileBody.bat with parameters. Code: @echo off setlocal DisableDelayedExpansion set LF=^
::Above 2 blank lines are required - do not remove set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set whileBody=for %%n in (1 2) do if %%n==2 (%\n% call :StrLen argv argvLen=%\n% set "body=!argv:*do=!"%\n% call :StrLen body bodyLen=%\n% set /A condLen=argvLen-bodyLen-2%\n% for %%a in (!condLen!) do set "cond=!argv:~0,%%a!"%\n% echo for /L %%%%w in (1,0,1^^) do if !cond! !body! else exit ^^^^!whileResult^^^^!^> whileBody.bat%\n% endlocal%\n% ) else setlocal EnableDelayedExpansion ^& set argv=
set !=^^^^!
setlocal EnableDelayedExpansion
%whileBody% %!%j%!% neq 0 do ( set /a k=j, j=whileResult%%%%j, whileResult=k )
call :lcm 3527 3784 var= echo Least common multiple of 3527 and 3784: %var% goto :EOF
:lcm n1 n2 lcm= setlocal set /a "whileResult=%1, j=%2" cmd /V:ON /Q /C whileBody set /a j=%1*%2/%errorlevel% endlocal & if "%3" neq "" (set %3=%j%) else echo %j% exit /B
The whileBody.bat file may be renamed after was created, so WHILE or WHILEBODY macros may create a second whileBody.bat file. This way, a while loop may be nested inside another one. Code: %whileBody% %!%j%!% lss 10 do (%\n% set /A mul=i*j %\n% set /P =%!%mul%!%^< NUL %\n% set /A j+=1 %\n% ) if exist whileBodyRow.bat del whileBodyRow.bat ren whileBody.bat whileBodyRow.bat
echo Multiplication Table echo/ set i=1 %while% %!%i%!% lss 10 do ( %\n% set j=1 %\n% cmd /V:ON /Q /C whileBodyRow %\n% echo/ %\n% set /A i+=1 %\n% )
Results: Code: Multiplication Table
1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
|
| 30 Dec 2011 19:34 |
|
 |
|
aGerman
Expert
Joined: 22 Jan 2010 18:01 Posts: 1395 Location: Germany
|
 Re: infinite loop with break condition
dbenham wrote: Delayed expansion state, Command extension state, Echo state - they all revert back to the default state based on the registry. This is also true for implicit instantiation of CMD that occurs with FOR /F %%A IN ('some command'), and also on both sides of a pipe. I learned the significance of this at Why does delayed expansion fail when inside a piped block of code?Yeah, my tests confirmed that. Thanks for the linked thread, very helpful and interesting! Regards aGerman
|
| 30 Dec 2011 20:34 |
|
 |
|
Rileyh
Joined: 01 Sep 2011 03:54 Posts: 147 Location: Perth, Western Australia
|
 Re: infinite loop with break condition
The simplest way that I have found to do it is this: Code: set "n=0" :loop set /a n+=1 if /i _"%n%"==_"10" (goto :exitloop) ping -n 10 1.1.1.1 goto :loop :exitloop exit /b
Why (and how!) do you use macros to do infinite loops? And <b>aGerman</b>'s original topic post, it is not an infinite loop, it breaks after a set loop number. Regards, Rileyh
|
| 01 Jan 2012 02:33 |
|
|
Who is online |
Users browsing this forum: Bing [Bot] and 5 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum
|
|
 |