前のページ|次のページ

マクロ変数のスコープの例

既存のマクロ変数の値の変更

マクロプロセッサは、マクロ変数を作成できるマクロプログラムステートメント(%LETステートメントなど)を実行するときに、新しいマクロ変数を作成するのではなく、既存のマクロ変数の値を変更しようとします。ただし、%GLOBALステートメントと%LOCALステートメントを除きます。
説明のため、次の%LETステートメントについて考えます。2つの%LETステートメントによって、マクロ変数NEWに値を割り当てています。
%let new=inventry;
%macro name1;
   %let new=report;
%mend name1;
次のステートメントをサブミットしたとします。
%name1

data &new;
data report;
NEWがグローバル変数として存在しているため、マクロプロセッサは新しい変数を作成せず、この変数の値を変更します。マクロNAME1のローカルシンボルテーブルは空のままです。
次の図は、NAME1の実行前、実行中、実行後の、グローバルシンボルテーブルとローカルシンボルテーブルのコンテンツを示しています。
シンボルテーブルのスナップショット
シンボルテーブルのスナップショット

ローカル変数の作成

マクロプロセッサは、マクロ変数を作成できるマクロプログラムステートメントを実行するときに、使用可能な同じ名前のマクロ変数が存在しなければ、その変数をローカルシンボルテーブルに作成します。次の例について考えてみます。
%let new=inventry;
%macro name2;
   %let new=report;
   %let old=warehse;
%mend name2;

%name2

data &new;
   set &old;
run;
NAME2が実行されると、SASコンパイラはその後のステートメントを次のように解釈します。
data report;
   set &old;
run;
マクロNAME2の実行終了後、マクロプロセッサは&OLD参照を検出します。このとき、マクロ変数OLDは存在しません。マクロプロセッサは参照を置換できないため、警告メッセージを発行します。
次の図は、さまざまなステージでのグローバルシンボルテーブルとローカルシンボルテーブルのコンテンツを示しています。
さまざまなステージでのシンボルテーブル
実行前、実行中、実行後のシンボルテーブル。
一方、次のプログラムのように、マクロNAME2の内部にSASステートメントを配置したとします。
%let new=inventry;
%macro name2;
   %let new=report;
   %let old=warehse;
   data &new;
      set &old;
   run;
%mend name2;

%name2
この場合、マクロプロセッサは、NAME2の実行中にSETステートメントを生成するため、NAME2のローカルシンボルテーブルでOLDを検出します。したがって、このマクロを実行すると次のステートメントが生成されます。
data report;
   set warehse;
run;
ネストのレベル数に関係なく、同じルールが適用されます。次の例について考えてみます。
%let new=inventry;
%macro conditn;
   %let old=sales;
   %let cond=cases>0;
%mend conditn;

%macro name3;
   %let new=report;
   %let old=warehse;
   %conditn
      data &new;
         set &old;
         if &cond;
      run;
%mend name3;

%name3
マクロプロセッサは、次のステートメントを生成します。
data report;
   set sales;
   if &cond;
run;
マクロプロセッサが&COND参照に到達する前にCONDITNの実行が終了しているため、マクロプロセッサが&COND参照を置換しようとしたときには、すでにCONDという名前の変数は存在しません。したがって、マクロプロセッサは警告メッセージを発行し、定数テキストの一部として未置換の参照を生成します。次の図に、各ステップでのシンボルテーブルを示します。
2つのレベルのネストを示すシンボルテーブル
2つのレベルのネストを示すシンボルテーブル
マクロ呼び出しの配置は、ネストされたスコープを作成することであって、マクロ定義の配置ではありませんので注意してください。たとえば、NAME3の内部でCONDITNを呼び出すと、ネストされたスコープが作成されます。NAME3の内部でCONDITNを定義する必要はありません。

マクロ変数をローカルにする

マクロプロセッサに、既存のマクロ変数の値を変更させるのではなく、確実にローカルマクロ変数を作成させる必要がある場合があります。このような場合、%LOCALステートメントを使用してマクロ変数を作成します。
マクロの実行停止後にマクロ変数の値が必要でない場合、マクロ内に作成するすべてのマクロ変数を必ずローカルにします。マクロ変数の値を誤って変更する可能性を最小限にすると、大規模なマクロプログラムのデバッグが容易になります。また、ローカルマクロ変数を定義するマクロの実行が終了すると、それらのローカルマクロ変数は存在しませんが、グローバルマクロ変数はSASセッションが存続する限り存在します。したがって、ローカル変数を使用すると、ストレージ全体の使用量が減ります。
たとえば、次に示すように、マクロNAMELSTを使用してVARステートメント用の名前のリストを作成するとします。
%macro namelst(name,number);
   %do n=1 %to &number;
      &name&n
   %end;
