|SAS Macro Language: Reference|
Commonly Encountered Problems lists some problems you may encounter when working with the macro facility. Because for many of these situations error messages aren't written to the SAS log, solving them can be hard. For each problem, the table gives some possible causes and some solutions.
|Display manager session hangs after you submit a macro definition. You type and submit code but nothing happens.||
|The %MEND statement is not recognized and all text is becoming part of the macro definition.|
|Display manager session hangs after you call a macro||An error in invocation, such as forgetting to provide one or more parameters, or forgetting to use parentheses when invoking a macro that is defined with parameters.||The macro facility is waiting for you to finish the invocation.|
|The macro does not compile when you submit it.||A syntax error exists somewhere in the macro definition.||Only syntactically correct macros are compiled.|
|The macro does not execute when you call it or partially executes and stops.||
|A macro successfully executes only when it receives the correct number of parameters that are of the correct type.|
|The macro executes but the SAS code gives bad results or no results.||Incorrect logic in the macro os SAS code.||Computers do what you tell them, not what you intended to tell them.|
|Code runs fine if submitted as open code, but when generated by a macro, the code doesn't work and issues strange error messages.||
|Rarely, macro quoting functions alter the tokenization of text enclosed
in them. Use the %UNQUOTE function.
See "%UNQUOTE" in Chapter 13.
|A %MACRO statement generates "invalid statement" error.||
|For the macro facility to work, the MACRO system option must be one. Edit your SAS configuration file accordingly.|
Common Macro Error Messages and Causes lists some common macro error and warning messages. For each message, some probable causes are listed, and pointers to more information are provided.
|Error Message||Possible Causes||For More Information|
|Solving Macro Variable Resolution Problems|
macro processor examines a name token that follows an
&, it searches the macro symbol tables for a matching macro variable
entry. If it finds a matching entry, it pulls the associated text from the
symbol table and replaces
&name on the input
stack. When a macro variable name is passed to the macro processor but the
processor does not find a matching entry in the symbol tables, it leaves the
token on the input stack and generates this message:
WARNING: Apparent symbolic reference NAME not resolved.
The unresolved token is transferred to the input stack for use by other parts of the SAS System.
Note: You receive the WARNING only if the SERROR
system option is on.
To solve these problems, check that you've spelled the macro variable name right and that you are referencing it in an appropriate scope.
When a macro variable resolves but does not resolve to the correct value, you can check several things. First, if the variable is a result of a calculation, make sure the correct values were passed into the calculation. And, make sure you have not inadvertently changed the value of a global variable. (See Solving Problems with Macro Variable Scope for more details on variable scope problems.)
Another common problem is adding text to the end of a macro variable but forgetting to add a delimiter that shows where the macro variable name ends and the added text begins. For example, suppose you want to write a TITLE statement with a reference to WEEK1, WEEK2, and so on. You set a macro variable equal to the first part of the string, then supply the week's number in the TITLE statement:
%let wk=week; title "This is data for &wk1"; /* INCORRECT */
When these statements compile, the macro processor looks for a macro variable named WK1, not WK. To fix the problem, add a period (the macro delimiter) between the end of the macro variable name and the added text, as in the following statements:
%let wk=week; title "This is data for &wk.1";
If a name conflict occurs, SAS may not issue a warning or error message, depending on the details of the conflict. Therefore, the best practice is to avoid using the strings AF, DMS, or SYS as the beginning characters of macro names and macro variable names.
|Solving Problems with Macro Variable Scope|
A common mistake that occurs with macro variables concerns referencing local macro variables outside their scope. As described in Chapter 5, "Scope of Macro Variables," macro variables are either global or local. Referencing a variable outside its scope prevents the macro processor from resolving the variable reference. For example, consider the following program:
%macro totinv(var); data inv; retain total 0; set sasuser.houses end=final; total=total+&var; if final then call symput("macvar",put(total,dollar14.2)); run; %put **** TOTAL=&macvar ****; %mend totinv; %totinv(price) %put **** TOTAL=&macvar ****; /* ERROR */
When you submit these statements, the %PUT statement in the macro TOTINV
writes the value of TOTAL to the log, but the %PUT statement that follows
the macro call generates a warning message and writes the text
TOTAL=&macvar to the log, as follows:
TOTAL= $1,240,800.00 WARNING: Apparent symbolic reference MACVAR not resolved. **** TOTAL=&macvar ****The second %PUT statement fails because the macro variable MACVAR is local to the TOTINV macro. To correct the error, you must use a %GLOBAL statement to declare the macro variable MACVAR.
Another common mistake that occurs with macro variables concerns overlapping macro variable names. If, within a macro definition, you refer to a macro variable with the same name as a global macro variable, you affect the global variable, which may not be what you intended. Either give your macro variables distinct names or use a %LOCAL statement to explicitly define a local macro variable. See "Forcing a Macro Variable to Be Local" in Chapter 5 for an example of this technique.
|Solving Open Code Statement Recursion Problems|
Recursion is something calling itself. Open code recursion is when your open code erroneously causes a macro statement to call another macro statement. The most common error that causes open code recursion is a missing semicolon. In the following example, the %LET statement is not terminated by a semicolon:
%let a=b /* ERROR */ %put **** &a ****;
When the macro processor encounters the %PUT statement within the %LET statement, it generates this error message:
ERROR: Open code statement recursion detected.
Open code recursion errors usually occur because the macro processor is not reading your macro statements as you intended. Careful proofreading can usually solve open code recursion errors, because this type of error is mostly the result of typos in your code, not errors in execution logic.
To recover from an open code recursion error, first try submitting a single semicolon. If that does not work, try submitting the following string:
*'; *"; *); */; %mend; run;
Continue submitting this string until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
If the above method does not work, close your SAS session and restart SAS. Of course, this causes you to lose any unsaved data, so be sure to save often while you are developing your macros, and proofread them carefully before you submit them.
|Solving Problems with Macro Functions|
Some common causes of problems with macro functions include
If you encounter an error related to a macro function, you may also see other error messages, generated by the invalid tokens left on the input stack by the macro processor.
Consider the following example. The user wants to use the %SUBSTR function to assign a portion of the value of the macro variable LINCOLN to the macro variable SECONDWD. But a typo exists in the second %LET statement, where %SUBSTR is misspelled as %SUBSRT:
%macro test; %let lincoln=Four score and seven; %let secondwd=%subsrt(&lincoln,6,5); /* ERROR */ %put *** &secondwd ***; %mend test; %test
When the erroneous program is submitted, the following appears in the SAS log:
WARNING: Apparent invocation of macro SUBSRT not resolved.
The error messages clearly point to the function name, which is misspelled.
|Solving "Apparent Invocation of Macro Not Resolved" Problems|
When a macro name is passed to the macro processor but the processor does not find a matching macro definition, it generates the following message:
WARNING: Apparent invocation of macro NAME not resolved.
This error could be caused by the misspelling of the name of a macro or a macro function, or it could be caused by an error in a macro definition that caused the macro to be compiled as a dummy macro. A dummy macro is a macro that the macro processor partially compiles but does not store.
receive this warning only if the MERROR system option is on.
|Solving the "Black Hole" Macro Problem|
One error that is most frustrating to new users of the macro language is one that is not accompanied by any error message (and is therefore hard to solve if you are a novice). When the macro processor begins compiling a macro definition, it reads and compiles tokens until it finds a matching %MEND statement. If you omit a %MEND statement or cause it to be unrecognized by omitting a semicolon in the preceding statement, the macro processor does not stop compiling tokens. Every line of code you submit becomes part of the macro.
Resubmitting the macro definition and adding the %MEND statement does not correct the error. When you submit the corrected definition, the macro processor treats it as a nested definition in the original macro definition. The macro processor must find a matching %MEND statement to stop compilation.
Note: It is a good practice to use the %MEND statement with the macro name,
so you can easily match %MACRO and %MEND statements.
If you recognize that SAS is not processing submitted statements and you are not sure how to recover, submit %MEND statements one at a time until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
Then recall the original erroneous macro definition, correct the error in the %MEND statement, and submit the definition for compilation.
There are other syntax errors that can create similar problems, such as unmatched quotation marks and unclosed parentheses. Often, one of these syntax errors leads to others. Consider the following example:
%macro rooms; /* other macro statements */ %put **** %str(John's office) ****; /* ERROR */ %mend rooms; %rooms
When you submit these statements, the macro processor begins to compile the macro definition ROOMS. However, the single quotation mark in the %PUT statement is not marked by a percent sign. Therefore, during compilation the macro processor interprets the single quote as the beginning of a literal token. It does not recognize the closing parenthesis, the semicolon at the end of the statement, or the %MEND statement at the end of the macro definition.
To recover from this error, you must submit the following:
If the above methods do not work, try submitting the following string:
*'; *"; *); */; %mend; run;
Continue submitting this string until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
Obviously, it is easier to catch these types errors before they occur. You can avoid subtle syntax errors by carefully checking your macros before submitting them for compilation. Refer to Developing Bug-free Macros for a syntax checklist.
cause of unexplained and unexpected macro behavior is using a reserved word
as the name of a macro variable or macro. For example, the SAS System reserves
names starting with SYS; you should not create macros and macro variables
with names beginning with SYS. Also, most host environments have reserved
words too. For example, on PC-based platforms, the word CON is reserved for
console input. Check Appendix 1, "Reserved Words in the Macro Facility,"
for reserved SAS System keywords; check your SAS companion for host environment
|Resolving Timing Issues|
Many macro errors occur because a macro variable resolves at a different time than when the user intended or a macro statement executes at an unexpected time. A prime example of the importance of timing is when you use CALL SYMPUT to write a DATA step variable to a macro variable. You cannot use this macro variable in the same DATA step where it is defined; you can use it only in subsequent steps (that is, after the DATA step's RUN statement).
The key to forestalling timing errors is to understand how the macro processor works. In simplest terms, the two major steps are compilation and execution. The compilation step resolves all macro code to compiled code. Then the code is executed. Most timing errors occur because the user expects something to happen during compilation that doesn't actually occur until execution or, conversely, expects something to happen later but is actually executed right away.
Here are two examples to help you understand why the timing of compilation
and execution can be important.
In the following program, the user intends to use the %LET statement and the SR_CIT variable to indicate whether a data set contains any data for senior citizens:
data senior; set census; if age > 65 then do; %let sr_cit = yes; /* ERROR */ output; end; run;
However, the results differ from the user's expectations. The %LET statement
is executed immediately, while the DATA step is only being compiled--before the data set is read. Therefore, the %LET statement executes
regardless of the results of the IF condition. Even if the data set contains
no observations where AGE is greater than 65, SR_CIT is always
The solution is to set the macro variable's value by a means that is controlled by the IF logic and does not execute unless the IF statement is true. In this case, the user should use CALL SYMPUT, as in the following correct program:
%let sr_cit = no; data senior; set census; if age > 65 then do; call symput ("sr_cit","yes"); output; end; run;
When this program is submitted, only if an observation is found with
AGE greater than 65 is the value of SR_CIT set to
yes. Note that the variable
was initialized to
no. It is generally a good idea to
initialize your macro variables.
In the previous example, you learned you had to use CALL SYMPUT to conditionally assign a macro variable a value in a DATA step. So, you submit the following program:
%let sr_age = 0; data senior; set census; if age > 65 then do; call symput("sr_age",age); put "This data set contains data about a person"; put "who is &sr_age years old."; /* ERROR */ end; run;If AGE was 67, you'd expect to see a log message like this one:
This data set contains data about a person who is 67 years old.
However, no matter what AGE is, the following message is sent to the log:
This data set contains data about a person who is 0 years old.
Why is this? Because when the DATA step is being compiled, &SR_AGE is sent to the macro facility for resolution, and the result is passed back before the DATA step executes. To achieve the desired result, submit this corrected program instead:
%let sr_age = 0; data senior; set census; if age > 65 then do; call symput("sr_age",age); stop; end; run; data _null_; put "This data set contains data about a person"; put "who is &sr_age years old."; run;
Note: Use double quotation marks in statements like PUT,
because macro variables do not resolve when enclosed in single quotation marks.
Here is another example of erroneously referring to a macro variable in the same step that creates it:
data _null_; retain total 0; set mydata end=final; total=total+price; call symput("macvar",put(total,dollar14.2)); if final then put "*** total=&macvar ***"; /* ERROR */ run;
Submitting these statements writes the following lines to the SAS log:
WARNING: Apparent symbolic reference MACVAR not resolved. *** total=&macvar ***
As this DATA step is tokenized and compiled, the
causes the word scanner to trigger the macro processor, which looks for a
MACVAR entry in a symbol table. Because such an entry does not exist, the
macro processor generates the warning message. Because the tokens remain on
the input stack, they are transferred to the DATA step compiler. During DATA
step execution, the CALL SYMPUT statement creates the macro variable MACVAR
and assigns a value to it. However, the text
&macvar in the PUT
statement occurs because the text has already been processed while the macro
was being compiled. If you were to resubmit these statements, then the macro
would appear to work correctly, but the value of MACVAR would reflect the
value set during the previous execution of the DATA step. This can be misleading.
Remember that in general, the
trigger immediate execution or resolution during the compilation stage of
the rest of your SAS code.
For more examples and explanation of how CALL SYMPUT creates macro variables, see "Creating Macro Variables with the CALL SYMPUT Routine" in Chapter 5.
|Solving Problems with the Autocall Facility|
The autocall facility is an efficient way of storing and using production (debugged) macros. When a call to an autocall macro produces an error, the cause is one of two things:
If the error is the autocall library specification and the MERROR option is set, SAS can generate any or all of the following warnings:
WARNING: No logical assign for filename FILENAME. WARNING: Source level autocall is not found or cannot be opened. Autocall has been suspended and OPTION NOMAUTOSOURCE has been set. To use the autocall facility again, set OPTION MAUTOSOURCE. WARNING: Apparent invocation of macro MACRO-NAME not resolved.
If the error is in the autocall macro definition, SAS generates a message like the following:
NOTE: Line generated by the invoked macro "MACRO-NAME".
When an autocall library specification causes an error, it is because the macro processor cannot find the member containing the autocall macro definition in the library or libraries specified in the SASAUTOS system option.
To correct this error, follow these steps.
Note: Some host environments have environment variables
or system-level logical names assigned to the SASAUTOS library; check your
SAS companion for more information on details about how the SASAUTOS library
specification is handled in your host environment.
When the autocall facility locates an autocall library member, the macro processor compiles any macros in that library member and stores the compiled macros in the catalog containing stored compiled macros. For the rest of your SAS session, invoking one of those macros retrieves the compiled macro from the WORK library. Under no circumstances does the autocall facility use an autocall library member when a compiled macro with the same name already exists. Thus, if you invoke an autocall macro and discover you made an error when you defined it, you must correct the autocall library member for future use and compile the corrected version directly in your program or session.
To correct an autocall macro definition in a display manager session, do the following:
The macro processor then compiles the corrected version, replacing the incorrect compiled macro. The corrected, compiled macro is now ready to execute at the next invocation.
To correct an autocall macro definition in an interactive line mode session, do the following:
The macro processor then compiles the corrected version, replacing the
incorrect compiled macro. The corrected, compiled macro is now ready to execute
at the next invocation.
When you want to use a macro as an autocall macro, you must store the macro in a file with the same name as the macro. Also, the file extension must be .SAS (if your operating system uses file extensions). If you experience problems with the autocall facility, be sure the macro and file names match and the file has the right extension when necessary.
|Displaying Information about Stored Compiled Macros|
To display the list of entries in a catalog containing compiled macros, you can use the display manager CATALOG window or the CATALOG procedure. The following PROC step displays the contents of a macro catalog in a SAS data library identified with the libref MYSASLIB:
libname mysaslib 'SAS-data-library'; proc catalog catalog=mysaslib.sasmacr; contents; run; quit;
You can also use PROC CATALOG to display information about autocall library macros stored in SOURCE entries in a catalog. You cannot use PROC CATALOG or the CATALOG window to copy or rename stored compiled macros.
In Release 6.11 or later, you can use PROC SQL to retrieve information about all compiled macros. For example, submitting the following statements produces output similar to Output from PROC SQL:
proc sql; select * from dictionary.catalogs where memname in ('SASMACR');
Output from PROC SQL
Library Member Member Object Object Name Name Type Name Type Date Object Object Description Modified Alias ------------------------------------------------------------ WORK SASMACR CATALOG FINDAUTO MACRO 05/28/96 SASDATA SASMACR CATALOG CLAUSE MACRO Count words in clause 05/24/96 SASDATA SASMACR CATALOG CMPRES MACRO CMPRES autocall macro 05/24/96 SASDATA SASMACR CATALOG DATATYP MACRO DATATYP autocall macro 05/24/96 SASDATA SASMACR CATALOG LEFT MACRO LEFT autocall macro 05/24/96
To display information about compiled macros when you invoke them, use the SAS system options MLOGIC, MPRINT, and SYMBOLGEN. When you specify the SAS system option MLOGIC, the libref and date of compilation of a stored compiled macro are written to the log along with the usual information displayed during macro execution.
|Solving Problems with Expression Evaluation|
The following macro statements use an implicit %EVAL function:
In addition, you can use the %EVAL function to perform an explicit expression evaluation.
The most common errors that occur while evaluating expressions are the presence of character operands where numeric operands are required or ambiguity about whether a token is a numeric operator or a character value. Chapter 6, "Macro Expressions," discusses these and other macro expression errors.
Quite often, an error occurs when a special character or a keyword appears in a character string. Consider the following program:
%macro conjunct(word= ); %if &word = and or &word = but or &word = or %then /* ERROR */ %do %put *** &word is a conjunction. ***; %else %do %put *** &word is not a conjunction. ***; %mend conjunct;
In the %IF statement, the values of WORD being tested are ambiguous--they could also be interpreted as the numeric operators AND and OR. Therefore, the SAS System generates the following error messages 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:word = and or &word = but or &word = or ERROR: The macro will stop executing.
To fix this problem, use the quoting functions %BQUOTE and %STR, as in the following corrected program:
%macro conjunct(word= ); %if %bquote(&word) = %str(and) or %bquote(&word) = but or %bquote(&word) = %str(or) %then %do %put *** &word is a conjunction. ***; %else %do %put *** &word is not a conjunction. ***; %mend conjunct;
In the corrected program, the %BQUOTE function quotes the result of the macro variable resolution (in case the user passes in a word containing an unmatched quotation mark or some other odd value), and the %STR function quotes the comparison values AND and OR at compile-time, so they are not ambiguous. You do not need to use %STR on the value BUT, because it is not ambiguous (not part of the SAS or macro language). See Chapter 7, "Macro Quoting," for more information on using macro quoting functions.
Top of Page
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.