C/C++、C#、VBなどでStatic宣言による静的変数、適材適所で利用できれば大変便利な機能ですよね。普段は何気なく使っている静的変数ですが、コンパイラを製作する上で、静的変数を取り込もうとすると、なにかと問題が生じるものなんです。一筋縄ではいきません。

静的変数はローカル領域内で参照可能でありながら、一つのアプリケーションでは唯一の存在になる変数です。ようは、任意のローカル領域内からのみ参照できるグローバル変数ってヤツです。

これをバカ正直にグローバル変数として定義していると変数名の衝突が起こりかねませんね。コンパイラは静的変数の名前管理は一ひねりする必要がありそうです。実体はグローバル領域にあるので、対象となるローカル領域がいつ呼び出されようと、アプリケーション内に存在するすべての静的変数はプロセス開始時に初期化され、終了時に破棄しなければなりません(破棄の場合は必要に応じてデストラクタを呼び出してやる必要があります)。

ユーザーの皆さんは直接的に関係ありませんが、ABの静的変数の内部表現は下記のようになっています。

Sub test()
 Static a As Long
End Sub

このような定義があったとすると、この静的変数aはグローバル領域に下記のような名前で管理されます。

Static.[class].test.[id].a

※クラスメソッドの場合はclassにクラス名が入ります。
※idにはすべての関数を識別可能な排他値が入ります。

本来であればクラス名と関数名と変数名ですべての静的変数を表現できるのですが、ABには関数のオーバーロード機能が付いているんですよね。なので、idという排他的付加データが必要になるというワケです。

これで静的変数の表現は可能になりました。あとは、変数名の前についている名前空間データを識別してアクセス規制をかけるだけです。こうすることで、グローバル領域に確保された変数データを任意の関数内から参照可能になります。

さて、もしこの変数aが何らかの実体オブジェクトだった場合、コンストラクタを呼び出すのはいつになるのでしょうか?正解は関数呼び出しではなく、アプリケーション初期化時です。ABはプロセス開始直後に_System_StartupProgram関数がコールバックされる仕組みになっているので、このタイミングで静的変数の初期化をしてしまおうと考えています。

こんな感じで、静的メンバに引き続き、静的ローカル変数の対応もほぼ確実にものになってきました。残るは静的メソッド。今夜じゅうはムリかな~