Date: Fri, 2 Feb 2007 18:17:29 -0500
Reply-To: Chang Chung <chang_y_chung@HOTMAIL.COM>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Chang Chung <chang_y_chung@HOTMAIL.COM>
Subject: Re: Macro Quoting Tid Bit
On Fri, 2 Feb 2007 22:26:32 +0000, toby dunn <tobydunn@HOTMAIL.COM> wrote:
>From a little Birdie:
>
>.. When %SYSFUNC is used, a Macro variable passed to a function is expanded
>and resolved before a value is passed. This means that delta characters
>from Macro quoting have been removed and the function will never see them.
>
>.. With %SYSCALL, Macro variables are passed directly to the CALL routine
>without any expansion or resolution. This is done because a CALL routine
>could modify the variable's value, so the true value of the variable must be
>passed. This also means any delta characters from Macro quoting are passed
>to the function.
Hi,
Thanks Toby, and thanks Little Birdie!
So, this means that it is a feature, not a bug.... Well, this came out
before, but recently, it came out of the discussion between Toby and me.
Here is an interesting consequencies of the above bug.. uh, feature.
Below, we are trying to match a percent sign using prxsubstr through
%sysfunc. This function is supposed to return the position and the length of
the match. The position returned in this case is 0(zero) since the percent
sign has been quoted away.
%let t=%nrstr(abcd %b);
%let pos=0;
%let len=0;
%let prx =%sysfunc(prxparse("%"));
%syscall prxsubstr(prx,t,pos,len);
%put p=&p.;
/* it returns p=0, why? it is quoted away. */
In fact, there is a tech note on this
http://support.sas.com/techsup/unotes/SN/013/013067.html, where si suggests
single quoting the target string like:
/* single quote */
%let t = %nrstr('abcd %b');
%let pos=0;
%let len=0;
%let prx =%sysfunc(prxparse("%"));
%syscall prxsubstr(prx,t,pos,len);
%put pos=&pos.;
/* this time it returns 8 */
The note says that since then pos returns consistently 1 off. We can then
subtract 1 from the pos and that is the correct pos.
Well, not quite. This applies only when we know how the string t was quoted.
Frequently all we know is that the input string has been quoted, not knowing
how or how many times. In many cases in writing a general-use macro, we
habitually %superq() input string, whenever there is a chance of something
dangerous inside the input string. In this case, it is easy to get pos=0
again, if the macro var t has been quoted again in process.
%let t = %nrstr('abcd %b');
%let pos=0;
%let len=0;
%let prx =%sysfunc(prxparse("%"));
%let t = %superq(t); /* quoted again */
%syscall prxsubstr(prx,t,pos,len);
%put pos=&pos.;
/* this time it returns 0 again */
Frankly, I feel that preserving delta characters in %syscall seems to make
it almost unusable in macro context. And I am not sure if I fully understand
the reason why the delta characters has to be preserved. Especially in this
example, the variable t is not even involved in returning the new values
back at all!
Cheers,
Chang
|