| Date: | Thu, 14 Jan 1999 10:28:26 -0500 |
| Reply-To: | David D Kane <ddk@NUMERIC.COM> |
| Sender: | "SAS(r) Discussion" <SAS-L@UGA.CC.UGA.EDU> |
| From: | David D Kane <ddk@NUMERIC.COM> |
| Organization: | Numeric Investors L.P. |
| Subject: | Scoping variables one level up |
| Content-Type: | multipart/mixed; |
|---|
Surely, someone has already solved this problem.
How does one force a macro variable to have a scope that is one level
above the macro in which it is created but *not* global?
Consider a utility (attached at the end of this message) that creates an
inderminate number of macro variables (var1, var2, etc) on the basis of
the observations in a data set. I use this utility (ScanList) all the
time (if someone has a better version, please post it). In order for the
calling macro to uses var1, var2 . . ., I need to declare them as
global.
The problem is that I work on big projects with other people. These
projects might have a large macro, call it top, which would call my
macro, call it middle1, which uses ScanList as well as Jones' macro,
call it middle2, which also calls ScanList. But Jones and I may not know
about each other and now the global variables (which we really want to
be *local* to middle1 and middle2) can conflict with each other in top.
This is a problem. How should we solve it? How do we "transfer" a macro
variable created in ScanList to the calling macro without making that
macro variable global?
/*******************************************************************************
* Program name: ScanList.sas
*
* Programmer: DDK
*
* Purpose: This small macro is intended to facilitate the easy creation
of an
* indeterminate number of macro variables. It takes five arguments:
*
* dataset is a flag indicating whether or not the variables are
being passed
* in in a dataset. TRUE means that they are. The default is
FALSE. If
* they are not in a data set then they must be in a string
deliminated by
* delim.
* list is either a data set name (if dataset is TRUE) or it is a
string
* deliminated by delim, the default value for which is the pipe
(|). The
* presense of spaces is irrelevant in list.
* delim is the deliminator used in list. The default value is pipe
(|).
* prefix is the base name of the macro variables to be created.
* numName is the desired name for the number of macro variables
created.
* variable is the name of the variable in the dataset called list
which has
* the desired values for the macro variables.
*
* The macro creates variables of the form name1, name2, et cetera
and places
* the values in them. It also creates a variable, numName, with the
number
* of variables in the list. If the list is empty then no macro
* variables will be created (I think).
*
* Date created: 9809
*
*******************************************************************************/
%Macro ScanList(
dataset = FALSE,
list =,
delim = |,
prefix =,
numName =,
variable =
);
/*******************************************************************************
*
* The code is in two parts. First, for string input and second for a
dataset.
* I need to add a flag for checking whether the data set (or the list)
is empty.
*
*******************************************************************************/
%if &numName eq %then %let numName = &prefix.num;
%local i howMany;
%global &numName;
%if &dataset eq FALSE %then %do;
%let i = 1;
%do %while( %scan(&list, &i, |) ne );
%global &prefix&i;
%let &prefix&i = %scan(&list, &i, |);
%let i = %eval(&i + 1);
%end;
%let &numName = %eval(&i - 1);
%end;
%else %if &dataset eq TRUE %then %do;
data _NULL_;
set &list end = last;
if last then call symput('howMany', put(_N_, 8.));
run;
%do i = 1 %to &howMany;
%global &prefix&i;
%end;
data _NULL_;
set &list;
call symput(compress("&prefix"||put(_N_, 8.)),
compress(&variable));
run;
%let &numName = &howMany;
%end;
%Mend ScanList;
[text/x-vcard]
begin: vcard
fn: David Kane
n: Kane;David
org: Numeric Investors
email;internet: ddk@numeric.com
title: Statistician
x-mozilla-cpt: ;0
x-mozilla-html: FALSE
version: 2.1
end: vcard
|