Batch "macros" with arguments

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#61 Post by Ed Dyreen » 26 Nov 2011 10:09

'
This is interesting, but I'm not seeing how it is useful for exceeding the 8k limit.
I did see how, but my hopes are descending rapidly
for in () seems to have troubles with brackets ()
and even trying to get the result by using echo don't work

Code: Select all

echo.@endoftest>nul

@echo off
setlocal
set val=
set "@macro=echo.this is a macro &echo.that uses memory &echo.but i'm sure that 1 + 1 equals &set /a "val=1+1" &if defined val echo.val=0%val%1!val!2^!val^! "

setlocal enableExtensions enableDelayedExpansion
set val

for /f "usebackq tokens=*" %%? in ( `echo. ^&!@macro!` ) do echo.%%?

echo(
set val
This isn't working out as I had hoped :(

Code: Select all

this is a macro
that uses memory
but i'm sure that 1 + 1 equals
2yes val=012

Omgevingsvariabele val is niet gedefinieerd

 endoftest Druk op een toets om door te gaan. . .
Thanks for the tip, I didn't know for in () uses it's own CMD session 8)

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Batch "macros" with arguments

#62 Post by jeb » 26 Nov 2011 15:34

Hi Ed,

Ed Dyreen wrote:I did see how, but my hopes are descending rapidly
for in () seems to have troubles with brackets ()
and even trying to get the result by using echo don't work


Don't lose your hope, as always the solution is obvious :D

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set LF=^


set "pLF=%%LF%%"
set "mLF=%%pLF%%^"
set @macro=for /L %%n in (1,1,3) do (^
   echo this is a macro %mLF%
   echo dsd %mLF%
   set /a val=1+%%n ^>NUL %mLF%
   echo val%%n=!val!%mLF%
)
setlocal enableExtensions enableDelayedExpansion
for /f "usebackq tokens=1,* delims==" %%1 in ( `cmd /V:on /q /c "!@macro!"` ) do (
   if "%%2" neq "" set "%%1=%%2"
)
echo --- Output is ---
set val


Output wrote: --- Output is ---
val1=2
val2=3
val3=4


hope it helps
jeb

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#63 Post by Ed Dyreen » 26 Nov 2011 23:23

'
Wow thanks jeb :D :!:

I see how it works, and it's usable to save some macro memory.

I am having problems fitting my _File.declare macro, the reason it won't fit is because it has a lot of attributes, and to get one attribute I need to refer to other macro's.

For the moment I am using a simple function call :macroEval ( macro ), at least now I know another way of doing it without call. 8)

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#64 Post by dbenham » 07 Dec 2011 07:02

Ed - Before you spend too much time on your new project, try a timing comparison between executing macro within IN() clause vs. executing macro via helper function in an external batch file like you were originally.

Maybe you've already done so. I'm curious which is faster.


Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#65 Post by Ed Dyreen » 07 Dec 2011 13:09

'
Here are the results of a simple quicky test...

"TST.CMD"

Code: Select all

@echo off &setlocal disableDelayedExpansion
:: (
   set ^"@Delayed=^>nul ( set "$NotDelayedFlag=!" ^&if defined $NotDelayedFlag ( echo.result : NotDelayed ) else echo.result : Delayed )"
   setlocal enableDelayedExpansion
   :: (
      echo.call test start %time%
      for /l %%? in ( 1, 1, 1000 ) do call calltest.CMD
      echo.call test stop %time%
      echo.

      echo.cmdLine test start %time%
      for /l %%? in ( 1, 1, 1000 ) do for /f "usebackq tokens=*" %%1 in ( `cmd /v:on /e:on /t:0B /q /c "!@Delayed!"` ) do echo.%%1
      echo.cmdLine test stop %time%
   :: )
   endlocal
:: )
endlocal

pause
exit
"calltest.CMD"

Code: Select all

:calltest
:: (
   %@Delayed%
:: )
exit /b

Code: Select all

call test start 20:04:23,01
call test stop 20:04:24,46

cmdLine test start 20:04:24,46
cmdLine test stop 20:05:24,25
Druk op een toets om door te gaan. . .
The results are bad, I did not expect that the cmdLine macro is about 30 to 45 times slower :(

I do have something to add to this;
As function libraries get larger the time to call/jump functions increases dramatically,
my untested theory is that the cmdLine variant will eventually win.
It's delay is more consistent and only related to environmental size.
But when the function :macroEval is at the top of the library, it will be faster, always :!: :idea:

Correct me if I'm wrong, I am lost, I can't decide which one I like better :oops:

Code: Select all

set macro=(
   call :macroEval ( macro, args )
   call :macroEval ( macro, args )
   call :macroEval ( macro, args )
)

Code: Select all

set macro=(
   for /f "usebackq tokens=*" %%1 in ( `cmd /v:on /e:on /t:0B /q /c "!macro!, args"` ) do catch con
   for /f "usebackq tokens=*" %%1 in ( `cmd /v:on /e:on /t:0B /q /c "!macro!, args"` ) do catch con
   for /f "usebackq tokens=*" %%1 in ( `cmd /v:on /e:on /t:0B /q /c "!macro!, args"` ) do catch con
)

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#66 Post by Ed Dyreen » 07 Dec 2011 19:25

'
The cmdLineMacro conversion is way too complex, it completely crashes when the macro contains strings like

Code: Select all

for /f ^^^"eol^^=^^^%$lf%%$lf%^%$lf%%$lf%^^ delims^^=^^^" %%r in

Code: Select all

Defined_=setLocal disableDelayedExpansion &for /l %$ in ( 1, 1, 2 ) do if %$ == 2 (
 setLocal enableDelayedExpansion
 for /f ^"eol^=^

^ delims^=^" %r in ( "yesyes" ) do (
 echo.
 echo.$t=%!_
 ) ) else set $p=_
