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

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. 


1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

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.

View solution in original post

5 REPLIES 5
Kurt_Bremser
Super User

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.

Kurt_Bremser
Super User

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
Pyrite | Level 9
Is this not the case in the example code?
Kurt_Bremser
Super User

@SasStatistics wrote:
Is this not the case in the example code?

Quote from your post:

%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2); /minoperator mindelimiter=' ';
Tom
Super User Tom
Super User

@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.

 

SAS Innovate 2025: Register Now

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!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 5 replies
  • 882 views
  • 7 likes
  • 3 in conversation