Page 1 of 2

create macro: Let's create a small handout with reports .

Posted: 02 May 2023 06:20
by einstein1969
I'm going crazy creating macros and I ask you for help starting from simple examples.

If you have links that summarize I would like to know them.

I searched the forum and came across threads that always took for granted something that was too big for my mental capacity.

I need to optimize a script to run as fast as possible. A very good way is to create a code that creates other static code with calculations prepared beforehand.
But I still want to leave some calculations without necessarily pushing this method to the maximum. So I have code that needs to be executed differently depending on certain values.
Instead of using "IF" commands I wanted to create macros to insert into the code using the percent expansion "%" and the trick of eliminating the macro from the environment to perform "set" calculations as quickly as possible.

Request:

1) What changes do I need to make to achieve my goal?
2) for complex code should I use the LF trick? Can I avoid this by putting all the code on one line? What advantages are there?
3) what other precautions should I take into account to use both variables expanded by the "%" and delayed variables "!" at the time of execution of the macro?
4) Can I also use "%" and delayed expansions in the macro definition?
5) When executing the macro, can I use additional "%" and delayed "!" expansions?

This is the schematic of the code to transform/complete:

Code: Select all

@echo off

setlocal EnabledelayedExpansion

For /L %%L in () do (

	rem create macro for faster execution

	if !condition! equ 1 (
		rem create macro1
		set "macro1=definition1"
	) else (
		set "macro1=definition2"
	)
	call :sub1
)

goto :eof

:sub1

(

	set macro1=

	For /L %%M in () do (
		rem execute macro1
		%macro1%
	)

)

goto :eof
example of macro1:

Code: Select all

for %%G in (!var!) do (
	  	set "array[%%G]=!array[%%G]!!var2!"
	  	set "array2[%%G]=!array2[%%G]!!var2!"
	  )
or:

Code: Select all

for /L %%G in (1,1,!var2!) do echo %CHAR%!array[%%G]!
How should I define these macros?

EDIT: correct an error on code "else"

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 07:54
by T3RRY
For arithmetic macro's, it's rather practical to define an array of sums that can be indexed using one or more "key" variables, expanding the relevant macro using the current value of the given "key" String/s expanded using a for /f string loop if needed.
Think of it as using lookup values to enact the correct macro for the current State without having to perform any conditional tests.

This isn't the simplest example, but it shows a simple use case. It's an extract from the Game engine I'm working on with icarus and yeshi.

Code: Select all

REM Vectors
	Set "South="1/(Object.Y-Object.maxY)","Object.Y=Object.Y %% Object.maxY + 1""
	Set "East="1/(Object.X-Object.MaxX)","Object.X=Object.X %% Object.MaxX + 1""
	Set "West="1/(Object.X-1)","Object.X=((Object.X - Object.MaxX) %% Object.MaxX) + (Object.MaxX-1)""
	Set "North="1/(Object.Y-1)","Object.Y=((Object.Y - Object.maxY) %% Object.maxY) + (Object.maxY-1)""

	Set "SouthWest="1/(Object.Y-Object.MaxY)","1/(Object.X-1)","Object.Y=Object.Y %% Object.MaxY + 1","Object.X=((Object.X - Object.MaxX) %% Object.MaxX) + (Object.MaxX-1)""
	Set "NorthWest="1/(Object.Y-1)","1/(Object.X-1)","Object.Y=((Object.Y - Object.MaxY) %% Object.MaxY) + (Object.MaxY-1)","Object.X=((Object.X - Object.MaxX) %% Object.MaxX) + (Object.MaxX-1)""
	Set "NorthEast="1/(Object.Y-1)","1/(Object.X-Object.MaxX)","Object.Y=((Object.Y - Object.MaxY) %% Object.MaxY) + (Object.MaxY-1)","Object.X=Object.X %% Object.MaxX + 1""
	Set "SouthEast="1/(Object.Y-Object.MaxY)","1/(Object.X-Object.MaxX)","Object.Y=Object.Y %% Object.MaxY + 1","Object.X=Object.X %% Object.MaxX + 1""