%mend namelst;
次のプログラムでNAMELSTを呼び出します。
%let n=North State Industries;

proc print;
   var %namelst(dept,5);
   title "Quarterly Report for &n";
run;
このマクロを実行すると、SASコンパイラは各ステートメントを次のように解釈します。
proc print;
   var dept1 dept2 dept3 dept4 dept5;
   title "Quarterly Report for 6";
run;
マクロプロセッサは、%DOループの反復を実行するたびに、グローバル変数Nの値を変更します。(ループの実行が停止すると、Nの値は6になります。これについては、%DOステートメントで説明されています。)競合を避けるには、次に示すように、%LOCALステートメントを使用してローカル変数Nを作成します。
%macro namels2(name,number);
   %local n;
   %do n=1 %to &number;
      &name&n
   %end;
%mend namels2;
ここで、次のように同じプログラムを実行します。
%let n=North State Industries;

proc print;
   var %namels2(dept,5);
   title "Quarterly Report for &n";
run;
マクロプロセッサは、次のステートメントを生成します。
proc print;
   var dept1 dept2 dept3 dept4 dept5;
   title "Quarterly Report for North State Industries";
run;
次の図に、NAMELS2の実行前、NAMELS2の実行中、およびマクロプロセッサがTITLEステートメントで&N参照を検出したときのシンボルテーブルを示します。
同じ名前を持つグローバル変数とローカル変数のシンボルテーブル
同じ名前を持つグローバル変数とローカル変数

グローバルマクロ変数の作成

%GLOBALステートメントを使用すると、同じ名前の変数がまだそこに存在しなければ、現在のスコープとは無関係にグローバルマクロ変数が作成されます。
たとえば、次のプログラムでは、マクロCONDITNに、マクロ変数CONDをグローバル変数として作成する%GLOBALステートメントが含まれています。
%macro conditn;
   %global cond;
   %let old=sales;
   %let cond=cases>0;
%mend conditn;
このプログラムの他の部分を次に示します。
%let new=inventry;

%macro name4;
   %let new=report;
   %let old=warehse;
   %conditn
   data &new;
      set &old;
      if &cond;
   run;
%mend name4;

%name4
NAME4を呼び出すと、次のステートメントが生成されます。
data report;
   set sales;
   if cases>0;
run;
NAME4の外部にSAS DATAステップステートメントを配置するとします。この場合、マクロプロセッサが参照を置換するには、すべてのマクロ変数をグローバルにする必要があります。CONDITNの実行が開始される時点で、NAME4の%LETステートメントによって、すでにOLDがNAME4に対するローカル変数として作成されているため、CONDITNの%GLOBALステートメントにOLDを追加することはできません。(%GLOBALステートメントを使用して、既存のローカル変数をグローバルにすることはできません。)
したがって、OLDをグローバルにするには、変数参照が現れる前の任意の場所で、次のマクロNAME5に示すように%GLOBALステートメントを使用します。
%let new=inventry;

%macro conditn;
   %global cond;
   %let old=sales;
   %let cond=cases>0;
%mend conditn;

   %macro name5;
      %global old;
      %let new=report;
      %let old=warehse;
      %conditn
   %mend name5;

%name5

data &new;
   set &old;
   if &cond;
run;
ここで、NAME5の%LETステートメントでは、ローカル変数としてOLDを作成するのではなく、既存のグローバル変数OLDの値を変更しています。SASコンパイラは、各ステートメントを次のように解釈します。
data report;
   set sales;
   if cases>0;
run;

ローカル変数の値に基づくグローバル変数の作成

パラメータなどのローカル変数をマクロの外部で使用するには、次のプログラムに示すように、ローカル変数の値を、%LETステートメントを使用して別の名前のグローバル変数に割り当てます。
%macro namels3(name,number);
   %local n;
   %global g_number;
   %let g_number=&number;
   %do n=1 %to &number;
      &name&n
   %end;
%mend namels3;
ここで、マクロNAMELS3を次のプログラムから呼び出します。
%let n=North State Industries;

proc print;
   var %namels3(dept,5);
   title "Quarterly Report for &n";
   footnote "Survey of &g_number Departments";
run;
コンパイラは、各ステートメントを次のように解釈します。
proc print;
   var dept1 dept2 dept3 dept4 dept5;
   title "Quarterly Report for North State Industries";
   footnote "Survey of 5 Departments";
run;
前のページ|次のページ|ページの先頭へ