next up previous contents index
: マニュアルの書き方 その 1 : : Asir 用のライブラリの書き方 : 変数名の衝突   目次   索引


モジュール機能

ライブラリで利用されている関数, 変数をカプセル化する仕組みが モジュール (module) である. 大規模なライブラリを作成する場合は, いままでの節に述べたような 名前の問題を回避するために, module を用いるとよい.

まず module を用いたプログラムの例をあげよう. これは 12 章で詳しく説明した スタックを実現しているプログラムである.

module stack;

static Sp $
Sp = 0$
static Ssize$
Ssize = 100$
static Stack $
Stack = newvect(Ssize)$

localf push $
localf pop $

def push(A) {
  if (Sp >= Ssize) {print("Warning: Stack overflow\nDiscard the top"); pop();}
  Stack[Sp] = A;
  Sp++;
}
def pop() {
  local A;
  if (Sp <= 0) {print("Stack underflow"); return 0;}
  Sp--;
  A = Stack[Sp];
  return A;
}
endmodule;

def demo() {
  stack.push(1);
  stack.push(2);
  print(stack.pop());
  print(stack.pop());
}

モジュールは module モジュール名 〜 endmodule で囲む. モジュールの中だけで使う大域変数は static で宣言する. この変数はモジュールの外からは参照もできないし, 変更もできない. 大域変数の初期化は宣言に続いてたとえば,

static Sp $
Sp = 0$
のようにおこなう. なお上の例にはあらわれないが, モジュールの外の大域変数は extern で宣言する.

次に来るのが localf を用いたモジュール内の関数の宣言である. ここでは, pushpop を宣言している. この宣言は必須である.

(大域) 関数 demo では, モジュール stack の中の 関数 push と pop を

stack.push(2);         stack.pop()
なる形式で呼び出している. つまり
モジュール名.関数名 (引数1, 引数2, ... )
の形式でモジュール内の関数をモジュールの外から呼び出せる. さて,
  if (Sp >= Ssize) {print("Warning: Stack overflow\nDiscard the top"); pop();}
ではモジュールの内の関数 pop を呼び出している. これをみればわかるように, モジュールの内部の関数を呼ぶには普通の形式で呼び出せばよい. モジュールで用いる関数名は局所的である. つまりモジュールの外や別のモジュールで定義されている関数名と同じ名前が 利用できる.

なお asir では局所変数の宣言は不要であった. しかし上の例を見れば分かるように, local A; なる形式で 局所変数を宣言できる. キーワード local を用いると, 宣言機能が有効となる. 宣言機能を有効にすると, 宣言されてない変数はロードの段階で エラーを起こす. 変数名のタイプミスによる予期しないトラブルを防ぐには, 宣言機能を有効にしてプログラムするのがよい.

モジュール内の関数をそのモジュールが定義される前に 呼び出すような関数を書くときには, その関数の前でモジュールを次のように プロトタイプ宣言しておく必要がある.

module stack;
localf push $
localf pop $
endmodule;    /* ここまでがプロトタイプ宣言 */

def demo() {
  print("----------------");
  stack.push(1);
  print(stack.pop());
  print("---------------");
}

module stack;
  stack の定義実体
endmodule;

宣言がないと, たとえば demo の実行時に push が undefined function エラーとなり停止する.



Nobuki Takayama 平成15年9月12日