Tag Archive for SAS Macro

AND & OR, a cautionary tale

The inspiration for this post is a situation where having the string “OR” or “AND” as an input to a piece of SAS Macro code breaking a program that I had written. Here is a simplified example of what I was doing:

%macro test;
%let doms=GE GT NE LT LE AND OR;
%let lv_count=1;
%do %while (%scan(&doms,&lv_count,’ ‘) ne );
%put &lv_count;
%let lv_count=%eval(&lv_count+1);
%end
%mend test;

%test;

The loop proceeds well until the string “AND” is met and “OR” has the same effect. The result is the following message appears in the log:

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:  %scan(&doms,&lv_count,’ ‘) ne
ERROR: The condition in the %DO %WHILE loop, , yielded an invalid or missing value, .  The macro will stop executing.
ERROR: The macro TEST will stop executing.

Both AND & OR (case doesn’t matter but I am sticking with upper case for sake of clarity) seem to be reserved words in a macro DO WHILE loop while equality mnemonics like GE cause no problem. Perhaps, the fact that and equality operator is already in the expression helps. Regardless, the fix is a simple one:

%macro test;
%let doms=GE GT NE LT LE AND OR;
%let lv_count=1;
%do %while (“%scan(&doms,&lv_count,’ ‘)” ne “”);
%put &lv_count;
%let lv_count=%eval(&lv_count+1);
%end
%mend test;

%test;

Now none of the strings extracted from the macro variable &DOMS will appear as bare words and confuse the SAS Macro processor but you do have to make sure that you are testing for the null string (“” or ”) or you’ll send your program into an infinite loop, always a potential problem with DO WHILE loops so they need to be used with care. All in all, an odd looking message gets an easy solution without recourse to macro quoting functions like %NRSTR or %SUPERQ.

SAS Macro and Dataline/Cards Statements in Data Step

I recently tried code like this in a SAS macro:

data sections;
        infile datalines dlm=”,”;
        input graph_table_number $15. text_line @1 @;
        datalines;
        “11.1           ,Section 11.1″,
        “11.2           ,Section 11.2″,
        “11.3           ,Section 11.3″
        ;
run;

While it works in its own right, including it as part of a macro yielded this type of result:

ERROR: The macro X generated CARDS (data lines) for the DATA step, which could cause incorrect results.  The DATA step and the macro will stop executing.

A bit of googling landed me on SAS-L where I spotted a solution like this one that didn’t involving throwing everything out:

filename temp temp;

data _null_;
        file temp;
        put;
run;

data sections;
        length graph_table_number $15 text_line $100;
        infile temp dlm=”,”;
        input @;
        do _infile_=
        “11.1           ,Section 11.1″,
        “11.2           ,Section 11.2″,
        “11.3           ,Section 11.3″
        ;
                input graph_table_number $15. text_line @1 @;
                output;
        end;
run;

filename temp clear;

The filename statement and ensuing data step creates a dummy file in the SAS work area that gets cleared at the end of every session. That seems to fool the macro engine into thinking that input is from a file and not the CARDS/DATALINES method to which it takes grave exception. The trailing @’s hold an input record for the execution of the next INPUT statement within the same iteration of the DATA step so that the automatic variable _infile_ can be fed as part of the input process in a do block with the output statement ensure that new records from the input buffer reach the data set being created.

This method does work but I would like to know the underlying reason as to why SAS Macro won’t play well with included data entry using DATALINES or CARDS statements in a data step, particularly when it allows other methods that using either SQL insert statements or standard variable assignment in data step. I find it such a curious behaviour that I remain on the lookout for the explanation why it is like this.

  • As is commonly the case with places like these, all the views that you find expressed on here in postings and articles are mine alone and not those of any organisation with which I have any association, through work or otherwise. With regards to any comments left on the site, I reserve the right to reject any that are inappropriate. Otherwise, whatever is said is the sole responsibility of whoever is leaving the comment.