I have written a macro function, and the following toy example shows my problem. So my problem is that my validation of arguments does not work. For example, I would like to check that:
- SomeMacroVariableArgument is 1 (My original function will take a macro variable argument and that's why I added it here to replicate my original example as much as possible).
- Boolean1 and Boolean2 are either 0 or 1.
Running this code:
%let TestVar = 1;
%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2); /minoperator mindelimiter=' ';
/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/
%if &TestVar. NE 1 or &Boolean1. not in (0 1) or &Boolean2. not in (0 1) %then %do;
%if &SomeMacroVariableArgument. NE 1 %then %do;
%put ERROR: This variable should be 1 ;
%end;
%if &Boolean1. not in (0 1) %then %do;
%put ERROR: Boolean1 should be 0 or 1 ;
%end;
%if &Boolean2. not in (0 1) %then %do;
%put ERROR: Boolean2 should be 0 or 1 ;
%end;
%put ERROR: Macro not executed due to invalid parameters ;
%end;
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
%else %do;
data MyData;
Argument1 = &Argument1.;
run;
%end;
%mend MyFun;
%put test = %MyFun(1,&Testvar. ,0,0); /* This yields an error message /*
The error message I got is:
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
&TestVar. NE 1 or &Boolean1. not in (0 1) or &Boolean2. not in (0 1)
ERROR: The macro MYFUN will stop executing.
What is the problem and how can I fix it? I believe it is clear that the purpose with the validation is to check that SomeMacroVariableArgument is 1 and
the Boolean1 and Boolean2 arguments are either 0 or 1.
Extra question 1:
When using the logical or, I assume it means that atleast one of the conditions is forfilled, not that just one of them is?
Extra question 2:
According to https://go.documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/p00iah2thp63bmn1lt20esag14lh.htm , the symbol for the logical NE depends on your computer. I could for instance use ^= or ~= instead of NE; how do I know which "my computer" uses?
All advice appreciated.
The macro processor does understand the IN operator, but not the NOT IN operator combination. You need to negate your conditions differently:
%let TestVar = 1;
%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2) /minoperator mindelimiter=' ';
/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/
%if &TestVar. NE 1 or not (&Boolean1. in (0 1)) or not (&Boolean2. in (0 1)) %then %do;
%if &SomeMacroVariableArgument. NE 1 %then %do;
%put ERROR: This variable should be 1 ;
%end;
%if not (&Boolean1. in (0 1)) %then %do;
%put ERROR: Boolean1 should be 0 or 1 ;
%end;
%if not (&Boolean2. in (0 1)) %then %do;
%put ERROR: Boolean2 should be 0 or 1 ;
%end;
%put ERROR: Macro not executed due to invalid parameters ;
%end;
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
%else %do;
data MyData;
Argument1 = &Argument1.;
run;
%end;
%mend MyFun;
%MyFun(1,&Testvar. ,0,0);
Since the macro generates data step code, do not use it in a %PUT statement, as the first semicolon created will terminate that %PUT, but the adjacent statement will not be recognized, as it becomes part of the %PUT.
The macro processor does understand the IN operator, but not the NOT IN operator combination. You need to negate your conditions differently:
%let TestVar = 1;
%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2) /minoperator mindelimiter=' ';
/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/
%if &TestVar. NE 1 or not (&Boolean1. in (0 1)) or not (&Boolean2. in (0 1)) %then %do;
%if &SomeMacroVariableArgument. NE 1 %then %do;
%put ERROR: This variable should be 1 ;
%end;
%if not (&Boolean1. in (0 1)) %then %do;
%put ERROR: Boolean1 should be 0 or 1 ;
%end;
%if not (&Boolean2. in (0 1)) %then %do;
%put ERROR: Boolean2 should be 0 or 1 ;
%end;
%put ERROR: Macro not executed due to invalid parameters ;
%end;
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
%else %do;
data MyData;
Argument1 = &Argument1.;
run;
%end;
%mend MyFun;
%MyFun(1,&Testvar. ,0,0);
Since the macro generates data step code, do not use it in a %PUT statement, as the first semicolon created will terminate that %PUT, but the adjacent statement will not be recognized, as it becomes part of the %PUT.
And the MINDELIMITER and MINOPERATOR options have to be part of the %MACRO statement, so there must not be a semicolon after the closing bracket of the macro parameters.
@SasStatistics wrote:
Is this not the case in the example code?
Quote from your post:
%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2); /minoperator mindelimiter=' ';
@SasStatistics wrote:
...
Extra question 2:
According to https://go.documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/p00iah2thp63bmn1lt20esag14lh.htm , the symbol for the logical NE depends on your computer. I could for instance use ^= or ~= instead of NE; how do I know which "my computer" uses?
Why not just use NE then you don't need to know.
Note that on a EBCDIC computer (IBM mainframe) the standard logical NOT symbol is ¬, which corresponds to EBCDIC code point X'5F'.
Just don't try to use <> as meaning NE because you will very surprised by the results. You can get away with it in SQL code (but why confuse yourself?).
You can always try it to see:
434 data test; 435 x1= 3 ne 2; 436 x2= 3 ^= 2; 437 x3= 3 ~= 2; 438 /* for ebcidic computers use the actual not symbol instead of ascii characters ~ or ^ */ 439 * But never do this ! ; 440 x4= 3 <> 2; NOTE: The "<>" operator is interpreted as "MAX". 441 x5= 3 >< 2; 442 put (x1-x5) (=); 443 run; x1=1 x2=1 x3=1 x4=3 x5=2 NOTE: The data set WORK.TEST has 1 observations and 5 variables.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.