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)
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,(,));
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.
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
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,(,));
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)
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.
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
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.
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.
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.
Thank you so much to everyone for your solutions and reference materials. I appreciate your help, the code works well now!
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.
I think you are perhaps expecting too much of documentation. Does it explain how nested parentheses work in arithmetic expressions?
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).
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.