DATA Step, Macro, Functions and more

Multiple ampersands

Accepted Solution Solved
Reply
Contributor
Posts: 29
Accepted Solution

Multiple ampersands

I haven't understood how are multiple ampersands resolved? I formulated a logic that whenever two ampersands occur together, they get resolved into one ampersand (moving from left to right) and one can think of a bracket enclosing the entire text following that ampersand then..For e.g. &&m1&m2 should logically mean &(m1&m2) &((&m1&m2&m3), however, it doesnt work like this and &&&&&m1&m2&m3 gives the same answer as &&&&m1&m2&m3

Please enlighten...

Message was edited by: Varun Nakra.. I am not able to reply to the post here, hence, editing original message.


Accepted Solutions
Solution
‎11-02-2012 10:07 PM
SAS Super FREQ
Posts: 8,743

Re: Multiple ampersands

Hi,

There have been many previous postings on this topic. Searching for previous posts you would have found references to the FORWARD SCAN rule and the RESCAN rule of the Macro facility.

Several folks suggested turning on SYMBOLGEN. In a multiple ampersand situation, there is no better helper than SYMBOLGEN. You can ask people how they think resolution happens, many people have their own internal logic for what happens, but SYMBOLGEN shows you how resolution REALLY happened. Reading and understanding the documentation is essential. Guessing about multiple ampersand resolution is not good enough. Asking other folks their opinion is not good enough. Turn on SYMBOLGEN. Turn on SYMBOLGEN. Turn on SYMBOLGEN. And if you have a macro program, turn on MPRINT and MLOGIC, too.

Start your test with a %PUT _GLOBAL_ or %PUT _ALL_, then run your test -- with SYMBOLGEN turned on. Do not move down into 15 ampersands until you understand how &var, &one&two, &x..&y and &&var&i works. Then and only then venture into &&&var or other more esoteric usages.

That's my advice.

Here are some of the previous forum postings.

https://communities.sas.com/message/124977#124977

https://communities.sas.com/message/12495#12495

I agree with Art. I have been using SAS Macro variables for quite some time and hardly ever use more than 3 ampersands and, like Art, my most common usage is &&var&i.

cynthia

View solution in original post


All Replies
Valued Guide
Posts: 632

Re: Multiple ampersands

You are very close.  The macro reference is indeed broken into parts - left to right.  Non macro elements are passed along for each pass.  for this example say that &m2 contains the text: Fred

&&m1&m2

&&  m1  &m2

&  m1  Fred

&m1Fred

A good way to learn how more complex macro variables are resolved is to use symbolgen.  something like.

options symbolgen;

%put &&m1&m2;

Contributor
Posts: 29

Re: Multiple ampersands

Thanks for the reply Art, however, what I am looking at is resolution of more than 2 ampersands such as  - &&&&&m1&m2&m3.
Why does &&&&m1&m2&m3 and  &&&&&m1&m2&m3 have the same result?

Please explain the logic behind resolution of such multiple ampersands..

PROC Star
Posts: 1,233

Re: Multiple ampersands

You are correct that two ampersands resolve to one, and trigger the value to be rescanned.  But there is no bracketing, as described in your first post.

Here are some notes on the resolution of your two examples, showing each pass of the scanning

%let m1=x;

%let m2=y;

%let m3=z;

%let m1yz=foo;

%let xyz=foo2;

&&&&m1&m2&m3  <- original value

&&m1yz  <- && became & | && became & | m1 is just text | &m2 resolved to y | &m3 resolved to z

&m1yz  <- && became & | m1yz is just text

foo <- &m1yz resolved to foo

&&&&&m1&m2&m3

&&xyz <- && became & | && became & | &m1 resolved to x | &m2 resolved to y | &m3 resolved to z

&xyz  <-&& became & | xyz is just text

foo2 <- &xyz becomes foo2

So as shown above, the two values do resolve differently.  If you are seeing the same result, I would guess that maybe you do not have macro variables &m1 &m2 &m3 defined.  In that case, you will get something like below. I'm less confident that I got this part right, without having SAS on hand to double check....:

&&&&m1&m2&m3

&&m1&m2&m3 <- with note that &m2 and &m3 couldn't be resolved

