BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
KevinViel
Pyrite | Level 9

Can a macro statement (%IF-%THEN, for instance) be a value of a macro parameter?  For instance, might I do something like:

 

, define_option = %nrstr( %%if &__i. > 1 and %%sysfunc( mod( &__i. , 4 ) = 1 %%then do page; )

 

I might not need the double %% signs, but it occurred to that the macro facility writes code, not macro.  This might be an example of when to nest a macro definition inside a macro, the elusive beast against which we were warned back in the heyday of SAS-L?

 

Thank you,

 

Kevin

 

1 ACCEPTED SOLUTION

Accepted Solutions
Quentin
Super User

Hey Kviel,

 

I'd say no.  The problem is that the macro statements need to be seen when the macro is compiled.  So if you try something like:

 

%macro foo
  (i=
  ,option =%nrstr( %if &i > 1 %then %put true; )
   );
  %unquote(&option)
%mend foo ;


%foo(i=2)

 

The %IF is not revealed until the macro foo is executing, so it's way too late for it to be used when foo is being compiled.  You get:

 

8    %foo(i=2)
ERROR: The %IF statement is not valid in open code.

[update: I guess if you're on 9.4M5 or later you might get a different result, cuz open statement %IF is now allowed, but it still wouldn't be what you want.]

 

Hard to see the big picture from what you've shared.  But I would stick with Master Ian's rule that nesting macro definitions is not a good idea.

 

--Q.

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.

View solution in original post

10 REPLIES 10
PaigeMiller
Diamond | Level 26

I think the answer to your question: Can a macro statement be a value of a macro parameter?" is clearly yes.

 

%let gender=F;
%let abc=%nrstr(%if &gender=F %then %put &gender;);
%put &=gender;
%put &=abc;

However, depending on what you are trying to do, this may not be the best way to achieve your goal.

--
Paige Miller
KevinViel
Pyrite | Level 9

Paige,

 

  Thank you for a prompt reply.  The distinction is that those are macro VARIABLES, where parameters pertain to the macro statement:

 

19 %macro test
20 ( parameter = %str()) ;
21
22 %let variable = 1 ;
23
24 data _null_ ;
25 %if %nrbquote(&parameter.) ne %str() %then &parameter. ;
26
27 %if &variable. = 1 %then put "The test is Good!" %str(;) ;
28 run ;
29
30 %mend test ;
31
32 %test ;
MPRINT(TEST): data _null_ ;
MPRINT(TEST): put "The test is Good!" ;
MPRINT(TEST): run ;

The test is Good!
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds

33
34
35 %test
36 ( parameter = %nrstr( %if &variable. = 1 %then put "All Good!" ; )) ;
MPRINT(TEST): data _null_ ;
NOTE: Line generated by the macro variable "PARAMETER".
36 %if &variable. = 1 %then put "All Good!" ;
_
2 The SAS System

180
MPRINT(TEST): %if &variable. = 1 %then put "All Good!" ;
MPRINT(TEST): put "The test is Good!" ;
MPRINT(TEST): run ;

ERROR 180-322: Statement is not valid or it is used out of proper order.

NOTE: The SAS System stopped processing this step because of errors.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds

 

 

 

Thank you,

 

Kevin

PaigeMiller
Diamond | Level 26

It's still not clear to me what you are trying to do, or why you need a macro command as the argument &parameter.

 

Nevertheless, this code seems to produce the desired output

 

%macro test(parameter = %str( )) ;
data _null_ ;
%if &parameter. ne %str( ) %then put "&parameter." %str(;);
%if &parameter. = 1 %then put "The test is Good!"%str(;);
run ;
%mend test ;

%test()

%test( parameter = 1)

PS: If you are going to paste a SAS log into your reply, please click on the {i} icon first and paste the log into the window that appears.

 

 

--
Paige Miller
Quentin
Super User

Hey Kviel,

 

I'd say no.  The problem is that the macro statements need to be seen when the macro is compiled.  So if you try something like:

 

%macro foo
  (i=
  ,option =%nrstr( %if &i > 1 %then %put true; )
   );
  %unquote(&option)
%mend foo ;


%foo(i=2)

 

The %IF is not revealed until the macro foo is executing, so it's way too late for it to be used when foo is being compiled.  You get:

 

8    %foo(i=2)
ERROR: The %IF statement is not valid in open code.

[update: I guess if you're on 9.4M5 or later you might get a different result, cuz open statement %IF is now allowed, but it still wouldn't be what you want.]

 

Hard to see the big picture from what you've shared.  But I would stick with Master Ian's rule that nesting macro definitions is not a good idea.

 

--Q.

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
KevinViel
Pyrite | Level 9

Quentin,

 

  Good to hear from you 🙂

 

  I surmised the same, but you said it so much more fluently.  I was thinking of a macro writing a macro, but it failed.  I got further with data _null_ and call execute(), but not far enough.  At least I pushed my SAS knowledge today.

 

Kind regards,

 

Kevin

Astounding
PROC Star
Even if you can get it to work, it sounds like there are better ways. As it stands now, the burden on the user is incredibly high. Why not use a simple parameter such as:

,n_per_page=4,

then put the burden on the programmer to make proper use of that parameter within the macro's logic.
KevinViel
Pyrite | Level 9

The burden is high but so would be the flexibility.  I use such an approach "successfully" for allow the SAS (as opposed to the Macro) language to be the value of macro parameters.  For instance, I might have:

 

&code.
output ;

 

and have macro parameter code have the value

 

code = if prxmatch( "/\.sas$/" , strip( pathfile )) then

/* For example */
MLOGIC(XXXX): Parameter CODE has value if prxmatch( "/\.sas$/i" , strip( pathfile )) then

It carries the same risk of allowing the programmers to program open SAS code, no?

 

Thank you,

 

Kevin

 

Astounding
PROC Star

Kevin,

 

I would expect the failure rate to be far too high, in two regards:

 

  • How many times does the user have to experiment to get it to work, and
  • Even if it works, can there be confidence that the results are correct.

 

I would try to mitigate the complications by using double resolution.  First, outside the macro have the user code something along these lines:

 

%let mvar = if prxmatch( "/\.sas$/i" , strip( pathfile ));

The user has a better chance of getting the code right by removing the macro complications.  Next, when calling the macro, use the name of the macro variable only:

 

%call_to_macro (code=mvar)

Finally, inside the macro get the code to resolve using:

 

&&&code

Hope this is helpful.

Tom
Super User Tom
Super User

Don't even think of doing that for real.

If you really need to you could have the macro generate a code file that defines macro and then execute the code file to define the macro.

%macro gen_macro(string);
filename code temp;
data _null_;
  file code ;
  put '%macro sub_macro;';
  length str $32767;
  str=dequote(symget('string'));
  put str;
  put '%mend sub_macro;';
run;
%include code;
%sub_macro;
%mend gen_macro;


%gen_macro('%if 1=1 %then %put found; %else %put not found; ');
PaigeMiller
Diamond | Level 26

@KevinViel wrote:


I might not need the double %% signs, but it occurred to that the macro facility writes code, not macro.  This might be an example of when to nest a macro definition inside a macro, the elusive beast against which we were warned back in the heyday of SAS-L?

 


The logic doesn't follow. Just because you can't get this to work, does not imply that macros nested inside of macros are the solution.

--
Paige Miller

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 10 replies
  • 1169 views
  • 8 likes
  • 5 in conversation