Introduction to the SAS Macro Facility
Introduction to the SAS Macro Facility
Uses for SAS Macros
The macro language allows for programs
that are dynamic—capable of self-
modification.
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;
class lt;
var &var;
run;
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
proc means data=mysas.fish min median max;
class lt;
var hg;
run;
Compiler
Word Scanner
Input Stack
How many
tokens are
in the first
line of code?
proc
means
data
=
mysas
.
fish
min
median
max
;
class lt;
var hg;
run;
Compiler
Word Scanner
Input Stack
Actually,
the word
scanner
is passing
tokens to
the compiler
at this point
The Word Scanner--Tokenization
proc means data=mysas.fish min median max;
class
lt
;
var hg;
run;
Compiler
Word Scanner
Input Stack
When a
statement is
complete, its
syntax is checked
and it is
compiled
The Word Scanner--Tokenization
proc means data=mysas.fish min median max;
class lt;
var hg;
run;
Compiler
Word Scanner
Input Stack
For procedures
and data steps,
once a step
boundary is
reached, the
compiled code
is executed
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
%let var=hg;
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var &var;
run;
Compiler
Word Scanner
Input Stack
Macro Processor
Macro Processing
var=hg;
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var &var;
run;
%let
Compiler
Word Scanner
Input Stack
%let
Macro Processor
The % acts as a macro
trigger. The % and the
following name token
are sent to the macro
processor.
Macro Processing
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var &var;
run;
var
=
hg
;
Compiler
Word Scanner
Input Stack
%let var=hg;
Macro Processor
The word scanner
will continue to
deliver tokens to
the macro processor
until a semicolon is
reached
%let
Macro Processing
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var &var;
run;
Compiler
Word Scanner
Input Stack
Macro Processor
%let var=hg;
Variable Value
var hg
Symbol Table
The %let statement
assigns a value to the
macro variable
Macro Processing
;
run;
&var
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var
Compiler
Word Scanner
Input Stack
Macro Processor
Symbol Table
Remaining statements
up to the var statement
are passed to the compiler.
Variable Value
var hg
Macro Processing
;
run;
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var
Compiler
Word Scanner
Input Stack
Macro Processor
var
Symbol Table
The & sends var to the
macro processor…
Variable Value
var hg
Macro Processing
hg;
run;
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var
Compiler
Word Scanner
Input Stack
Macro Processor
var
Symbol Table
Variable Value
var hg
The macro processor
resolves the macro
variable reference and
places the value on the
input stack
Macro Processing
Title 'Summary Statistics';
proc means data=mysas.fish min median max;
class lt;
var hg;
run;
Compiler
Word Scanner
Input Stack
Macro Processor
Symbol Table
Variable Value
var 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 Value
SYSDATE Date of SAS invocation (DATE7.)
SYSDATE9 Date of SAS invocation (DATE9.)
SYSDAY Day of the week of SAS invocation
SYSTIME Time of SAS invocation
SYSVER Version of SAS being used
SYSLAST 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:
Writes names and values of all automatic macro
variables to the Log.
%put _automatic_;
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.