Introduction to the SAS Macro Facility
Uses for SAS Macros The macro language allows for programs that are dynamic capable of selfmodification. The major components of the macro language include: Macro variables Macro statements and functions Special programs using some combination of the above (macros)
An Example Here is code that will produce summary statistics on mercury level, elevation, surface area and max depth across lake types. Title 'Summary Statistics'; proc means data=mysas.fish min q1 median q3 max; class lt; var hg elv sa z; run; quit;
Example (Cont d) Suppose I want to generate separate tables for each of the variables listed in the var statement (maybe even delivering each to a separate pdf), what do I have to do? The macro facility provides a way to execute the same base code under different conditions.
Macro Variables Macro variables are used to store information that will be used to make code dynamic. All macro variables are character (special functions will be required to do numerical operations). Macro variables follow the same naming conventions as other variables; however, they are always preceded by an ampersand (&) when referenced.
Revised (yet unsophisticated) Example %let var=hg; Title 'Summary Statistics'; proc means data=mysas.fish min q1 median q3 max; run; class lt; var &var; quit; hg is assigned to the macro variable var (note, no ampersand when defined When the program runs, the value of var is substituted here (ampersand used during reference)
Assigning Values to Macro Variables The %let statement can be used to assign values to macro variables %let is macro statement all SAS macro statements (and functions) begin with %. % and & are referred to as macro triggers General form %let macro-variable=value Note: value is not quoted & is not included in variable name when it is defined %let is legal in open code (i.e. outside macros).
What is the Macro Facility Doing? The macro language s primary function is as a text substitution facility and/or code generator. To fully understand how macro processing works, we have to look at how SAS processes submitted code.
Program Processing and Flow A SAS program can be any combination of: Global statements Data steps and PROC steps Structured Query Language (SQL) SAS Component Language (SCL) SAS macro language All submitted programs, regardless of content, are delivered to the input stack.
Compilation and Execution When the code is delivered to the input stack, SAS Reads text in the input stack Routes text to the appropriate compiler Suspends activity when a step boundary is reached. Executes compiled code if there are no errors Repeats as necessary.
The Word Scanner--Tokenization The word scanner breaks up the text into units known as tokens. The process (open code): The word scanner passes tokens to the compiler, and the compiler requests tokens until it receives a semicolon. The compiler performs a syntax check on the statement.
Tokens There are four types of tokens: Literals: Any quoted string Any text string Any text string Numbers: Strings of digits. May include decimal points and scientific notation 23 23.7.7 23.7E-10 Names: Strings of characters beginning with a letter or underscore libname _n_ mmddyy10. fred Special: Special characters $ ( ). & %
The Word Scanner--Tokenization Compiler Word Scanner How many tokens are in the first line of code? Input Stack proc means data=mysas.fish min median max; class lt; var hg; run;
Compiler Actually, the word scanner is passing tokens to the compiler at this point Word Scanner proc means data = mysas. fish min median max ; Input Stack run; class lt; var hg;
The Word Scanner--Tokenization Compiler proc means data=mysas.fish min median max; When a statement is complete, its syntax is checked and it is compiled Word Scanner class lt ; Input Stack run; var hg;
The Word Scanner--Tokenization Compiler For procedures and data steps, once a step boundary is reached, the compiled code is executed proc means data=mysas.fish min median max; class lt; var hg; run; Word Scanner Input Stack
Tokenization How does the compiler know when to execute code? In an interactive session, is the run statement necessary? Try submitting the simple program a token at a time (except for proc, which must be submitted with the named procedure).
What Does This Mean for Macros? Certain tokens are macro triggers % (followed by any name token) is an indication of a macro statement or function. & (followed by any name token) is a reference to a macro variable. Let s look at the following code
Macro Processing Compiler Macro Processor Word Scanner Input Stack %let var=hg; Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var &var; run;
Macro Processing Compiler Macro Processor %let Word Scanner %let Input Stack var=hg; Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var &var; run; The % acts as a macro trigger. The % and the following name token are sent to the macro processor.
Macro Processing Compiler Macro Processor %let var=hg; Word Scanner var = hg ; Input Stack Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var &var; run; The word scanner will continue to deliver tokens to the macro processor until a semicolon is reached
Macro Processing Compiler Macro Processor %let var=hg; Word Scanner Input Stack Symbol Table Variable var Value hg Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var &var; run; The %let statement assigns a value to the macro variable
Macro Processing Compiler Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var Macro Processor Word Scanner &var Input Stack Symbol Table Variable var Value hg run; ; Remaining statements up to the var statement are passed to the compiler.
Macro Processing Compiler Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var Macro Processor var Word Scanner Input Stack Symbol Table Variable var Value hg run; ; The & sends var to the macro processor
Macro Processing Compiler Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var Macro Processor var Word Scanner Input Stack Symbol Table Variable var Value hg hg; run; The macro processor resolves the macro variable reference and places the value on the input stack
Macro Processing Compiler Title 'Summary Statistics'; proc means data=mysas.fish min median max; class lt; var hg; run; Macro Processor Word Scanner Input Stack Symbol Table Variable var Value hg The remainder of the code is passed to the compiler and is executed
Automatic Macro Variables By default, SAS has several macro variables established on its own. These variables are created at the invocation of the SAS session are global (always available) some have been assigned values by SAS (some are null) values can be re-assigned by users in some cases
Some Automatic Macro Variables Name SYSDATE SYSDATE9 SYSDAY SYSTIME SYSVER SYSLAST Value Date of SAS invocation (DATE7.) Date of SAS invocation (DATE9.) Day of the week of SAS invocation Time of SAS invocation Version of SAS being used Name of the most recently created data set. If none have been created, value is _NULL_.
Viewing Macro Variables The macro language has its own put statement. Syntax: %put text; Writes a new line to the SAS Log No quotes are required around text Resolves any macro triggers in text Can be used in open code
Viewing Automatic Macro Variables The statement: %put _automatic_; Writes names and values of all automatic macro variables to the Log.
Issues in Resolving Macro Variables How do each of the following resolve? %let date=march 14, 1998; %let name=john Doe; %let value1=3; %let value2=4; %let sum1=value1+value2; %let sum2=&value1+&value2; Remember, macro variable values are assigned as character strings
Issues in Resolving Macro Variables Let s consider a different condition on the employees data set Print out selected information for all employees in a given city. The city value should be passed as a macro variable.
Suppose we try this %let city=cary; proc print data=mysas.employees noobs; where upcase(city)=&city; var EmpID HireDate JobCode City Salary; run; What happens?
Resolution of Macro Variables Though the value of the macro variable city is stored with the value CARY as text The macro processor passes the value CARY back to the input stack upon resolving &city The token CARY is then passed to the compiler Since it is not quoted, it is interpreted by the compiler as a variable name Since there is no variable in the data set called CARY, an error is generated
Resolution of Macro Variables A possible solution is to modify the value of the macro variable: %let city= CARY ; However, this may not be the best solution, especially if one wishes to use the token CARY without the quotes
Resolution of Macro Variables Another possible solution %let city=cary; proc print data=mysas.employees noobs; where upcase(city)='&city'; var EmpID HireDate JobCode City Salary; run;????? Nope
Resolution of Macro Variables However, this %let city=cary; proc print data=mysas.employees noobs; where upcase(city)= &city ; var EmpID HireDate JobCode City Salary; run; works! Important: Every literal is a token, but single quoted strings are not scanned for macro triggers, double quoted strings are.