DATA Step, Macro, Functions and more

Call Symput within parameterized macro

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 12
Accepted Solution

Call Symput within parameterized macro

Hi,

I'm trying to get the code below to work, but I can't seem to figure out what I'm doing wrong. It's probably the Call Symput step. Basically, the user needs to enter in a percent for each color, in whole numbers (so 5 would be 5%). I would like to take the number that is entered and turn it into decimal form and create another macro variable for it. When I test to see if it worked (in the data step test), I get the "Syntax Error" "Apparent symbolic reference DEC_BLUE_A not resolve."

Am I missing an ampersand somewhere, or something? I've tried making a few changes here and there, but I haven't been successful yet.

Thank you for your help.

%WINDOW INPUTS

     #3  @35 "Inputs" COLOR = BLUE

     #6  @10 "Percents" COLOR = RED //

               @15 "Red" COLOR = BLACK +2 RED_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /

               @15 "Black" COLOR = BLACK +2 BLACK_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /

               @15 "Blue" COLOR = BLACK +2 BLUE_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE

;

%DISPLAY INPUTS;

%MACRO DECIMAL2(COLOR);

DATA DECIMAL;

     &COLOR._1 = &&&COLOR/100;

    CALL SYMPUT ("DEC_&COLOR",&COLOR._1);

RUN;

%MEND;

%DECIMAL2(RED_A); %DECIMAL2(BLACK_A); %DECIMAL2(BLUE_A);

DATA TEST; X = &DEC_RED_A; Y = &DEC_BLUE_A; Z = &DEC_BLACK_A; RUN;


Accepted Solutions
Solution
‎11-02-2012 11:56 AM
Super User
Super User
Posts: 6,500

Re: Call Symput within parameterized macro

When creating macro variables in a macro (your macro is using CALL SYMPUT) that you want to use after the macro has finished you need to be careful to make sure that the macro variable is not local to that macro.

You could slap in a %GLOBAL statement to force the macro variable to defined in the global scope.

%MACRO DECIMAL2(COLOR);

%global DEC_&COLOR ;

DATA DECIMAL;

     &COLOR._1 = &&&COLOR/100;

    CALL SYMPUT ("DEC_&COLOR",&COLOR._1);

RUN;

%MEND;

But it would be better to create it conditionally to prevent error messages if the macro variable already exist in an outer executing macro scope.

%macro decimal2(color);

%if not %symexist(dec_&color) %then %global dec_&color ;

data decimal;

   &color._1 = &&&color/100;

   call symputx("dec_&color",&color._1);

run;

%mend decimal2 ;

%let red=200 ;

%symdel dec_red /nowarn;

%decimal2(red);

%put red=&red dec_red=&dec_red ;

Also, do you really need the DATA step?

%macro decimal2(color);

%if not %symexist(dec_&color) %then %global dec_&color ;

%let dec_&color = %sysevalf(&&&color/100) ;

%mend decimal2 ;

View solution in original post


All Replies
Respected Advisor
Posts: 3,124

Re: Call Symput within parameterized macro

'%global DEC_RED_A DEC_BLUE_A DEC_BLACK_A' will help?

Haikuo

Super User
Posts: 10,500

Re: Call Symput within parameterized macro

I suspect that part of your problem is the value of &&&Color is supposed to resolve to the numeric value in Red_1, Blue_1 or Black_1. However since you are calling with COLOR=RED_A the resolution will never be one of those values entered in the window.

Your calculation line is resolving as:

RED_A_1 = &RED_A/ 100;

You might try using two parameters in your macro Color and suffix.

and

&color.&suffix = &color._1 / 100;

call symput("Dec_&Color.&suffix",&color.&suffix);

Valued Guide
Posts: 632

Re: Call Symput within parameterized macro

If you need macro variables, I would suggest not using the DATA step.

%* Macro window;
%WINDOW INPUTS
     #3  @35 "Inputs" COLOR = BLUE
     #6  @10 "Percents" COLOR = RED //
               @15 "Red" COLOR = BLACK +2 RED_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /
               @15 "Black" COLOR = BLACK +2 BLACK_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /
               @15 "Blue" COLOR = BLACK +2 BLUE_1 4 COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE;
%DISPLAY INPUTS;
%let dec_red = %sysevalf(&red_1/100);
%let dec_black = %sysevalf(&black_1/100);
%let dec_blue = %sysevalf(&blue_1/100);
%put &red_1 &dec_red;
%put &black_1 &dec_black;
%put &blue_1 &dec_blue;

OTOH if you are going to use these values in a DATA step then use the WINDOW statement and avoid the use of the macro language altogether.

***************************
* DATA step window;
data colors;
WINDOW INPUTS
     #3  @35 "Inputs" COLOR = BLUE
     #6  @10 "Percents" COLOR = RED //
               @15 "Red" COLOR = BLACK +2 RED_1 4. COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /
               @15 "Black" COLOR = BLACK +2 BLACK_1 4. COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE /
               @15 "Blue" COLOR = BLACK +2 BLUE_1 4. COLOR = GREEN REQUIRED = NO ATTR = UNDERLINE;
DISPLAY INPUTS;
dec_red = red_1/100;
dec_black = black_1/100;
dec_blue = blue_1/100;
put red_1 dec_red;
put black_1 dec_black;
put blue_1 dec_blue;
stop;
run;

Occasional Contributor
Posts: 6

Re: Call Symput within parameterized macro

Hello,

I had somewhat similar a problem; it seemed call symput inside a parametrized macro doesn't work. I found this article helpful: http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#tw3514-symput.htm

So it's a variable scope problem: When there is that "run;" after the data step, the scope of the variables you define in the data step will be the enclosing macro only. I just removed the "run;" and my code started to work. However, I do not know if that's the best way to handle the problem.

Super User
Posts: 9,681

Re: Call Symput within parameterized macro

Or use call symputx to assign it to a global macro variable .

call symputx('x',x,'G');

Solution
‎11-02-2012 11:56 AM
Super User
Super User
Posts: 6,500

Re: Call Symput within parameterized macro

When creating macro variables in a macro (your macro is using CALL SYMPUT) that you want to use after the macro has finished you need to be careful to make sure that the macro variable is not local to that macro.

You could slap in a %GLOBAL statement to force the macro variable to defined in the global scope.

%MACRO DECIMAL2(COLOR);

%global DEC_&COLOR ;

DATA DECIMAL;

     &COLOR._1 = &&&COLOR/100;

    CALL SYMPUT ("DEC_&COLOR",&COLOR._1);

RUN;

%MEND;

But it would be better to create it conditionally to prevent error messages if the macro variable already exist in an outer executing macro scope.

%macro decimal2(color);

%if not %symexist(dec_&color) %then %global dec_&color ;

data decimal;

   &color._1 = &&&color/100;

   call symputx("dec_&color",&color._1);

run;

%mend decimal2 ;

%let red=200 ;

%symdel dec_red /nowarn;

%decimal2(red);

%put red=&red dec_red=&dec_red ;

Also, do you really need the DATA step?

%macro decimal2(color);

%if not %symexist(dec_&color) %then %global dec_&color ;

%let dec_&color = %sysevalf(&&&color/100) ;

%mend decimal2 ;

☑ This topic is SOLVED.

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

Discussion stats
  • 6 replies
  • 1126 views
  • 6 likes
  • 7 in conversation