HSPのモジュール機能を活用してみる ACT-1

モジュール機能とは

今回はWin32 APIから少々離れて、スクリプト中でHSPのモジュール機能を活用することについて説明しましょう。このモジュール機能とはいったいどういったものかというと

複数のスクリプトをラベル名や変数名の衝突を気にせず結合するためのもの
《HSPマニュアル・モジュール機能ガイドより抜粋》

であります。一般的には、「新しい命令を定義する機能」と考えられています。多く利用される方法としては、他のプログラマが作成したモジュール命令を、簡単に自分のスクリプトに利用する、というものがあります。モジュール利用者は、必要な機能を実現するためのアルゴリズムなどがわからなくても、他のプログラマが作成したモジュールを利用すると、命令1つ書くだけで実現できてしまうので、この機能は非常に便利です。

しかし、この機能をただそれだけに利用していたのでは、モジュール機能の本領を発揮できないでしょう。モジュール機能には、うまく使えばスクリプトの構造を容易にすることができる、といった側面もあるのです。どちらかというとC言語などのようなプログラミングに近いスクリプト構造を実現して、スクリプトを単純にします。

例えば、スクリプトの最初のほうでウィンドウを初期化することを考えしょう。ウィンドウサイズを設定して、タイトルバーの文字列を変えて、文字を書いて、オブジェクトを配置して、……。こういったことを一つ一つ順に書いていくよりも、これらすべての作業を実行するモジュールをまず作成して、“init_main_window”という名前をつけてしまえば、あとは、スクリプトのメインルーチンにおいて“init_main_window”と記述するだけでウィンドウの初期化がすんでしまいますし、あとからスクリプトを見たときも内容を把握しやすくなります。

このようなことを実現する手法としてもう1つ、サブルーチンがあります。サブルーチンを使って上で述べたようなことを同様にこなすことは可能です。しかし、1つ問題が生じます。それは「変数の衝突」です。例えば、メインルーチンでtpという変数を使っていた場合に、サブルーチンでも同じ名前のtpという変数を使ってしまうと、サブルーチン内でこの変数の内容を書き換えてしまって予期しない不具合が起こってくる可能性があるのです。これらを防ぐ意味でも、モジュール機能を使うことがプログラミングにおいて有効であることがわかるでしょう。

モジュールの定義方法

モジュールを作成する場合、2つのプロプロセッサ命令を用いて行ないます。

#module

; この場所がモジュール空間になります

#global

2つのモジュール定義用プリプロセッサ命令#module#globalではさまれた部分は、モジュール空間(モジュール領域)と呼ばれます。モジュール空間は、外部空間(グローバル領域)や、他の場所で定義されているモジュール空間とは独立していて、この中の変数名やラベル名は他の場所と衝突することはありません。

また、モジュールはメインスクリプトの実行に影響を与えません。どういうことかというと、メインスクリプトの途中にモジュールが定義されていても、モジュール内のスクリプトはその時点で実行されないということです。

mes "メインスクリプト実行中1"

#module                  ; ここからモジュール

mes "モジュール内スクリプト実行中"

#global                  ; ここまでモジュール

mes "メインスクリプト実行中2"
stop

上のスクリプトを実行すると、ウィンドウには

メインスクリプト実行中1
メインスクリプト実行中2

と表示されるだけです。モジュール内のスクリプトが実行されていないことがわかります。

モジュール内にスクリプトを書いてそれを実行させるには、モジュール内で新しい命令としてそのスクリプトを実行させる、という手段をとります。新しい命令を定義するにはプリプロセッサ命令の#deffuncを使います。この命令を使って新しい命令を定義しておくと、それ以降のスクリプト中でその命令を使うことでモジュール内スクリプトを実行することができます。

mes "メインスクリプト実行中1"

#module                           ; ここからモジュール

#deffunc myfunc1                  ; 新しい命令 myfunc1 を定義
mes "モジュール内スクリプト実行中"
return

#global                           ; ここまでモジュール

mes "メインスクリプト実行中2"
myfunc1                           ; 新しい命令を実行
stop

上のスクリプトでは新しい命令myfunc1を定義して使用しています。このスクリプトを実行すると

メインスクリプト実行中1
メインスクリプト実行中2
モジュール内スクリプト実行中

と表示されるので、モジュール命令が実行されていることがわかります。

新しい命令には、通常の命令と同じようにパラメータをつけることができます。パラメータの種類(数値か文字列か、あるいは変数か)を指定するのに、#deffuncと命令の名前のあとにパラメータの種類を並べて記述します。

#deffunc myfunc2 val, str, int, int

上のように定義すると、新しい命令myfunc2は第1パラメータとして変数を、第2パラメータとして文字列を、第3および第4パラメータとして数値を指定することができるようになります。

パラメータは1つの命令で最大8個まで持つことができますが、注意しなければならないのは、変数および文字列型のパラメータは最初の2つまでにしか指定することができない、ということです。3番目以降に変数および文字列型のパラメータを指定することはできません。

定義した命令のパラメータを取得するにはmref命令を使います。mref命令の詳しい説明については、マニュアルを参照してください。

#module

#deffunc myfunc2 val, str, int, int  ; 新しい命令 myfunc2 を定義
mref p1, 16                          ; 第1パラメータ(数値型変数)
mref p2, 33                          ; 第2パラメータ(文字列)
mref p3, 2                           ; 第3パラメータ(数値)
mref p4, 3                           ; 第4パラメータ(数値)
mes "第1パラメータ(変  数)の内容は" + p1
mes "第2パラメータ(文字列)の内容は" + p2
mes "第3パラメータ(数  値)の内容は" + p3
mes "第4パラメータ(数  値)の内容は" + p4

p1 = -10                             ;変数の内容を書きかえる
return

#global

a = 50
mes "a = " + a
myfunc2 a, "HSPモジュールテスト", 30, 40
mes "a = " + a
stop

モジュール命令のパラメータとして変数を指定した場合、モジュール内でmrefによって割り当てられた変数(変数p1)はもとの変数(変数a)そのものになります。モジュール内で変数の内容を書きかえると、もとの変数の内容も書きかわっていることがわかります。