When iterating through a list of Acive objects
the array allows the movement of any Object, "%%O", using:

Code: Select all

	For %%v in ("!%%O.Vector!")Do Set /A "!%%~v:Object=%%O!" 2>nul
Without having to perform any traditional conditional tests, we just expand the macro for the movement rule substituting the variable name to apply it to.
Movement restrictions are embedded in the leading part of the sum that attempt to provoke divide by zero errors so that no change to the position occurs if the move is invalid.

This of course can be expanded to apply different calculations by having multiple index values to expand the appropriate Sum for more complex situations.

IE:

Code: Select all

For /F "tokens=1,2" %%i in ("!Var1!" "!Var2!")Do Set /A "!Macroname[%%i][%%j]!" 2>nul 
expanding the array with the inxdices that match whatever Var1 and Var2's current values are.

Because it Does away with the outer for loop, this method is better performing than the traditional use of:

Code: Select all

For %%n in (1 2)Do If %%n==2 (
    For /f "Tokens=1,2 Delims=, " %%i in ("!Args!")Do (
        REM Set /A sum
    )
)Else Set Args=

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 08:02
by einstein1969
T3RRY wrote:
02 May 2023 07:54
For arithmetic macro's, it's rather practical to define an array of sums that can be indexed using one or more "key" variables, expanding the relevant macro using the current value of the given "key" String/s expanded using a for /f string loop if needed.
Think of it as using lookup values to enact the correct macro for the current State without having to perform any conditional tests.
Unfortunately English is not my mother tongue, I tried to translate but I did not understand how you mean. Can you give an example?

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 08:43
by T3RRY
einstein1969 wrote:
02 May 2023 08:02
T3RRY wrote:
02 May 2023 07:54
For arithmetic macro's, it's rather practical to define an array of sums that can be indexed using one or more "key" variables, expanding the relevant macro using the current value of the given "key" String/s expanded using a for /f string loop if needed.
Think of it as using lookup values to enact the correct macro for the current State without having to perform any conditional tests.
Unfortunately English is not my mother tongue, I tried to translate but I did not understand how you mean. Can you give an example?
to elaborate on the previous example.

We can use numbers or strings as references or indexes when expanding variables, which is the typical way of implementing "Arrays" in batch.
IE:
"item[1]=value"

these indexes or strings of course do not have to be hard coded in the expansion of the value, as we all know when iterating through such arrays with for /l

Specifically for Macro arithmetic using Set /A, We can also expand from arrays using the values of other variables using for /F.

For a more complex situation, consider an example where you only want to apply a given equation for specific combinations of 3 values without having to do an overly complex If else nest, you can predefine that equation to an array at indices that match those values and reduce all logic to:

Code: Select all

For /f "tokens=1,2,3" %%v in ("!var1! !Var2! Var3!!")Do (
    If not "!Equation[%%v][%%u][%%t]!"=="" Set /A "!Equation[%%v][%%u][%%t]!"
)

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 09:03
by T3RRY
To focus more on the points of your question:

2) for complex code should I use the LF trick? Can I avoid this by putting all the code on one line? What advantages are there?

It can help readability of complex macro's.

3) what other precautions should I take into account to use both variables expanded by the "%" and delayed variables "!" at the time of execution of the macro?
%variables% included in the definition of the macro will have a permanent, fixed value.
!Variables! will be defined into the macro at the definition stage if the environment state is EnableDelayedexpansion at te of definition.
The precautions you take will depend on the presence of any poison characters. In most cases Quoting variable assignments is sufficient, but if relying on user input it's worth sanitizing any input prior to definition

4) Can I also use "%" and delayed expansions in the macro definition?
yes. You can also additional for loops to expand variables to greater degrees if needed.
If doing so, try and use a sigle for /f loop with whatever tokens required just the once.

