Hello @mansour_ib_sas,
When CATX is called for the first time (by %SYSFUNC), macro variable F contains only a blank, which is regarded equal to a null (i.e. empty) value in macro variable comparisons because trailing blanks are ignored. It appears to me that this lack of "character contents" triggers the %SYSEVALF function to evaluate &F numerically. After all, the CATX function does not only concatenate character strings, but also numeric arguments (which are converted to a character string, but only after evaluation), so &F could very well be a numeric expression which might contain non-integer operands and hence would need evaluation by %SYSEVALF. Calling %SYSEVALF with an empty argument, however, results in the error message you've reported (try %let x=%sysevalf();).
To avoid the error message you could apply %IF/%THEN logic to start with CATX calls only after F has been populated with the first "word" of the character string in macro variable A. However, I would recommend to perform the concatenation in the form
%let f=&f "%scan(&a,&i,%str( ))";
because this is simpler and doesn't require CATX at all (hence the error message cannot occur).
Note that I replaced your single blank in single quotes (' ') by %str( ) because those single quotes in a %SYSFUNC call would be interpreted as ordinary characters, here: delimiters, which is probably not what you intended. (So, please do the same in your COUNTW call.) Also, the initialization of macro variable F can be simplified to %let f=;.
There is no need to use the CAT... functions to concatenate macro variables. Just expand the values where you want them and they will automatically be concatenated. If you want something like a space between the values the just do:
%let f=&f "%scan(&a,&i,%str( ))";
So if F is already empty the leading space before the quote will be ignored by the %LET.
If you need to something other than space as the delimiter you might need to take special care to not add one in the front.
You could start your loop at 2.
%let f="%scan(&a,1,%str( ))";
%do i=2 %to ....
You could test and treat the first value differently.
What I like to do for this "catx" type structure is use a different macro variable to contain the separation character (string) and set it empty to start and then set it after the first "concatenation". Then no need for %IF logic.
For example to make a comma separated list.
%let f=;
%let sep=;
%do i=1 %to %sysfunc(countw(&a,%str( )));
%let f=&f.&sep."%scan(&a,&i,%str( ))";
%let sep=,;
%end;
Now it's good. Thank you for your pertinents comments
%macro tt();
%global f;
%let a=001-001 001-002;
%let f=;
%do i=1 %to %sysfunc(countw(&a.,%str( )));
%let f=&f. "%scan(&a.,&i,%str( ))" ;
%end;
%mend;
%tt;
%put f=&f.;
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.