プチコンで遊ぼう! (はてなブログ版)

任天堂3DSのプチコンで遊ぼう! [twitter:@eida_s]

はてなダイアリーから移行しました。 はてなダイアリーのURLを開いても自動的にこちらにリダイレクトされますのでご了承ください。

3号プログラミング覚え書き(2) DEF編

◆DEF関係

・関数/命令名の長さに制限はない
 変数と同様。

・大文字・小文字は区別されない
 変数と同様。

・$や%や#をつけると違う関数/命令となる
 変数と同様。

・関数/命令の呼び出し段数は残りのスタックサイズにのみ制限される
 関数/命令の中からさらに関数/命令を呼び出すことができるが、この呼び出し段数に制限はない。
 ただし、呼び出し毎に、現在の変数等をスタックに退避するので、どこかで「Stack overflow」エラーとなる。
 DEFの中で使っている変数の数・型によって、どこでエラーになるかは変わってくる。
 例えば、長い文字列を入れた文字型変数を使うと少ない段数でエラーになる。

・DEFの引数として配列を渡す時は、OUT句以降でなく、通常の引数として渡す
 【 DEFで引数に配列を渡す方法 】 のエントリで書いたとおり。
 なお、DEFの引数の[]は書いても書かなくても同じ。

VAR A$[5]
SUB1 A$
PRINT A$[0]
END

DEF SUB1 A$[]
  A$[0]="XYZ"
END

・関数の戻り値や命令のOUT引数を返さないと、呼び出し元でエラーになる
 【 DEFでハマったところ その2 】のエントリに書いたとおり。
 エラーになること自体は当然だが、呼び出し元の方でエラーになるので気を付ける。
 呼び出し先の処理を見直してみること。
 なお、初期のバージョンではOUT引数を返さない場合は「Type mismatch」エラーとなっていたが、現在のバージョン(3.2.1)では「Uninitialized variable used」エラーになり、ちょっとだけエラーの原因に気づきやすくなった。
 ただし、関数の戻り値を返さないパスを通った時のエラーは以前と同じで「Type mismatch」エラーになる。

・COMMON DEFにおける変数スコープ
これは、COMMON DEF、というよりも、本体のプログラムから別スロットで呼び出されるCOMMON DEFに関する制限。(同じスロット内から呼び出された時は、DEFもCOMMON DEFも同じ動作になる)
別スロットにある本体プログラムから呼び出されたCOMMON DEFのグローバルスコープは、本体スロットの方か、あるいは、COMMON DEFのあるスロットの方なのか?
これはCOMMON DEFのあるスロットの方になる。

ただし、配列の場合には、DIM/VARの仕様のせいでおかしなことが起こる。
(というよりはCOMMON DEFからはグローバル変数を使ってはいけないのが本来で、今現状では使えてしまっている、ということなのかもしれない。)
詳しくは次項。

・別スロット中のCOMMON DEFを呼ぶとその中でグローバル配列が使えない場合がある
具体的には以下のソース。

'This is the SLOT 0.
OPTION STRICT
USE 1
TEST1
'This is the SLOT 1.
OPTION STRICT
DIM TEST[10]

COMMON DEF TEST1
 TEST[0]=100
 TEST2
END

COMMON DEF TEST2
 ? TEST[0]
END

これをRUN 0で実行すると、スロット1の6行目で「Type mismatch」エラーとなる。
なぜか?以下、詳しく動作を見ていく。

(1)まず、スロット1のグローバルスコープは、スロット1なので、TEST配列がスロット0に宣言されていなくても問題ない。
(2)次に、スロット1の3行目でTEST配列は宣言されているので、実行時に「Undefined variable」エラーにはならない。
(3)スロット0の実行が始まると、スロット1のTEST1が呼び出される。
(4)実行がスロット1のTEST1に移るが、この時いきなり5行目のCOMMON DEFの行から始まるので、3行目のDIM文は実行されていない。すなわち、TEST配列は宣言はされているが確保されていない。
(5)そして、6行目のTEST[0]の実行時に、TEST配列が確保されていないために、TEST[0]への代入で「Type mismatch」エラーとなる。

かといって、COMMON DEFの中で配列を宣言しても、DEFの中で宣言した配列はローカルスコープになってしまう。

では、自作ライブラリ中でグローバル変数として配列を使う方法はないのか?
それは、スロット1にGOSUBで飛ばし、飛んだ先でDIM/VARで配列宣言することで可能である。具体的には以下のようにする。

'This is the SLOT 0.
OPTION STRICT
USE 1
GOSUB "1:@INIT"
TEST1
'This is the SLOT 1.
OPTION STRICT
@INIT
DIM TEST[10]
RETURN

COMMON DEF TEST1
 TEST[0]=100
 TEST2
END

COMMON DEF TEST2
 ? TEST[0]
END