5) When executing the macro, can I use additional "%" and delayed "!" expansions?
You can capture arguments into the macro or embed delayed variables within

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 14:14
by einstein1969
Thanks T3rry , you put many interesting things, I'm reading calmly because 'I have to digest a lot.

The trick of the objects you put at the beginning is really cool. 8)

I'll see if among the things you mentioned I find something that fits my work.

But for the moment I expand my example to include macros that interest me. Very simple.

The first problem I encounter in the definition of macros are the double quotes, the expansion of variables I can not see anything.

Try this code.

Code: Select all

@echo off

setlocal EnabledelayedExpansion

set var1=5
set Char=A

For /L %%L in () do (

	rem create macro for faster execution

	if !var1! gtr 5 (
		rem create macro1
		
		set "macro1=for /L %%G in (1,1,%var1%) do set "e[%%G]=!e[%%G]!%Char%123""
	) else (
		set "macro1=set "e=!e!%Char%123""
	)
	call :sub1
)

goto :eof

:sub1

(

	set macro1=

	For /L %%M in () do (
		rem execute macro1
		echo [%macro1%]
	)

)

goto :eof
EDIT : I have used echo [%macro1%] in the sub1 loop but intend %macro1%
EDIT2: fixed an error on code

Re: create macro: Let's create a small handout with reports .

Posted: 02 May 2023 22:31
by Aacini
Mmmm... you were not clear enough in your request. I'm afraid I don't follow you... Your descriptions are very theoretical, not practical...

You said "I need to optimize a script to run as fast as possible". Why don't just post an example of the (type of) script you want to optimize? This way we could clearly see what type of optimizations could be applied to such a code. However, there are a couple comments I want to state about this point.
  • A macro is not faster than the same code directly written in the script; in other words: a macro is not a method to write faster code. A macro is useful when there is a code segment that is used several times in a script (similar to a subroutine). A macro is faster than the same code written as subroutine an invoked via call :Subroutine
  • If you want to write conditional execution whitout use "IF" command, then there are several tricks that can be used in arithmetic expressions. The simplest one is use an array of different expressions and select the desired one via a subscript. Another method is described at this thread. If you want to do the same over non-arithmetic results, then you should clearly describe the desired results based on which inputs and/or show several examples.
  • At this thread another method to write arithmetic macros with changing values is described...
  • You can combine "%" and "!" expansion in the same "macro" definition in an advanced way that allows you to get useful results when process lists of elements. You can read a detailed description and extensive examples of this method here.
Sorry, but I can't help you to "achieve your goal" if I don't understand what such a goal is.

I hope this helps...

Antonio

Re: create macro: Let's create a small handout with reports .

Posted: 03 May 2023 09:30
by einstein1969
Hi Antonio,

Yes you are right it's very theoretical and impractical, but is an extract of the code.

Now I will try to explain myself better. This is the code that I have to optimize summarized to the bone. And the problem I face is writing macros.

I'm no expert in writing code that needs to be treated with escapes.

Let's say this is an excerpt of what I need to improve.

Code: Select all

@echo on

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B
set Accumulator[1]=B

For /L %%L in () do (

	rem calculate var1
	set var1=!time:~-1!
	call :sub1
)

goto :eof

:sub1

(
	For /L %%M in (1,1,5) do (
		
		if !var1! gtr 5 (
			for /L %%G in (1,1,%var1%) do set "Accumulator[%%G]=!Accumulator[%%G]!.%Char%.123"
		) else 	set "Accumulator=!Accumulator!.%Char%.123"

	)

)

goto :eof
To optimize the code I have to write a macro in the starting loop to be used in subprocedure sub1

thus:

Code: Select all

@echo on

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B
set Accumulator[1]=B

