BookmarkSubscribeRSS Feed
deleted_user
Not applicable
Hi,

I want to be able to call an action from within a macro loop. I'm not sure if this is possible?

%macro loop_vals(method,lval=g_dist,delim='*');
/*
lval is a string of variable values separated by *.
*/

%local i;
%local value;
%let i=1;
%let value=%scan(&lval,&i,&delim);
%if &value= %then %put ERROR- No values.;
%else &method;
%do %until(&value= );
%let i=%eval(&i+1);
%let value=%scan(&lval,&i,&delim);
&method;
%end;
%mend;

%let x=%str(%put &value);
%loop_vals(x)


Thanks
3 REPLIES 3
Cynthia_sas
SAS Super FREQ
Hi: what is the action that you want to call? Right now, X (which you set to %put value doesn't make sense).

Do you have some idea of what you want the final output of the macro to be?

Or, possibly you want to use CALL EXECUTE:
http://support.sas.com/kb/24/634.html
http://support.sas.com/kb/24/730.html
http://support.sas.com/kb/24/709.html
http://support.sas.com/kb/26/140.html

It's hard to visualize what your macro code is supposed to generate. Do you really want to execute a %put or is there some other statement or command or whole program that you want to invoke or execute? Why not just code the %put in the macro program? I don't get the point of scanning &LVAL and then using &METHOD -- you seem to do the same thing no matter what is in &LVAL. I would have expected some thing like this:

[pre]
%if &value = g_dist %then %do;
%put we want g_dist so we also must want something else;
%let other = wombat;
%end;
%else %if &value ne g_dist %then %do;
%put not g_dist ;
%let other = koala;
%end;
[/pre]
or something like this:
[pre]
%if &value = g_dist %then %do;
proc print data=sashelp.class;
title "value = g_dist";
run;
%end;
%else %if &value ne g_dist %then %do;
proc means data=sashelp.shoes min mean max;
title 'run proc means';
var sales;
run;
%end;
[/pre]

or...something requiring a call execute in a data step.

Also, as a best practice, it's probably best to avoid mixing positional parameters and keyword parameters...so I'd recommend against what you're showing because all the positional parameters have to appear, in the right order, before any of the keyword parameters.

If you review the output from the revised macro program below (which doesn't use &METHOD) you may get some idea of how the macro process is working, by reviewing the %PUT output in the log and looking at the titles for the proc print and the proc means output.

cynthia

[pre]
%macro loop_vals(lval=,delim=);
/*
lval is a string of variable values separated by *.
*/
%put inside macro *******;
%local i value;
%let i=1;

%let value=%scan(&lval,&i,&delim);
%if &value= %then %do;
%put ERROR- No values.;
%end;
%else %do;
%put @@@@@ i=&i value=&value do something for when i = 1;
proc print data=sashelp.class;
title "I=1 and value = &value";
run;
%end;
%do %until(&value= );
%let i=%eval(&i+1);
%let value=%scan(&lval,&i,&delim);

%if &value = kangaroo %then %do;
%put ***** inside do until: i=&i value=&value do something else for i ne 1;
%put ***** but ONLY do something if the value 'kangaroo' is in the LVAL list;
proc means data=sashelp.shoes min mean max;
var sales;
title "I= &i and value= &value";
run;
%end;
%if &value ne kangaroo %then %do;
%put --------> I= &i and value= &value NO PROC MEANS;
%end;
%end;
%mend;

ods listing;

options nosymbolgen nomprint nomlogic;
%loop_vals(lval=wombat#koala#kangaroo, delim='#');

%loop_vals(lval=kermit*gonzo*elmo, delim='*');
[/pre]
deleted_user
Not applicable
Hi Cynthia,

Thanks for the quick response. I'm new to SAS and just trying to work my way around this macro stuff so appologies for not being clear.

Using the following loop I can print each of the values in g_dist. So I get in the log:
tt
ee
ff

As I wasn't sure about what you can and can't do with loops, I was testing the waters to see if there was a way to pass it macro code as a parameter. As there are lots of instances where I would need to use a loop. Is there a way that I could have passed the "%put &value" as a parameter, or a call to another macro. Such as "%sms_output(&value,U:\FAVORITES\challenge);" and have it substitute the line underlined in the code? Just seeing if it's possible.

Thanks


%let g_dist=tt*ee*ff;

%macro loop_vals(lval=&g_dist,delim='*');
/*
lval is a string of variable values separated by *.
*/

%local i value;
%let i=1;
%if &value= %then %put ERROR- No values.;
%let value=%scan(&lval,&i,&delim);
%do %while(&value^= );
%put &value;
%let i=%eval(&i+1);
%let value=%scan(&lval,&i,&delim);
%end;

%mend loop_vals;
Cynthia_sas
SAS Super FREQ
Hi:
I like to call the SAS Macro facility a big typewriter. The purpose of the Macro facility is to generate code -- either entire steps, entire statements, or just parts of statements. And to generate that code conditionally, if you need to. You can invoke other macro programs conditionally, too. But, you have to have a fairly good knowledge of macro processing to put together an entire system of macro programs that are interdependent and work together.

My general rules for creating macro programs is to start by reading the documentation and working through some examples. You can do just about anything inside a Macro do loop .. you could generate a list of variable names for a KEEP statement:
[pre]
KEEP %lstvars ;
[/pre]
could generate:
[pre]
KEEP var1 var2 var3 var4 var5 var6 ;
[/pre]
OR, you could generate WHOLE steps of code:
[pre]
%makeprt(numfile=3);
[/pre]
could generate (with a %do loop):
[pre]
proc print data=file1; run;

proc print data=file2; run;

proc print data=file3; run;
[/pre]

Are there ways to do what you want? Yes. If you have read the Macro Facility reference guide and examples, you should be able to see how to do it. However, I would not, generally, design a macro program where the call to one macro program included a parameter that was a call to another macro program. My tendency would be to do something like this:

[pre]
%macro whichone;

*** TEST macro variable &value;
*** put some routine here to break apart &value;
*** into &tmpval1, &tmpval2, &tmpval3, etc ;
*** and set valcnt to hold the total count of what was passed;
*** or 0 if nothing was passed;
*** I show a simple do loop for easier understanding;

%if &valcnt gt 0 %then %do;
%do i = 1 %to &valcnt;
%sms_output(parm1=&&tmpval&i,parm2=U:\FAVORITES\challenge);
%end;
%end;
%else %do;
%other(parm1=fred,parm2=c:\temp\test);
%end;
%mend whichone;
[/pre]

And then %whichone where valcnt was gt 0 would invoke the %sms_output macro program however many times the loop iterated and %whichone where valcnt was 0 would invoke the %other macro program only once. Can you make this more complicated? Yes. Could you pass the macro name to invoke as a parameter? Yes. Is that more complicated? Yes. Does that involve understanding macro processing really well? Yes. How do you get to understand the macro facility and macro processing really well -- by reading the macro documentation, reading user papers about macro processing and applications they've written and by going to Tech Support for help.

The forum is a great place to get quick answers. You have a very specific need and there's a HUGE difference between using a %DO loop to generate a list of variables for a KEEP statement and using a %DO loop to invoke another macro program. For one thing, you could have scope issues between the GLOBAL and LOCAL symbol tables. For another thing -- you absolutely must make sure that all your other macro programs -- the ones whose names you want to pass dynamically -- all work, work absolutely correctly for all conditions and do not have ANY errors.

If you are working in the Pharmaceutical industry or for a CRO, your company probably has a library of macro programs and processes that are already in place. There's a good chance that someone at your site has some documentation for how your company's macro programs need to be coded to meet validation standards. Writing macro programs for clinical trials and drug submissions is different than writing a macro program to do a %put. After you read the SAS Macro Facility documentation, be sure to investigate your internal company resources on the topic of how your company's macro programs should be written.

cynthia

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

New Learning Events in April

 

Join us for two new fee-based courses: Administrative Healthcare Data and SAS via Live Web Monday-Thursday, April 24-27 from 1:00 to 4:30 PM ET each day. And Administrative Healthcare Data and SAS: Hands-On Programming Workshop via Live Web on Friday, April 28 from 9:00 AM to 5:00 PM ET.

LEARN MORE

Discussion stats
  • 3 replies
  • 944 views
  • 0 likes
  • 2 in conversation