&m1&m2&m3 <- (cant remember if another note about &m2 and &m3 not resolving will be generated)

&m1&m2&m3 <- with note that &m1 didn't resolve.

&&&&&m1&m2&m3

&&&m1&m2&m3 <-with note that &m1 &m2 &m3 couldn't be resolved

&&m1&m2&m3

&m1&m2&m3

&m1&m2&m3 <-final value

Hope I got that right, as I don't have SAS in front of me.  If you want to learn more about this and other complexities of macro processing, I suggest you get a copy of Art's macro book ("Carpenter's Complete Guide to SAS Macro Language"), it's excellent.

Valued Guide
Posts: 632

Re: Multiple ampersands

I am hoping that you do not really have to have this many ampersands.  With very few exceptions (such as multiplely subscripted arrays - which I try very hard to avoid) three ampersands is quite enough.  I tend to use the &&var&i quite often, &&&var less often.  As @Quentin stated each time the scanner passes through the list it will write a note for each unresolvable reference.  You can see these using the %PUT with symbolgen.

Super User
Super User
Posts: 6,502

Re: Multiple ampersands

They don't produce the same result for me.

%symdel m1 m2 m3 fred sam m1sam / nowarn ;

%let m1=fred;

%let m2=sam;


%put |&&&&&m1&m2&m3|;

WARNING: Apparent symbolic reference M3 not resolved.

WARNING: Apparent symbolic reference FREDSAM not resolved.

WARNING: Apparent symbolic reference M3 not resolved.

|&fredsam&m3|


%put |&&&&m1&m2&m3|;

WARNING: Apparent symbolic reference M3 not resolved.

WARNING: Apparent symbolic reference M3 not resolved.

WARNING: Apparent symbolic reference M1SAM not resolved.

WARNING: Apparent symbolic reference M3 not resolved.

|&m1sam&m3|

Contributor
Posts: 29

Re: Multiple ampersands

Finally, I am able to reply.. The problem was with my browser. Posting the message here.

@Art, yes, that is true..but I wanted to understand the programming logic of resolving so many ampersands by SAS from a learning point of view. I also have your book and will read it thoroughly very soon..Great to have the opportunity to 'speak' to you here

@Quentin, thanks for recommending Art's book.. Taking your example forward -

%put &&&&m1&m2&m3

1. && resolves to &