For /L %%L in () do (

	rem calculate var1
	set var1=!time:~-1!

	if !var1! gtr 5 (
		set "macro=for /L %%G in (1,1,%var1%) do set "Accumulator[%%G]=!Accumulator[%%G]!.%Char%.123""
	) else 	set "macro=set "Accumulator=!Accumulator!.%Char%.123""

	call :sub1
)

goto :eof

:sub1

(
        set macro=
	For /L %%M in (1,1,5) do (
		
			%macro%

	)

)

goto :eof
What I needed to understand is how to write the macro.

For example, if I have to deal with double quotation marks with caret^, if for example I can use delayed expansion or not.
If I have to resort to LF in case of macros with more commands or I can concatenate them with &. If the & should be treated with caret etc.

Re: create macro: Let's create a small handout with reports .

Posted: 03 May 2023 11:10
by T3RRY
einstein1969 wrote:
03 May 2023 09:30
Hi Antonio,

Yes you are right it's very theoretical and impractical, but' an extract of the code.

Now I will try to explain myself better. This is the code that I have to optimize summarized to the bone. And the problem I face is writing macros.

I'm no expert in writing code that needs to be treated with escapes.

Let's say this is an excerpt of what I need to improve.

Code: Select all

@echo on

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B
set Accumulator[1]=B

For /L %%L in () do (

	rem calculate var1
	set var1=!time:~-1!
	call :sub1
)

goto :eof

:sub1

(
	For /L %%M in (1,1,5) do (
		
		if !var1! gtr 5 (
			for /L %%G in (1,1,%var1%) do set "Accumulator[%%G]=!Accumulator[%%G]!.%Char%.123"
		) else 	set "Accumulator=!Accumulator!.%Char%.123"

	)

)

goto :eof
To optimize the code I have to write a macro in the starting loop to be used in subprocedure sub1

thus:

Code: Select all

@echo on

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B
set Accumulator[1]=B

For /L %%L in () do (

	rem calculate var1
	set var1=!time:~-1!

	if !var1! gtr 5 (
		set "macro=for /L %%G in (1,1,%var1%) do set "Accumulator[%%G]=!Accumulator[%%G]!.%Char%.123""
	) else 	set "macro=set "Accumulator=!Accumulator!.%Char%.123""

	call :sub1
)

goto :eof

:sub1

(
        set macro=
	For /L %%M in (1,1,5) do (
		
			%macro%

	)

)

goto :eof
What I needed to understand is how to write the macro.

For example, if I have to deal with double quotation marks with caret^, if for example I can use delayed expansion or not.
If I have to resort to LF in case of macros with more commands or I can concatenate them with &. If the & should be treated with caret etc.
Escaping rules change a bit with double quotes, but what your trying to do is possible.

In the below example, I've modified the definition of the For version of the macro to demonstrate that you may embed metavariables into the macro that can be expanded upon execution

Code: Select all

@echo off

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B

(
	rem calculate var1
	set var1=!time:~-1!
	if !var1! gtr 5 (
		set "macro=for /L %%G in (1,1,!var1!) do (set "Accumulator[%%G]=^^^!Accumulator[%%M]^^^!.%Char%.123"&Echo(^!Accumulator[%%G]^!)"
	) else (
		set "macro=set Accumulator=^!Accumulator^!.%Char%.123^&Echo(^!Accumulator^!"
	)

	call :sub1
)

goto :eof

:sub1

(
      set macro=

	For /L %%M in (1,1,5) do (
		
			%macro%

	)

)

goto :eof

Re: create macro: Let's create a small handout with reports .

Posted: 04 May 2023 04:21
by einstein1969
Thanks T3rry but I don't understand the rules.

I did a test with only two escape characters "^^" before the exclamation mark "!" and gives me the same result.So you need 3 or 2 when in double quote ' " ' ?

this seems to work:

Code: Select all

@echo off

setlocal EnabledelayedExpansion

set Char=A
set Accumulator=B

