BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
colouser
Calcite | Level 5

Hello SAS users!

Please see code below. I'm having trouble referencing the following parameters %printz(10-0120, 10-0220) in place of %printz(courses, schedule).

The parameters I want to use are in the format 10-0120 but SAS reads them as two separate parameters (10 and 0120). Please help!

  %macro printz/parmbuff;

        %put Syspbuff contains: &syspbuff;

        %let num=1;

        %let dsname=%scan(&syspbuff,&num);

        %do %while(&dsname ne);

           proc print data=sasuser.&dsname;

           run;

           %let num=%eval(&num+1);

           %let dsname=%scan(&syspbuff,&num);

        %end;

     %mend printz;

%printz(courses, schedule)

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

The parameters I want to use are in the format 10-0120 but SAS reads them as two separate parameters (10 and 0120). Please help!

You need to tell %SCAN() what to use as the delimiter, otherwise it will use its default set which on an ASCII base system are any of these characters:

blank . < ( + & ! $ * ) ; ^ - / , % |

SYSPBUFF will include the parentheses so you probably want your %SCAN() call to use (,) as the delimiters

%let dsname=%scan(&syspbuff,&num,(,));

View solution in original post

13 REPLIES 13
jakarman
Barite | Level 11

Macro quoting made easy - SAS Users (By the way my name is not Quentin)

Why you are needing macro-quoting.... see: SAS(R) 9.4 Macro Language: Reference, Second Edition (%strn %nrstr) but I guess you are needing SAS(R) 9.4 Macro Language: Reference, Second Edition as it is a runtime issue.

---->-- ja karman --<-----
Ksharp
Super User

Actually, I would not use parmbuff anymore, it is very  awkward ,instead using call execute( ) .

%macro printz/parmbuff;

        %put Syspbuff contains: &syspbuff;

        %let num=1;

        %let dsname=%scan(&syspbuff,&num,%str(%(%)%,));

        %do %while(&dsname ne );

           %put &dsname;

           %let num=%eval(&num+1);

           %let dsname=%scan(&syspbuff,&num,%str(%(%)%,));

        %end;

     %mend printz;

%printz(10-0120, 10-0220)

Xia Keshan

Tom
Super User Tom
Super User

The parameters I want to use are in the format 10-0120 but SAS reads them as two separate parameters (10 and 0120). Please help!

You need to tell %SCAN() what to use as the delimiter, otherwise it will use its default set which on an ASCII base system are any of these characters:

blank . < ( + & ! $ * ) ; ^ - / , % |

SYSPBUFF will include the parentheses so you probably want your %SCAN() call to use (,) as the delimiters

%let dsname=%scan(&syspbuff,&num,(,));

Tom
Super User Tom
Super User

For your actual problem of passing in multiple dataset names you should just use BLANK as the delimiter. Then you do not need to use PARMBUFF option.

%macro printz(dslist);

%local num dsname ;

