I have a macro which needs to validate keyword parameters against a list. The code below distills the issue (the actual macro is much more complex).
%MACRO CONVERTOR (CONVERSION_TYPE = );
%IF &CONVERSION_TYPE IN (MILES_TO_METERS,MILES_TO_FEET) %THEN %DO;
%LET ORIGINAL_UNIT = MILES;
%END;
%MEND;
%CONVERTOR (CONVERSION_TYPE = MILES_TO_METERS);
Executing this yields the following error in the log:
ERROR: Required operator not found in expression: &CONVERSION IN (MILES_TO_METERS,MILES_TO_FEET)
Could someone please point out the correct way to do this? It seems that SAS doesn't allow the IN operator within a macro code?
Trying to us IN as an operator in macro code is tricky, and probably not worth it. If you do want to use it then make sure to tell the macro compiler that you want to use it and what character to use as the delimiter. It is generally a bad idea to use a comma as a delimiter in macro code as it can cause trouble when trying to pass values into macro functions (or macro calls) since comma is used as the delimiter between arguments (parameters).
%macro convertor(conversion_type) / minoperator mindelimiter='|';
%local original_unit ;
%if &conversion_type in miles_to_meters|miles_to_feet %then %do;
%let original_unit = %scan(&conversion_type,1,_);
%end;
%else %put WARNING: Conversion_type not recognized. &=conversion_type;
%put &=conversion_type &=original_unit ;
%mend;
%convertor(conversion_type = miles_to_meters);
%convertor(conversion_type = pounds_to_dollars);
Try using
*macro IN operator; options minoperator mindelimiter=',';
specify the correct delimiter
Historically IN was not a macro operation, but it was added at some point in the last decade. For backward compatibility the old functionality remains and you have to specify the options. I think you may also need a space between the words? Or at least it helps to make it legible and easier to debug.
I find it easiest to
1) Set options permanently as suggested by @novinosrin
2) Set it specifically for each macro to avoid unexpected behaviour.
I also like to add an %ELSE and %PUT to my tests to make it clear where my logic is failing.
%MACRO CONVERTOR (CONVERSION_TYPE = ) / minoperator mindelimiter=',';
%IF &CONVERSION_TYPE IN (MILES_TO_METERS, MILES_TO_FEET) %THEN %DO;
%PUT ORIGINAL_UNIT = MILES;
%END;
%ELSE %PUT Logic failed;
%MEND;
%CONVERTOR (CONVERSION_TYPE = MILES_TO_METERS);
In addition to specifying the two options ...
Off the top of my head and untested ...
Do NOT use parentheses around the list of values.
Do NOT add a space on either side of the delimiter.
Trying to us IN as an operator in macro code is tricky, and probably not worth it. If you do want to use it then make sure to tell the macro compiler that you want to use it and what character to use as the delimiter. It is generally a bad idea to use a comma as a delimiter in macro code as it can cause trouble when trying to pass values into macro functions (or macro calls) since comma is used as the delimiter between arguments (parameters).
%macro convertor(conversion_type) / minoperator mindelimiter='|';
%local original_unit ;
%if &conversion_type in miles_to_meters|miles_to_feet %then %do;
%let original_unit = %scan(&conversion_type,1,_);
%end;
%else %put WARNING: Conversion_type not recognized. &=conversion_type;
%put &=conversion_type &=original_unit ;
%mend;
%convertor(conversion_type = miles_to_meters);
%convertor(conversion_type = pounds_to_dollars);
See if https://github.com/scottbass/SAS/blob/master/Macro/parmv.sas meets your needs.
Or, if not, perhaps you can use it as a starting point for your own generic macro parameter validation macro.
Thank you all for responding.
In light of the added complexity, I'll just use the OR operator ....but it's good to know how properly use the IN() operator if needed in the future! A requirement of this particular macro is maintainability by "non SAS experts" hence it would be inappropriate to rely on options or other such dependencies.
%MACRO CONVERTOR (CONVERSION_TYPE = );
%IF &CONVERSION_TYPE = MILES_TO_METERS OR &CONVERSION_TYPE = MILES_TO_FEET %THEN %DO;
%LET ORIGINAL_UNIT = MILES;
%END;
%MEND;
%CONVERTOR (CONVERSION_TYPE = MILES_TO_METERS);
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.