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
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.
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,
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(¶meter.) ne %str() %then ¶meter. ;
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
It's still not clear to me what you are trying to do, or why you need a macro command as the argument ¶meter.
Nevertheless, this code seems to produce the desired output
%macro test(parameter = %str( )) ;
data _null_ ;
%if ¶meter. ne %str( ) %then put "¶meter." %str(;);
%if ¶meter. = 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.
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.
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
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
Kevin,
I would expect the failure rate to be far too high, in two regards:
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.
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; ');
@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.
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
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.