2. && resolves to & (at this stage we have two &'s in front of m1)

3. m2 resolves to y

4. m3 resolves to z

5. && resolves to &

6. M1YZ resolves to foo

This suggests that SAS is resolving the macro variables from left to right. It tries to resolve two ampersands into one ampersand until it reaches two ampersands in front of a text after which it resolves all the rest of the macro variables and then comes back to resolve the two leading ampersands.

%put &&&&&m1&m2&m3

1. && resolves to &

2. && resolves to & (at this stage we have three &'s in front of m1)

3. m1 resolves to x

3. m2 resolves to y

4. m3 resolves to z

5. && resolves to &

6. XYZ resolves to foo2

This suggests that SAS is resolving the macro variables from left to right. It tries to resolve two ampersands into one ampersand until it reaches three ampersands in front of a macro variable after which it resolves all the macro variables one by one and then comes back to resolve the two leading ampersands.

The difference in the two resolutions above is - in the first case when SAS had two ampersands in front of m1, it didnt interpret m1 as a macro variable, however, in the second case, when SAS reached three ampersands in front of m1, it interpreted m1 as a macro variable.

So I thought of playing with it further and using a text 'varun' and not a macro variable in place of m1.

%put &&&&varun&m2&m3

1. && resolves to &

2. && resolves to & (at this stage we have two &'s in front of varun)

3. m2 resolves to y

4. m3 resolves to z

5. && resolves to &

6. varunYZ not resolved.

This suggests that SAS is resolving the macro variables from left to right. It tries to resolve two ampersands into one ampersand until it reaches two ampersands in front of a text after which it resolves all the rest of the macro variables and then comes back to resolve the two leading ampersands.

%put &&&&&varun&m2&m3

1. && resolves to &

2. && resolves to & (at this stage we have three &'s in front of varun)

3. && resolves to & (at this stage we have two &'s in front of varun)

4. && resolves to & (at this stage we have one & in front of varun)

5. m2 resolves to y

6. m3 resolves to z

7. varunyz not resolved

Now I couldn't understand when SAS reached 3 ampersands in front of a text 'varun', it didn't generate a warning at this stage that apparent symbolic reference 'varun' couldnt be resolved. Instead, it continued resolutions of the ampersands further till it reached one ampersand in front of varun.

I am confounded by the order of resolution of macro variables when multiple ampersands are used. What logic does SAS follow?

I think multiple ampersands for multiple macro variables at the same time may create some more confusion.

P.S. I am doing this from a learning point of view; trying to understand the logic used by SAS here.

Message was edited by: Varun Nakra.. I am not able to reply to the post here, hence, editing original message.

PROC Star
Posts: 1,233

Re: Multiple ampersands

Hi,

I think the rule is actually simpler than you think.  I think the rule is:

"When building tokens, two consecutive ampersands resolve to a single ampersand, and trigger the string to be rescanned in an additional pass."

You don't need your part about "until it reaches n ampersands in front of a text..."

So in your last example.

%let m2=y;

%let m3=z;

* (no other macro variables defined);

%put &&&&&varun&m2&m3;

Pass #1 resolves to &&&varunyz

Explanation: Ampsersands #1 and #2 resolve to one.  Ampersands #3 and #4 resolve to one.  Ampserand #5 begins a macro variable reference, because it is an ampersand followed by  character (v) which is valid as the start of a macro variable name.  The macro processor tries to resolve &varun and it cannot (because it is not defined, I assume, in your example). So it returns &varun.  &m2 resolves to y.  &m3 resolves to z.

Pass #2. resolves to &&varunyz.

Explanation:

Ampersands #1 and #2 resolve to one ampersand.  Ampersand #3 begins a macro variables reference, and SAS tries to resolved &varunyz.  It cannot, so returns &varunyz.

Pass #3 resolves to &varunyz

Explanation: Ampersands #1 and #2 resolve to one ampersand. There is no macro variables reference.

Pass #4 resolves to &varunyz

Explanation: SAS sees &varunyz as a macro variable reference, tries to resolve it.  When it cannot, it returns &varunyz.

So I would expect your %put statement to to return:

&varunyz

I would also expect one message that &varun could not be resolved (from pass 1) , and two messages that &varunyz could not be resolved (from passes 2 and 4).

Is that consistent with what you are seeing?   If not, could you post the log?

Regards,

--Q.

Solution
‎11-02-2012 10:07 PM
SAS Super FREQ
Posts: 8,743

Re: Multiple ampersands

Hi,

There have been many previous postings on this topic. Searching for previous posts you would have found references to the FORWARD SCAN rule and the RESCAN rule of the Macro facility.

Several folks suggested turning on SYMBOLGEN. In a multiple ampersand situation, there is no better helper than SYMBOLGEN. You can ask people how they think resolution happens, many people have their own internal logic for what happens, but SYMBOLGEN shows you how resolution REALLY happened. Reading and understanding the documentation is essential. Guessing about multiple ampersand resolution is not good enough. Asking other folks their opinion is not good enough. Turn on SYMBOLGEN. Turn on SYMBOLGEN. Turn on SYMBOLGEN. And if you have a macro program, turn on MPRINT and MLOGIC, too.

Start your test with a %PUT _GLOBAL_ or %PUT _ALL_, then run your test -- with SYMBOLGEN turned on. Do not move down into 15 ampersands until you understand how &var, &one&two, &x..&y and &&var&i works. Then and only then venture into &&&var or other more esoteric usages.

That's my advice.

Here are some of the previous forum postings.

https://communities.sas.com/message/124977#124977

https://communities.sas.com/message/12495#12495

I agree with Art. I have been using SAS Macro variables for quite some time and hardly ever use more than 3 ampersands and, like Art, my most common usage is &&var&i.

cynthia

Contributor
Posts: 29

Re: Multiple ampersands

Thanks for the reply Quentin, however, what I posted was the Symbolgen output of resolution of ampersands in the log.

%put &&&&&varun&m2&m3

1. && resolves to &

2. && resolves to & (at this stage we have three &'s in front of varun)

3. && resolves to & (at this stage we have two &'s in front of varun)

4. && resolves to & (at this stage we have one & in front of varun)

5. m2 resolves to y

6. m3 resolves to z

7. varunyz not resolved

Statements 1 to 7 are the ones written in the log by symbolgen which suggest that in the first pass amp#1, amp#2 get resolved to one amp; amp#3, amp#4 get resolved to one amp. Now according to your explanation, amp#5 should have tried resolving varun, however, it doesn't and no message is printed for it. Instead, it resolves the resulting ampersands before it could approach resolving m2 and m3.

Many thanks Cynthia, I will read all the documentation and posts that you suggested. I have been using symbolgen, MPRINT and MLOGIC in my macro programming, however, was just intrigued by the logic behind the multiple scanning resolution. A common usage wont let me go beyond &&var&i, however, I was just chasing this from a learning point of view.

Thanks all

Contributor
Posts: 29

Re: Multiple ampersands

After reading the threads that Cynthia referred to and the SUGI pdf, I can now calculate the correct answer to such multiple ampersand references, however, the log using Symbolgen doesn't show the 'correct' resolution steps at times (publishes && resolves to & more number of times than it is required OR, publishes && resolves to & out of order).. This happens when multiple ampersands occur before a text and not a macro variable, however, the result from the resolution is according to the forward scan and rescan rules.

1. Rule1 : Every pair of ampersands gets resolved to a single ampersand and that single ampersand is 'left alone' until the scanning of the complete string takes place

2. Rule2 : Since, multiple ampersands have been used, a rescan occurs following Rule1.

PROC Star
Posts: 1,233

Re: Multiple ampersands

FYI Varun, I posted my last reply before seeing your note that after you read the other thread, we are now in agreement as to the rules for handling multiple ampersands.  Glad it makes sense.

Contributor
Posts: 29

Re: Multiple ampersands

Thanks Q for taking the pain. Yes, Symbolgen did behave chimerically on my laptop too, however, the results were consistent with our expectations. FYI, i was using SAS 9.1. I'll try the code on 9.2 too. Now, it gives me a sense of relief. The SUGI paper referred by Cynthia was enlightening

PROC Star
Posts: 1,233

Re: Multiple ampersands

Hi Varun,

Well, I cranked up an old PC with SAS on it, and with SYMBOLGEN on, I do see messages that SAS tried to resolve both VARUN and VARUNYZ, as I had expected:

8    options symbolgen;
9    %let m2=y;
10   %let m3=z;
11   %put &&&&&varun&m2&m3;
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Unable to resolve the macro variable reference &varun
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Unable to resolve the macro variable reference &varun
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable M2 resolves to y
SYMBOLGEN:  Macro variable M3 resolves to z
WARNING: Apparent symbolic reference VARUNYZ not resolved.
&varunyz


I was surprised that the order of the symbolgen lines suggests that SAS tried to resolve &varun twice before &m2 and &m3.  And I don't think I would trust symbolgen enough to believe it.  If it's true, to me its an oddity of the word scanner/tokenizer/macro processor/whatever construct you choose, but one which does not impact the final outcome, of &varunyz being returned.  And, if you define &varun, then the symbolgen messages are consistent with my belief that &m2 and &m3 are resolved in the first pass.  In my mental map of how the macro languages work, below I think of symbolgen lines 1-5 as coming from a first pass which resolved to &&QYZ, line 6 from a second pass which resolved to &QYZ, and the warning message coming from a third pass which could not find a macro variable named QYZ.

12   options symbolgen;
13   %let varun=Q;
14   %let m2=y;
15   %let m3=z;
16   %put &&&&&varun&m2&m3;
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable VARUN resolves to Q
SYMBOLGEN:  Macro variable M2 resolves to y
SYMBOLGEN:  Macro variable M3 resolves to z
SYMBOLGEN:  && resolves to &.
WARNING: Apparent symbolic reference QYZ not resolved.
&Qyz

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 13 replies
  • 2959 views
  • 7 likes
  • 5 in conversation