(
	rem calculate var1
	set var1=!time:~-1!
	if !var1! gtr 5 (
		set "macro=for /L %%G in (1,1,!var1!) do (set "Accumulator[%%G]=^^!Accumulator[%%M]^^!.%Char%.123"&Echo(^!Accumulator[%%G]^!)"
	) else (
		set "macro=set Accumulator=^!Accumulator^!.%Char%.123^&Echo(^!Accumulator^!"
	)

	call :sub1
)

goto :eof

:sub1

(
      set macro=

	For /L %%M in (1,1,5) do (
		
			%macro%
pause
	)

)

goto :eof
@jeb or @aacini or @dbenham:
If you read you are strong with these things, can you tell me something about it?

Re: create macro: Let's create a small handout with reports .

Posted: 04 May 2023 06:56
by Aacini
I think you are not clear enough about what you really want...

What do you want?
  1. Learn about macros? You can read the several posts here about this topic, modify the examples in order to understand how such a feature work and then, when you find a specific point you have problems with, post your non-working code, specify what you want and the problem you have. I think that in this case we could help you to fix your specific problem.
  2. Optimize a code? You can post your working code (describing the results it produce) and request help in order to optimize such working code. Perhaps the optimization process have no relation with "macros"... Or perhaps yes. Who knows? There are a lot of different programs that can be optimized via different methods. How we could know if we don't see the pre-optimized working code?
Your question, as currently stated, is something like: "I have a program that I want to optimize. I suppose it can be optimized via a macro. However, because I don't know macros enough, I can't show you what exactly is my problem. Could you help me?" :(

Re: create macro: Let's create a small handout with reports .

Posted: 04 May 2023 11:28
by einstein1969
Learn about macros? You can read the several posts here about this topic, modify the examples in order to understand how such a feature work and then, when you find a specific point you have problems with, post your non-working code, specify what you want and the problem you have. I think that in this case we could help you to fix your specific problem.
Yes, I want learn about macro.

Can you tell me where to read something about it? As I said above I did not find anything simple. But I can do as you said. If you give me some simple links even outside the forum example on stackoverflow.

Re: create macro: Let's create a small handout with reports .

Posted: 05 May 2023 00:15
by jeb
Currently there is no "ONE" simple guide with the "state of the art" techniques.

You have to read many posts and none of them use the latest development state

Macros with parameters appended
viewtopic.php?f=3&t=2518
But take post #4 for the better definition
viewtopic.php?f=3&t=2518#p11362

In the same thread: Good macro explanation by Aacini
viewtopic.php?f=3&t=2518#p12045

Later there was an important change for the \n definition
The \n value used to create multi-line macros can be greatly simplified
viewtopic.php?f=3&t=2518&start=15#p57692

Probably this will help when you create bigger macros
Comments without increasing macro size
viewtopic.php?f=3&t=5374

Avoid problems in the definition phase by reading
FOR variable %%A in macro definition gets overridden when script is called by other script within FOR loop
viewtopic.php?f=3&t=9721&p=62580

For some (complex) samples you could look at
https://github.com/jeb-de/BatchLibrary

Somewhere on dostips, I described a technique to define a macro independent of the delayed expansion mode, but I can't find it anymore
It's part of the batchLibrary: https://github.com/jeb-de/BatchLibrary/ ... e.cmd#L238

Re: create macro: Let's create a small handout with reports .

Posted: 05 May 2023 07:07
by miskox
2jeb: thank you for this looong post of useful links. I will take a look at them too. I am having troubles understanding macros aswell. Will check them. I think it is time for me to try and use them.

Saso

Re: create macro: Let's create a small handout with reports .

Posted: 06 May 2023 02:17
by einstein1969
@jeb

Thanks for the links, I'm looking at them.

But I wanted to ask you a question. What is your method that you use and have you used to discover the various ways to create macros. An example is enough for me.

Then I wanted to ask you why when there are quotation marks you need two ^ carets. Also why does it work with 3 ^ caret too?. see the example that t3rry did.