Date: Mon, 16 Oct 2006 11:58:19 -0400
Reply-To: Peter Crawford <peter.crawford@BLUEYONDER.CO.UK>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Peter Crawford <peter.crawford@BLUEYONDER.CO.UK>
Subject: Re: Macro with keyword parameters and PARMBUFF
Jim
since you have only one keyword parameter, and do no statements
(other than debugging options), keep maintainability in sight by
turning it into a macro function, called like
Counter = %COUNT ( a b c, 3 5 7 _sysmis_, b a, 1 9);
or
%put count is %COUNT ( a b c, 3 5 7 _sysmis_, b a, 1 9);
If you really want just to demonstrate the ParmBuff feature,
try counting the commas in &sysPbuff .
Good Luck
Peter
On Mon, 16 Oct 2006 11:03:20 -0400, Jim Groeneveld <jim2stat@YAHOO.CO.UK>
wrote:
>Hi friends,
>
>I am developing an advanced macro %COUNT, counting specified values for
>variables within records, similar to SPSS's COUNT command. So far no
>problem. But I want the macro to contain both one or more keyword
parameters
>and subsequent positional parameters to analyze from the macro variable
>&SYSPBUFF:
>
> %MACRO Count (CountVar=) / PARMBUFF; %* Macro definition;
> %COUNT (CountVar=Counter, a b c, 3 5 7 _sysmis_, b a, 1 9); * Macro
call;
>
>This (of course!?) does not work:
> ERROR: All positional parameters must precede keyword parameters.
>
>That is too bad. I get it to work with:
>
> %MACRO Count (CountVar) / PARMBUFF; %* Macro definition;
> %COUNT (Counter, a b c, 3 5 7 _sysmis_, b a, 1 9); * Macro call;
>
>or with
>
> %MACRO Count (CountVar=) / PARMBUFF; %* Macro definition;
> %COUNT (CountVar=Counter, V=a b c, N=3 5 7 _sysmis_, V=b a, N=1 9);
> * Macro call;
>
>where I (of course) have to account for the dummy keywords (V= and N=) in
>the SYSPBUFF variable list. I do not at all like these two solutions.
>
>How can I define and assign the named parameters by keyword and the
unnamed
>ones as positional ones? Or is this a bug or limitation in SAS?
>Or should I revert to a command or statement style invocation? How?
>
>I finally can get it to work correctly with:
> %MACRO Count / PARMBUFF; %* Macro definition;
> %COUNT (CountVar=Counter, a b c, 3 5 7 _sysmis_, b a, 1 9);
>while processing the first argument explicitly inside the macro.
>Is there a better or more elegant solution with defined keyword arguments?
>I would like to define more optional keyword parameters and I don't want
to
>recognize optional keyword parameters as such by my macro code, but by
SAS,
>because the presence of an '=' character may not be exclusive.
>
>The whole preliminary macro (and test) code for the time being is:
>
>%*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
>%* Macro Count counts value lists for dataset variables ;
>%*______________________________________________________;
>
>%* (C) Jim Groeneveld, 16 October 2006;
>
>%MACRO Count / PARMBUFF;
> %LOCAL CountVar H VarList ValList I Var J Val Debug;
>
> %LET Debug=0;
> %IF (&Debug EQ 1 OR &Debug GT 11) %THEN %DO;
> OPTIONS MPRINT MERROR SERROR MLOGIC SYMBOLGEN MACROGEN;
> %END;
>
> %LET SYSPBUFF = %Disclose (Enclosed=&SYSPBUFF); %* remove enclosing
parens;
>%put syspbuff=&SYSPBUFF;
> %LET CountVar = %SCAN(&SYSPBUFF,1,%STR(,));
>%put A: CountVar=&CountVar;
> %IF (%QUPCASE(%SCAN(%QUOTE(&CountVar),1,=)) EQ COUNTVAR AND
> %SCAN(%QUOTE(&CountVar),2,=) NE) %THEN
> %LET CountVar=%SCAN(%QUOTE(&CountVar),2,=);
>%put B: CountVar=&CountVar;
>
> &CountVar = 0;
> %LET H = 2;
> %LET VarList=%QSCAN(&SYSPBUFF,&H,%STR(,));
> %LET ValList=%QSCAN(&SYSPBUFF,%EVAL(&H+1),%STR(,));
> %DO %WHILE (%QUOTE(&VarList) NE);
>%put VarList=&VarList;
>%put ValList=&ValList;
> %IF (%QUOTE(&ValList) EQ) %THEN %DO;
> %PUT Empty value list, VarList=&VarList;
> %END;
> %ELSE %DO;
>
> %LET I = 1;
> %LET Var = %QSCAN ( &VarList, &I, %STR( ) );
> %DO %WHILE (%QUOTE(&Var) NE);
> %LET J = 1;
> %LET Val = %QSCAN ( &ValList, &J, %STR( ) );
> %DO %WHILE (%QUOTE(&Val) NE);
> %IF (%UPCASE(&Val) EQ _SYSMIS_) %THEN
> %DO;
> IF (&Var LE .z) THEN &CountVar = &CountVar + 1;
>* (all 28 SAS missing values are checked here);
> %END;
> %ELSE
> %DO;
> IF (&Var EQ &Val) THEN DO;
> &CountVar = &CountVar + 1;
>*put &Var= "Var=&Var Val=&Val " &CountVar=;
> END;
>* (no sum statement to avoid implicit RETAIN);
> %END;
> %LET J = %EVAL (&J + 1);
> %LET Val = %SCAN ( &ValList, &J, %STR( ) );
> %END;
> %LET I = %EVAL (&I + 1);
> %LET Var = %SCAN ( &VarList, &I, %STR( ) );
> %END;
>
> %END;
> %LET H = %EVAL (&H + 2);
> %LET VarList=%QSCAN(&SYSPBUFF,&H,%STR(,));
> %LET ValList=%QSCAN(&SYSPBUFF,%EVAL(&H+1),%STR(,));
> %END;
>%MEND Count;
>
>%*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
>%* Auxiliary Macro Disclose removes enclosing parentheses ;
>%*________________________________________________________;
>
>%MACRO Disclose (Enclosed=);
> %IF (%QUOTE(&Enclosed) EQ %STR(%(%))) %THEN; %* if () then return
nothing;
> %* to prevent warning
message;
> %ELSE %IF (%QSUBSTR(&Enclosed,1,1) EQ %STR(%()
> AND %QSUBSTR(&Enclosed,%LENGTH(&Enclosed),1) EQ %STR(%))) %THEN
> %QSUBSTR(&Enclosed, 2, %LENGTH(&Enclosed)-2); %* return disclosed
value;
> %ELSE &Enclosed; %* return original value;
>%MEND;
>
>DATA _NULL_;
> INPUT a b c;
> %COUNT (CountVar=Counter, a b c, 3 5 7 _sysmis_, b a, 1 9);
> PUT (_ALL_)(=);
> CARDS;
>1 2 3
>4 5 6
>7 8 9
>. .z ._
>;
>RUN;
>
>I already have contributed a draft paper about (a basic version of) this
>macro for SGF 2007.
>I am currently improving the basic macro %COUNT that I already have
>available on my website. It eventually will also allow value range
>specifications, like in SPSS.
>
>Regards - Jim.
>--
>Jim Groeneveld, Netherlands
>Statistician, SAS consultant
>home.hccnet.nl/jim.groeneveld
|