The converter ( using jeb's technique 4 posts up ) translates to

Code: Select all

Defined_cmd=setLocal disableDelayedExpansion &for /l %$ in ( 1, 1, 2 ) do if %$ == 2 ( %$plf% setLocal enableDelayedExpansion %$plf% for /f ^"eol^=^%$plf%%$plf%^ delims^=^" %r in ( "yesyes" ) do ( %$plf% echo. %$plf% echo.$t=%!_ %$plf% ) ) else set $p=_
De syntaxis van de opdracht is onjuist.

 endoftest Druk op een toets om door te gaan. . .
:x I give up, for now... :oops:

Aacini
Expert
Posts: 1913
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Batch "macros" with arguments

#67 Post by Aacini » 10 Dec 2011 01:27

Hey, dave! I just carefully read all the five pages of this topic and have not discovered what is the method you used to place macro parameters after the macro expansion, like in these lines:

Code: Select all

%macro.diffTimeRaw% t1 t2 base
%macro.diffTimeRaw% t2 t3 base_setlocal_endlocal


that you posted in this topic, instead of place them between %macroCall% and %macroName% and enclosed in both parentheses and quotes. Could you show me a simple example on how to do that? Thanks!

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#68 Post by Ed Dyreen » 10 Dec 2011 01:51

'
This is the basic technique for appending arguments

Code: Select all

@echo off &setlocal enableDelayedExpansion

set $lf=^


:: 2 empty lines
set ^"$n1c=^^^%$lf%%$lf%^%$lf%%$lf%^^"

set ^"@macroTest=for /l %%? in ( 1, 1, 2 ) do if %%? == 2 ( %$n1c%

echo.$=^^^!$^^^!_ %$n1c%

) else set $="

%@macroTest% This works ^^^!

pause
exit

Code: Select all

$= This works !_
Druk op een toets om door te gaan. . .
Macros with parameters appended
viewtopic.php?f=3&t=2518

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#69 Post by dbenham » 10 Dec 2011 09:19

Sorry Aacini, and thanks Ed for providing the link.

I wanted to include at least 3 links in the post Aacini cited, but this site only allows a maximum of 2 links per post. So I ended up not including any :roll:

Dave Benham

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Batch "macros" with arguments

#70 Post by aGerman » 10 Dec 2011 10:12

[OffTopic]

dbenham wrote:I wanted to include at least 3 links in the post Aacini cited, but this site only allows a maximum of 2 links per post.

It's limited because of spam bots. They often try to include a lot of hyperlinks in their posts.
There is no possibility to include more than 2 links but you can prevent parsing automatically as a hyperlink. Unfortunately the forum also doesn't support BBCode NOPARSE tags that's why I use the following trick:

Code: Select all

http:[i]//[/i]www.dostips.com/

The result is
http://www.dostips.com/

Regards
aGerman

[/OffTopic]

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#71 Post by dbenham » 10 Dec 2011 10:30

@aGerman - very nice :D I'll try to remember that for future posts.

Dave Benham

Aacini
Expert
Posts: 1913
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Batch "macros" with arguments

#72 Post by Aacini » 10 Dec 2011 21:33

All this macro stuff in wonderful! I understand this is an advanced topic that challenge and amuse experts (like all of you, people!). However, my main concern is to made possible that average people may have access to advanced techniques like this one, so I have a somewhat different point of view than yours...

I slightly modified the callMacro variable and renamed it this way:

set ForMacroParamsIn=for /F "tokens=1-9 delims=,;= " %%1 in

so the execution of a macro with parameters is achieved this way:

%ForMacroParamsIn% ("Param1 Param2 ...") DO %macroName%

The DELIMS value set the same standard delimiters of normal Batch processing. The TOKENS value, combined with %%1 replaceable parameter, set the macro parameters to %1, %2, ... %9, the same parameters of a normal Batch function (yes, it works!).

Note that the macro definition must NOT include the DO part, just the enclosing parentheses; this means that the same macro may be executed with no parameters this way:

%macroName%

If a macro is executed this way and it use %1..%9 replaceable parameters, they will be replaced by the caller program parameters in the usual way (by adding the standard CALL).

