Hello,
I'm trying to execute a macro in a do loop and am stuck. I'm new to macros and I know there are a lot of problems with my code!
Please go easy on me and in your correction, assume my knowledge is already limited so I might not understand everything you say at first.
Here's a sample macro that works fine on its own:
/*the macro*/
%macro calc(n, i);
data power_calc;
result = &n**&i;
run;
%mend;
Here's the looping macro I wrote to execute %calc:
%macro loop(n, start, end);
%do i=&start %to &end;
%calc(n=&n, i=&i);
%end;
%mend;
Here's the call to the looping macro:
%let n = 2;
%let start = 1;
%let end = 4;
%loop(start = &start, end = &end);
Here are the error messages where I can see that the call to %calc is not resolving
NOTE: Line generated by the invoked macro "CALC".
1 result = &n**&i;
------
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
NOTE: Line generated by the invoked macro "LOOP".
9 Â Â %calc(n=&n, i=&i) Â Â
----
217
ERROR 217-322: Invalid statement due to first character being unprintable (hexadecimal representation: C2A0C2A0).
You didn't give the argument N a value in this line
%loop(start = &start, end = &end)
and so when %loop executes, N has no value and the code fails.
Its the same as typing
%loop(start = &start, end = &end, n=);
and so again argument N has no value. I leave it up to you to figure out what value to place after N= in the above statement.
Sorry. I pasted a version of the code that didn't have the &n argument in the call. I fixed this at one point and still get the same error messages.
The call in the code was:
%let n = 2;
%let start = 1;
%let end = 4;
%loop(n = &n, start = &start, end = &end);
And the error messages are the same:
NOTE: Line generated by the invoked macro "CALC".
1 result = &n**&i;
------
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
NOTE: Line generated by the invoked macro "LOOP".
9 Â Â %calc(n=&n, i=&i) Â Â
----
217
ERROR 217-322: Invalid statement due to first character being unprintable (hexadecimal representation: C2A0C2A0).
Using
%let n = 2;
%let start = 1;
%let end = 4;
%loop(n = &n, start = &start, end = &end)
everything works for me.
Since it is not working for you, please turn on the macro debugging options by running this line of code
options mprint;
and then run your code again and show us the ENTIRE log (every single line, every single character, not just the error messages) by copying the log as text and then pasting it into the window that appears when you click on the </> icon. DO NOT SKIP THESE INSTRUCTIONS.
That macro %CALC() is not something you would call in that way (unless all you wanted was to write some stuff to the SAS log) because it always writes the same dataset, POWER_CALC. So after the looping only the results of the last call will still exist.
Perhaps your real macro is more complex and that is the problem?
@abaker_ca wrote:
Do you know how I should call %calc() so that it writes out each iteration?
It is not about how you call it but what it is doing.
If you can change the macro then make it create a different dataset each time.
%macro calc(n, i);
data power_calc_&n_&i;
result = &n**&i;
run;
%mend;
Or perhaps append an observation to a fixed dataset. But in that case the dataset needs more variables.
%macro calc(n, i);
data next;
n=&n;
i=&i;
result = n**i;
run;
proc append data=next base=power_calc force;
run;
%mend;
If you cannot change the %CALC() macro the add the extra logic inside your looping macro.
%calc(&n,&i);
data next;
n=&n;
i=&i;
set power_calc;
run;
proc append data=next base=all_power_calc force;
run;
Unfortunately, none of the examples you've given work with the do loop macro. Although they are good examples of a better way to write the original %calc macro.
My issue is that I have an analysis where I will have to execute the macro I've written about 30 times and then append all the output together.
I'd prefer not to have to type out the call to the macro that many times!
But I just can't figure out how to execute it within a do-loop.
Perhaps the do loop should be in the macro itself.....
That is what the third example is for. I just did not write out the looping code as you already had that.
So I could put a do loop in the 3rd example?
You should be able to just add the extra steps after the call to the %calc macro in your existing %DO loop you shared before.
If the actual output of %calc() has enough variables to distinguish the the input N and I values you don't need to extra data step to add those variables.
I hate to ask you to do all the heavy lifting for me but I truly don't know enough SAS to put this all together.
If I could add the extra steps in the %do loop, what would that look like?
I've been laboring over this for a while and haven't figured it out on my own so I'd appreciate a complete set of code where the %calc is called in the %do that I can execute.
I just need one working example so I can pick it apart and hopefully understand the logic.
The solution worked!
Thank you so much. I'm going to see if I can use this general approach to my programming from now on.
Alice
Don't use the same macro variables over to avoid confusion (e.g. i)
%macro calc(n, i);
data power_calc&i.;
result = &n**&i;
iteration = &i.;
run;
%mend;
%macro loop(n, start, end);
%do j=&start %to &end;
%calc(n=&n, i=&j);
%end;
%mend;
%let n = 2;
%let start = 1;
%let end = 4;
%loop(n=&n, start = &start, end = &end);
data want;
set power_calc1-power_calc&end.;
run;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.
Find more tutorials on the SAS Users YouTube channel.