2017年8月10日木曜日

そのマクロ変数、ローカル?グローバル?③CALL SYMPUT編



「CALL SYMPUT」 または 「CALL SYMPUTX」 で定義したマクロ変数が、ローカル・グローバルどちらになるのか解説します。


まずは前提知識。




シンボルテーブル


マクロ変数を入れる箱の事をシンボルテーブルといいます。

・ローカルシンボルテーブル ・・・ ローカルマクロ変数を入れる箱
・グローバルシンボルテーブル ・・・ グローバルマクロ変数を入れる箱

図1
つまりマクロ変数がローカルなのか?グローバルなのか?という問題は、どちらのシンボルテーブルに入るかを問題としているわけです。




CALL SYMPUT で定義したマクロ変数の、ローカル・グローバルの判定方法


📝 説明の前に・・
SAS社のリファレンスの説明と実際の動作に差異があったため、私の実験結果に基づく動作の説明も含みます。何か不足している点など、お気づきの点がありましたらコメントいただけると幸いです。



CALL SYMPUT が含まれるデータステップの「run;」がマクロの中にあるのか、マクロの外にあるのかで、ローカル・グローバルの判定結果が変わります。


マクロの中に「run;」がある
%macro TEST;
   data _null_;
      call symput("MAC1", "1234");
   run;
%mend;
%TEST;

マクロ外に「run;」がある
data _null_;
   call symput("MAC1", "1234");
run;



判定は以下のとおり。
図2



具体例


では具体例をみていきましょう。
まず今回の解説で使うマクロ変数を予めリセット(削除)しときます。

%symdel MAC1 MAC2 MAC3 MAC4 MAC5 MAC6 MAC7 MAC8 MAC9 MAC10 / nowarn;



① マクロ外で定義したマクロ変数が、「グローバル」になる例。

data _null_;
   call symput("MAC1","abcd");
run;
%put _user_;

ログ
GLOBAL MAC1 abcd


② マクロ内で定義したマクロ変数が、「グローバル」になる例。

%macro TEST;
    data _null_;
       call symput("MAC2","abcd");
    run;

    %put _user_;
%mend;
%TEST;

ログ
GLOBAL MAC2 abcd


③ マクロ内で定義したマクロ変数が、「ローカル」になる例。

%macro TEST;
    %let MAC3 = abcd;

    data _null_;
       call symput("MAC4","1234");
    run;

    %put _user_;
%mend;
%TEST;

ログ
TEST MAC3 abcd
TEST MAC4 1234



例外

上のほうで示した「図2」のオレンジ色で示した「例外あり」のルートでは以下の例外が起きます。

① マクロ内で「SQLプロシジャ」の後に実行するCALL SYMPUTのマクロ変数は「ローカル」になる。

%macro TEST;
    proc sql ;
       select * from SASHELP.CLASS;
    quit;

    data _null_;
       call symput("MAC5","abcd");
    run;

    %put _user_;
%mend;
%TEST;

ログ
TEST MAC5 abcd


② マクロ内で「%GOTO &マクロ変数」や「%GOTO %マクロ名」みたいな記述があると、その後のCALL SYMPUTのマクロ変数は「ローカル」になる。

%let MAC6=GOGO;

%macro TEST;
    %goto &MAC6;
    %GOGO:

    data _null_;
       call symput("MAC7","1234");
    run;

    %put _user_;
%mend;
%TEST;

ログ
TEST MAC7 1234
GLOBAL MAC6 GOGO



③ マクロで「parmbuff」を使っていると、CALL SYMPUTのマクロ変数は「ローカル」になる。

%macro TEST / parmbuff;
    data _null_;
       call symput("MAC8","1234");
    run;

    %put _user_;
%mend;
%TEST;

ログ
TEST MAC8 1234



失敗例


① たまに質問を頂くので注意喚起。
CALL SYMPUTで定義したマクロ変数を同じデータステップ内で参照することは出来ません。

data _null_;
   call symput("MAC9","123");
   x = &MAC9;
run;

ログ
 WARNING: MAC9のシンボリック参照を解決できません。




② これは上級者が遭遇する失敗例。
「CALL SYMPUTでマクロ変数を定義」&「そのマクロ変数を使用(参照)する」みたいなマクロがあったとして、そのマクロをCALL EXECUTEで実行すると、うまくマクロ変数の参照が出来ないようです。

%macro TEST;
   data _null_;
      call symput("MAC10","123");
   run;

   %put &MAC10;
%mend;

data _null_;
   call execute('%TEST');
run;

ログ
 WARNING: MAC10のシンボリック参照を解決できません。

SAS社のUsage Noteにも載ってました。



てことで、どうでしょう、、正直最初はなんじゃこりゃーって感じでいろんなシチュエーションがあって覚えらんないですよね。慣れれば、なんとなくわかってきます。




記事一覧

1. 基本概念
2. %LET編
3. CALL SYMPUT編
4. マクロ変数の展開
5. マクロ変数の作成場所を明示的に指定する

0 件のコメント:

コメントを投稿