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.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.