dimの考察
dimは配列変数を設定・提供するdefine節専用命令である。
配列変数は他の数値変数・文字変数と同様に番号で表され、?の接頭辞で区別され、[]で囲まれた添え字(0と正の整数)を必要とする。格納できるのは数値変数と同じく整数のみである。
表示に関してはほぼ数値変数と同様に扱える。
宣言の仕方
*define dim ?100[10] game *start end
これが最も基本的な形式。しかしもっと使いやすくしてみる。
*define numalias dim_max,10 numalias dim1,100 numalias dim2,101 dim ?dim1[dim_max] dim ?dim2[dim_max] game *start end
numaliasを先に宣言して使用することで、マジックナンバー的な効果が得られる。
同じ長さの配列が複数欲しい時など重宝する。
また、添え字は多次元にできる。
*define dim ?100[10][10] ; 11*11の配列変数を用意する。 game *start end
あまりやりすぎるとすぐにメモリーが足りなくなるので注意する。ユーザーのローカル環境に過大な期待を抱かないこと。
添え字
*define dim ?100[10] ; 配列変数100番を設定。この配列変数は、0〜10までの添え字を取る。 game *start for %0=0 to 11 %0番の中身:?100[%0] ; %0が11になった時、添え字の最大値以上にアクセスしようとしてエラーが発生する。 next end
または。
*define dim ?100[10] ; 配列変数100番を設定。この配列変数は、0〜10までの添え字を取る。 game *start for %0=10 to -1 step -1 %0番の中身:?100[%0] ; %0が-1になった時、負の添え字にアクセスしようとしてエラーが発生する。 next end
数値の格納方法
配列変数に数値を設定する時は、movを使う。
*define dim ?100[10] game *start 0番の中身:?100[0] mov ?100[0],10 0番の中身:?100[0] \ end
一度に複数の配列変数を設定する時は、movlを使うと便利。
*define dim ?100[10] dim ?101[10][10] game *start movl ?100,0,1,2,3,4,5,6,7,8,9,10 movl ?101[0],0,1,2,3,4,5,6,7,8,9,10 end
使える場所
添え字を必要とする以外は数値変数と同じように使える。例外はあるので注意したい。
格納されている数値を画面に表示したい時は、そのまま書けばいい。
*define dim ?100[10] game *start ; 配列変数の中身を順番に表示する。(ただし、何も設定してないので0になるが) for %0=0 to 10 %0番の中身:?100[%0] next \ end
何かの命令の引数に使うこともできる。
*define dim ?100[10] game *start movl ?100,10,10,10,10,10,10,10,10,10,10,10 strsp ?100[0],"文字列",?100[1],?100[2],?100[3],?100[4],?100[5],?100[6],?100[7],?100[8],?100[9],?100[10] print 1 @ end
ただし、結果を受け取るための数値変数のかわりにはできない。
*define dim ?100[1] game *start movl ?100,0,10 rnd2 %0,?100[0],?100[1] ; ランダムの最小値や最大値を指定するのに配列変数を使っても問題ないが…… 乱数:%0 rnd2 ?100[0],1,10 ; 配列変数に直接乱数を格納しようとする、エラーが出る。 乱数:?100[0]@ end
なお、これはdefsubで自作した関数でも同様で、getparamでi%numやs%strなどした個所に配列変数をもってくるとエラーになる。その引数部分は数値変数か文字列変数しか受け付けないのだ。
この制限はかなりきついもので、inc,dec,add,sub,mul,divのような基本的な四則演算命令すらもdimは使えないことになる。
*define dim ?100[10] game *start inc ?100[0] ; ここがエラーになる! end
配列変数の計算をしたければ、一旦補助の数値変数にコピーして計算して戻すか、movを使わなければならない。
*define dim ?100[10] game *start ; incのかわり mov ?100[0],?100[0]+1 ; これならOK end
globalonとの関係
配列変数はグローバルにはならない。以下のサンプルを何度も起動してみて欲しい。
*define globalon dim ?301[10] game *start inc %300 起動:%300回目 配列変数の中身(変更前):?301[0] rnd2 %0,1,100 mov ?301[0],%0 配列変数の中身(変更後):?301[0] @ end
起動回数は保存されてカウントアップしていくが、配列変数の中身は毎回初期化されてしまうのがわかるだろう。
従って、配列変数の中身を保持しようとすると、独自にそれなりの処理を作らなければならない。
最近追加されたcsv関連の命令を使ってもいいが、csvだとユーザーに変更される恐れがある。
そこで考えたのがグローバル文字列を使う方法だ。
配列変数の中身全体をグローバルの文字列変数に格納し、適宜文字列変数から配列変数に展開するのだ。
セーブ直前で文字列変数に格納。ロード直後に配列変数に展開。これなら大丈夫だと思う。
*define globalon dim ?300[10] ; 訳語が変だったらごめん defsub squeeze_array ; 指定された配列変数を文字変数に圧縮する。 defsub spread_array ; 指定された文字変数を配列変数に展開する。 ; numaliasの設定数値は適宜変更してください。 numalias array_num,100 numalias array_length,101 numalias array_loop,102 numalias array_temp,103 numalias array_separater,104 numalias array_cursor,105 stralias array_default_separater,"," ; デフォルトの区切り文字 game *squeeze_array ; 第一引数は圧縮したい配列変数の番号。同じ番号の文字列変数に圧縮する。 ; 第二引数は圧縮したい配列変数の添え字の最大値。 ; この関数は一次元配列のみを対象とする。 getparam %array_num,%array_length mov $%array_num,"" ; 初期化 for %array_loop=0 to %array_length add $%array_num,array_default_separater itoa $array_temp,?%array_num[%array_loop] add $%array_num,$array_temp next add $%array_num,array_default_separater return *spread_array ; 第一引数は展開したい文字列変数の番号。同じ番号の配列変数に展開する。 ; この関数は一次元配列のみを対象とする。 getparam %array_num mov %array_length,0 ; 配列変数の添え字 mid $array_separater,$%array_num,0,1 ; 区切り文字を取得 mov %array_cursor,1 ; 文字列変数のどこを見るか設定 mov $array_cursor,"" ; その文字列変数の切片を保管する変数。 len %array_temp,$%array_num ; 文字列の長さを取得しておく *spread_array_loop ; ループ開始 mid $array_temp,$%array_num,%array_cursor,1 ; 一文字取得 if $array_temp=$array_separater goto *spread_array_1 add $array_cursor,$array_temp goto *spread_array_loop_end *spread_array_1 atoi %array_loop,$array_cursor mov ?%array_num[%array_length],%array_loop mov $array_cursor,"" inc %array_length *spread_array_loop_end inc %array_cursor if %array_cursor<%array_temp goto *spread_array_loop return *start spread_array 300 ; 文字列変数300番を、配列変数300番に展開 notif ?300[0]=0 goto *main ; 最初の起動であれば、配列変数の中身をランダムに設定。 for %0=0 to 10 rnd2 %1,1,100 mov ?300[%0],%1 next *main ; 配列変数の中身を表示する。 for %0=0 to 10 %0番の中身:?300[%0] next ; 配列変数一つ一つに1を足す。 for %0=0 to 10 mov ?300[%0],?300[%0]+1 next squeeze_array 300,10 ; 配列変数300番(長さ10)を文字列変数300番に保存 @ end