%do num=1 %to %sysfunc(countw(&dslist,%str( ));

  %let dsname=%scan(&dslist,&num,%str( ));

  proc print data=sasuser.&dsname;

  run;

%end;

%mend printz;

%printz(courses schedule)

jakarman
Barite | Level 11

Tom did you test you %let dsname syspbuff?   ( I am getting an error)  Xia's code is correct.

This working, I have put some debugging around it, so you can develop/test a macro as a separate component

44         options mprint mlogic symbolgen ;

45        

46         %macro test/parmbuff;

47         %let num=1 ;

48         %let dsname=%scan(&syspbuff,&num,%nrstr(%(%),) );

49         %put &dsname;

50         %mend;

51        

52         %test(102-101 , 130);

MLOGIC(TEST):  Beginning execution.

MLOGIC(TEST):  %LET (variable name is NUM)

MLOGIC(TEST):  %LET (variable name is DSNAME)

SYMBOLGEN:  Macro variable SYSPBUFF resolves to (102-101 , 130)

SYMBOLGEN:  Macro variable NUM resolves to 1

MLOGIC(TEST):  %PUT &dsname

SYMBOLGEN:  Macro variable DSNAME resolves to 102-101

102-101

MLOGIC(TEST):  Ending execution.

Avoiding the macro approach would make sense. With a little of bad luck there are more strange chars of OS-datasetnamings coming in.

In that case we should ask the OP what he is after for.

The - character is not usable as SAS datasetname unless validmemname=extend has been set SAS(R) 9.4 Language Reference: Concepts, Third Edition.  

---->-- ja karman --<-----
Tom
Super User Tom
Super User

Why all of the unneeded macro quoting?

%macro test / parmbuff ;

%let dsname=%scan(&syspbuff,1,(,));

%put syspbuff=&syspbuff dsname=&dsname ;

%mend test ;

%test(1-203,10-304);


syspbuff=(1-203,10-304) dsname=1-203

jakarman
Barite | Level 11

Tom, good question about the third parameter of the scan function. Is documented as it must be a string.

The char normally having a meaning in macro language are there. To be sure it defined as string following the manual of %str usage.

My question why your coding is working.  would you define it als .() or (), it is failing. But why (,) is working? 
Changing the string to ',' will recognize the comma but not the ( ) chars and  doing it as '(),' will also give correct results.

It is the link to Russ Tyndal, avoiding possible intrepretation conflicts as good coding habit. The (,) looks to be working  but not finding in the documentation why. It could be that %scan macro handles the text string in a way it does not matter as long the , is not in the way. 

I like coding conforming documentation not on trial and error basis. Sorry I have been educated the old way coding. 

When I was working with remote connect sessions it was even more complicated to realize what happened.
Using a %let in the macro expecting it remote executed (open code level) experienced it was resolved and lost at compile time. Perfect code wrong moment processed. The %nrstr was needed to delay the statement to execution time. For better maintainability I changed that  with using defining nested macro-s knowing they were not execute nested but delayed synchronized at different machines.     

An other was using the / in datasetnaming (Unix and %syslput) then a new SAS version added the / for a remote session indication with %syslput. Arghh..... 

...To add...

Agree Tom, most people should fist learn to solve as much as possible without using sas-macro-s.

They are moving too quick into this area.

If you want to develop a macro supporting advanced parameters this usage is an option.  It will be hard work and testing to get it correct so you need to be convinced it is worth all effort. I would say it is only the case having a generic one to be used by a lot of people.

I you want to know other exceptional ones, that are:

SAS(R) 9.4 Macro Language: Reference, Second Edition  sysparm  if you have some job needing different setting known at the os-level.

SAS(R) 9.4 Stored Processes: Developer's Guide, Second Edition  one or several of the many automatic variables set by a web-server or other type service 

Suppose you want some code able to be processed at a lot of those but needing a little bit variation caused by some behavior.

---->-- ja karman --<-----
Tom
Super User Tom
Super User

Wrapping values in parentheses is a basic part of the SAS syntax.  For a good example look at data set options.

You can also use quotes.

Try it.

Tom
Super User Tom
Super User

My question why your coding is working.  would you define it als .() or (), it is failing. But why (,) is working? 

Changing the string to ',' will recognize the comma but not the ( ) chars and  doing it as '(),' will also give correct results.

There are two things going on here.

One is how SAS is parsing the function call. To the SAS tokenizer certain characters cause groupings to occur. The key ones are quotes and parentheses.  So when it sees an opening parentheses it knows to group everything until it sees the matching closing character.  And unlike quotes (or /* */ comments) parentheses can be nested and SAS will match the closing parenthesis to the proper opening one.  Because of this you can use () to protect delimiters.  Note that you only need to start worrying about macro quoting when you want to mask the NORMAL meaning of the characters.  Since here we definitely do NOT want to mask the normal meaning macro quoting is not appropriate.


So the (,) is recognized as the third parameter because the normal delimiter (comma in this case) is protected by the ().  Also the closing parenthesis is not interpreted as ending the function call because it is associated with the opening parenthesis.  Note that they do not need to be completely around the outside of the positional parameter argument.  So in your example of  .()  there is no problem with parsing the string since the value does not contain the delimiter so all three characters would be passed to the function.


The second is that to macro language everything is a string so all characters in the third parameter become part of the list of delimiters.

colouser
Calcite | Level 5

Thank you so much to everyone for your solutions and reference materials. I appreciate your help, the code works well now!

jakarman
Barite | Level 11

Well Tom that is the difference between us, I do not like to invent my own manual by trial and error. I wan to see it is documented and designed to work that way. In this case there are differences between normal SAS datastep languages and the SAS macro language and there are interactions between those.

If you mean SAS tokens... SAS(R) 9.4 Macro Language: Reference, Second Edition    And not all is documented, you are sometimes bumping against the odd ones of real mistakes or implementation failures. Just an example: 

The comment   SAS(R) 9.4 Macro Language: Reference, Second Edition is a nice one.  /*  */  may contain semicolons (documented), but if you use that accidently with a macro comment (%* ) you will notice it is not a token but a string. Parsing of tokens can be surprising. By that macro quoting to understand.

I went a couple of times through all of this with some type of errors.   

---->-- ja karman --<-----
Tom
Super User Tom
Super User

I think you are perhaps expecting too much of documentation.  Does it explain how nested parentheses work in arithmetic expressions?

jakarman
Barite | Level 11

Tom, I know the way SAS language handling normally does. That is not the point.

And I know by experience that you may not assume is the same way within the SAS-macro-s. Previous examples given.

The nested parantheses if have seen being defined (concepts/ tokens). As the remarks un numeric precision (you know).

But do you know problematic errors different behavior in existing running programs can be when going for release updates.
Systems and analyses sometimes based on an observed result but not really well defined.

Forget a moment this dedicated topic, I will give an more understandable one we can agree.

Using SQL you can do a subset on an ordered dataset. Some programmer just coded the result and it was ordered.

When going for a next release the same code gave other results. Of course seeing that SQL there was no order for the results.

Please coorect that one.....    Uhhh like you are doing it was a release fault and a lot of trouble....
We can agree that SQL is documented  to code a ordered clause when you need the result ordered (I hope). 


          

---->-- ja karman --<-----

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 13 replies
  • 6908 views
  • 9 likes
  • 4 in conversation