This way, a normal subroutine may be directly translated to a macro with no further modifications (just the standard macro additions, like duplicating %) provided that it comply with the macro requirements: have not GOTO's, use not %normal% expansions but only !delayed! ones, etc. I am preparing a series of advices on things like convert a ":LOOP-GOTO LOOP" cycle in a "COUNT-FOR /L !COUNT!" one and similar tasks. This mean that a (normal!) Batch user may develop a series of subroutines in the usual way and then convert they to macros using a translator program, so he/she may have access to macro benefits (faster execution speed, is there any other one?) with no need to understand the ^^^^^!%%%%!^& Batch macro language mumbo jumbo.

I am currently working in the development of SUBTOMACRO.BAT, a subroutine-to-macro conversion program that will work with these specifications:

1- A "Subroutine Library" is a LIBNAME.BAT file that contain several subroutines written under macro constraints. Each routine starts at :SubName line and ends at EXIT /B [exitCode] line.
2- SUBTOMACRO.BAT program takes a Subroutine Library and create an equivalent Macro Library.
3- A "Macro Library" is a LIBNAME.macrodef.bat file that contain several SET ^"LIBNAME.SubName=(...)" macro definition commands and a routine that allows to define just certain macros. Use it this way:

Code: Select all

setlocal DisableDelayedExpansion   required in LIBNAME.macrodef files
call ReserveEnvironmentSpace #KB   if you will load a large amount of macros
call LIBNAME1.macrodef         load all macros from LIBNAME1
call LIBNAME2.macrodef name1 name2   load just these macros from LIBNAME2
setlocal EnableDelayedExpansion      if it is required
rem Continue here with your program code

4- SUBTOMACRO.BAT is a Macro Library maintenance program. Use it this way:
CALL SUBTOMACRO LIBNAME [/L:Lib[:Macro...] ...] [[-]SubName ...]
If LIBNAME.macrodef.bat file does not exist, it is created with all the subroutines of LIBNAME.bat file, or just with the SubName's given.
If LIBNAME.macrodef.bat exists, these maintenance operations are achieved on it:
- Add a new SubName definition if its macro does not exist.
- Replace an existing macro with the same SubName name definition.
- Delete an existing macro if the SubName given is preceded by dash.

When subroutines are being converted to macros, nested CALL's to another subroutines are replaced by an embedded expansion of the equivalent macro execution if such macro was previously defined; to achieve this, the CALL must be the only or last command in the line. This point means that the order of macro definitions must obey the same rules of regular programming languages (like Pascal or C) with no prototype definitions nor FORWARD references; these rules are summarized this way: to embed a nested macro execution in a new macro definition, such nested macro must be previously defined; otherwise the new macro definition will effectively CALL the nested subroutine.

Before SUBTOMACRO edit an existing Macro Library it loads all previously defined macros in that library, so dependencies to subroutines/macros of the same library are automatically resolved. However, if a subroutine call a subroutine/macro in another library, such macro must be previously defined in order to be inserted in the new definition. The /L (library load) switch define the library, or which macros of a given library, must be loaded before the editing process start. For example:

CALL SUBTOMACRO LIBNAME1 /L:LIBNAME2 /L:LIBNAME3:nameX:nameY NewSub1 NewSub2

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#73 Post by dbenham » 10 Dec 2011 23:12

@Aacini - That sounds like an interesting and ambitious project - A macro compiler :!: :lol: (its sounds like an oxymoron, but yet it makes sense)

It would be good if you can adopt jeb's new macro syntax with parameters at the end: viewtopic.php?f=3&t=2518

Aacini wrote:This way, a normal subroutine may be directly translated to a macro with no further modifications (just the standard macro additions, like duplicating %) provided that it comply with the macro requirements: have not GOTO's, use not %normal% expansions but only !delayed! ones, etc. I am preparing a series of advices on things like convert a ":LOOP-GOTO LOOP" cycle in a "COUNT-FOR /L !COUNT!" one and similar tasks.
I'm worried that the list may grow to be longer than you realize.

Instead of forcing the developer to provide functioning code for all parts of the routine, it might be helpful to have simple "keywords" defined that would automatically be replaced with some of the common macro constructs, especially when they differ from how you would normally handle it in a normal subroutine. For example, the code to return a value across the endlocal border could be signaled by the keyword {RETURN1 localVar targetVar}. I haven't really thought this through, but I think you can see my point.

Good luck on your project.

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Batch "macros" with arguments

#74 Post by Ed Dyreen » 11 Dec 2011 00:22

Aacini wrote:This mean that a (normal!) Batch user may develop a series of subroutines in the usual way and then convert they to macros using a translator program, so he/she may have access to macro benefits (faster execution speed, is there any other one?)
'
Once upon a time I try to convert functions to macros.
Realized I only had 8k per macro and some functions were too big and/or complex.

There are some misconception about the relation between function and macro.
Macros are as 'fast' as functions are 'clever'.
'Clever functions' 'provide logic' to macros and 'stupid macros' 'provide abstraction' to functions.

choosing between macro or function depends on situation.
macro eat memory, function save memory
macro is faster, function is slower
macro speed affected by environment size
function speed affected by file size
macro is limited, function is unlimited
etc..

Macro and function are related in such neither are superior but rather supplementary to one another.

Post Reply