↑ページトップへ
表示調整
閉じる
挿絵表示切替ボタン
▼配色
▼行間
▼文字サイズ
▼メニューバー
×閉じる

ブックマークに追加しました

設定
0/400
設定を保存しました
エラーが発生しました
※文字以内
ブックマークを解除しました。

エラーが発生しました。

エラーの原因がわからない場合はヘルプセンターをご確認ください。

ブックマーク機能を使うにはログインしてください。
PR
21/50

エピ13.2 FOR ループを更に細かく


 ***


 エピ13.2 FOR ループを更に細かく


 ***


 FOR ループを更に細かく見て行きます。


 ***


 FOR の中間コードは 87h で分岐先は 1D2Fh です。


 1D2Fh 番地からの実行ステップを追います。


   1D2F: _259Bh()

   1D32: _169Ah(B6h) # B6h = '='

   1D36: push DE # DE = 2049h = 'I',20h

   1D37: _1DBBh()

   1D3A: pop HL # HL = 2049h

   1D3B: [47F0h] = HL # HL = 2049h

   1D3E: ex DE,HL # DE = 2049h; HL = 0000h

   1D3F: _23D2h()

   1D42: _1818h()


 259Bh のルーチンは変数名を DE に設定します。169Ah のルーチンは [HL] が B6h('=')かを調べます。B6h でなければ SYNTAX ERROR です。どちらもエピ12で出て来ましたね。

 1DBBh のルーチンは 2251h をコールして値を評価します。結果は数値ワークに入ります。

 23D2h のルーチンは DE と同じ名前の数値変数を探索するルーチンです。エピ12で出てきた 23C7h のルーチンの途中からで、数値変数の処理をします。DE は変数の数値部分の番地になります。

 1818h のルーチンは数値ワークから DE に5バイト転送します。これもエピ12で出て来ました。


 結果1:変数名 'I',20h を 47F0h に転送

    :数値変数の領域に変数 'I' を新規追加して、数値ワークから数値を転送


 ループ変数は、数値変数の領域に追加されます。同名の変数が既にあれば追加しないでそれを使います。


   1D45: _1697h(AEh) # AEh = 'TO'

   1D49: _1DBBh()

   1D4C: DE = 47F8h

   1D4F: _1818h()


 1697h のルーチンは、HL=[4801h] して 169Ah に続きます。AEh(='TO')でなければエラーに飛びます。他のルーチンは既出ですね。


 結果2:最終値を 47F8h に転送


   1D52: _1689h(AFh,1D60h) # AFh = "STEP"


   1D60: HL = 1615h

   1D63: DE = 47F2h

   1D66: A = [HL] # A = C1h

   1D67: [47F7h] = A # A = C1h

   1D6A: BC = 0005h

   1D6D: LDIR # HL = 1615h; DE = 47F2h; BC = 0005h


 1689h のルーチンは、HL=[4801h] して 168Ch に続きます。168Ch はメインループから呼び出されて中間コードの分岐処理にジャンプしたルーチンでした。ここでは AFh(='STEP')以外ならば 1D60h にジャンプします。

 1615h 番地からの5バイトは C1 00 00 00 80(= 1.0)です。これが STEP を省略した場合の変化幅です。


 STEP が省略されていない場合は、1D58h〜1D5Fh のコードで、1DBBh のルーチンで(2251h をコールして)数値を評価して数値ワークに設定、HL=[4644h] して、1D63h に合流します。


 結果3:変化幅(の省略時の値 1 )を 47F2h に転送

    :変化幅の符号を 47F7h に転送


 ***


 ここまでで、ループ変数に初期値を設定して、47F0h〜47FCh の 13 バイト(変数名・変化幅・変化幅の符号・最終値)の設定が終わりました。


 次はネスト数の処理とFOR領域への転送です。


 ***


 ネスト数1(4803h)が0の場合は、...


   1D6F: HL = [4648h] # HL = 4787h

   1D72: DE = [47F0h] # DE = 2049h = 'I',20h

   1D76: A = [4803h] # A = 00h

   1D79: inc A # A = 01h

   1D7A: dec A # A = 00h, Zf = 1

   1D7B: jr Z, 1D9Ch # JR


 このように 1D7Bh 番地でジャンプして、ネスト数のチェックとFOR領域への転送と進みます。

 ネスト数1が0以外の場合、つまりネストしていた場合の処理(1D7Dh〜1D9Bh)が気になるので、後で調べますね(エピ13.3です)。


   1D9C: HL = 4804h

   1D9F: A = [HL] # A = 00h

   1DA0: if A==0Fh: _139Eh


 ネスト数2(4804h)を調べて、15 だったら 139Eh(16FOR ERROR)に飛びます。


   1DA5: inc [HL] # HL = 4804h; (HL) = 01h

   1DA6: dec HL # HL = 4803h

   1DA7: inc [HL] # HL = 4803h; (HL) = 01h

   1DA8: dec HL # HL = 4802h


 ネスト数1(4803h)とネスト数2(4804h)を +1 します。


   1DA9: DE = [4648h] # DE = 4787h

   1DAD: BC = 0013h # 13h = 19

   1DB0: dec DE # DE = 4786h

   1DB1: LDDR # HL = 4802h; DE = 4786h; BC = 0013h


 4802h 番地から 4786h 番地(FOR領域の使用中の番地-1)に LDDR で 19 バイト転送します。


   1DB3: inc DE # DE = 4774h

   1DB4: ex DE, HL # DE = 47EFh; HL = 4774h

   1DB5: [4648h] = HL # HL = 4774h

   1DB8: jp 199Eh


 FOR領域の使用中の番地 4648h を更新して、199Eh にジャンプします。199Eh は LET 命令文の最後でジャンプした番地ですよ(エピ12)。


 ***

 **

 *


 次は NEXT です。中間コードは 8Dh で、分岐先は 1DC4h です。


   1DC4: A = [4803h] # A = 01h ネスト数1

   1DC7: if A==01h: _138Ah # err-msg SYNTAX ERROR


 ネスト数1が0の場合はエラーです。


   1DCB: _2556h() # 変数名チェック

   1DCE: [4801h] = HL # HL = 481Bh 命令文への番地

   1DD1: HL = [4648h] # HL = 4774h FOR領域の使用中の番地

   1DD4: _1E41h() if NC # DE = [HL] ループ変数名


 2556h のルーチンでループ変数名(NEXT I の I )を DE に転送します。変数名が省略されている場合は 1E41h のルーチンをコールしてFOR領域のループ変数名を DE に設定します。


   1DD7: A = E # A = 49h = 'I' ループ変数の1文字目

   1DD8: A -= [HL] # A = 00h

   1DD9: inc HL # HL = 4775h

   1DDA: B = A # B = 00h

   1DDB: A = D # A = 20h ループ変数の2文字目

   1DDC: A -= [HL] # A = 00h

   1DDD: A |= B # A = 00h

   1DDE: jr Z, 1DF5h # JR


 DE の変数名をFOR領域のループ変数名と比較します。正常な場合はここで 1DF5h へジャンプします。異常な場合は、...後でね。


   1DF5: inc HL # HL = 4776h(変化幅)

   1DF6: _23D2h() # 変数を検索

   1DF9: push DE # DE = 482Ch(数値変数)

   1DFA: push HL # HL = 4776h(変化幅)

   1DFB: _2D0Eh() # 加算の処理

   1DFE: pop HL # HL = 4776h(変化幅)

   1DFF: pop DE # DE = 482Ch(数値変数)


 ループ変数に変化幅を加算します。23D2h のルーチンで変数を検索して変数の番地を DE に設定して、HL=4776h の変化幅を 2D0Eh のルーチンで加算します。


   1E00: BC = 0005h

   1E03: HL += BC # HL = 477Bh(変化幅の符号)

   1E04: A = [HL] # A = C1h

   1E05: inc HL # HL = 477Ch(最終値)

   1E06: push HL # HL = 477Ch(最終値)

   1E07: or A # A = C1h

   1E08: jp P, 1E23h


 変化幅の符号を調べて、符号が0(=マイナス)の場合は 1E23h にジャンプします。ここでは符号は1(=プラス)なので次に続きます。変化幅の符号は変化幅の1バイト目と同じなので変化幅の符号を別途保存する必要は無いよね?


   1E0B: ex DE, HL # DE = 477Ch(最終値); HL = 482Ch(数値変数)

   1E0C: _3369h() # [DE]と[HL]をBCバイト比較

   1E0F: pop HL # HL = 477Ch

   1E10: BC = 0005h

   1E13: jr C, 1E2Dh


 ループ変数と最終値を比較します。(変化幅がプラスで)ループ変数 > 最終値なら FOR ループは終了で 1E2Dh にジャンプします。ループ変数 <= 最終値なら次に続きます。


   1E15: HL += BC # HL = 4781h(FOR領域の次文への番地)

   1E16: DE = 47FDh # DE = 47FDh(次文への番地)

   1E19: inc C # C = 06h

   1E1A: LDIR # HL = 4781h; DE=47FDh; BC=0006h


 FOR領域の 4781h 番地からの6バイトを 47FDh 以降に転送します。


   1E1C: HL = [4801h] # HL = 4813h 命令文への番地

   1E1F: A = [HL] # A = 0Dh 命令文(終端)

   1E20: jp 19A4h


 19A4h へジャンプします。これで FOR 命令文の直後から処理を繰り返すのです。


 ***


 ループ変数 > 最終値の場合は FOR ループの終了です。


   1E2D: C = 0Bh # BC = 000Bh

   1E2F: HL += BC # HL = 4787h

   1E30: [4648h] = HL # HL = 4787h FOR領域の使用中の番地


 FOR領域の使用中の番地 4648h を更新します。HL は 477Ch(最終値)を指していたので +11 するとループ1回分を戻したことになります。


 FOR領域は、ループが終了した後でもゼロクリアせず、4648h 番地を更新することで使用中の範囲を管理するのですよ。


   1E33: dec [4803h] # = 00h ネスト数1

   1E37: dec [4804h] # = 00h ネスト数2


 4803h(ネスト数1)と 4804h(ネスト数2)を -1 します。


   1E39: _1689h(2Ch,199Eh) # 2Ch = ','


   1E3F: jr 1DC4h


 1689h のルーチンをコールして、[HL] が 2Ch でなければ 199Eh へジャンプします。


 [HL] が 2Ch なら 1DC4h へ、...NEXT 命令の先頭にジャンプです。


 *


 先頭にジャンプ? どういう事?


 *


 2Ch は ',' ですが調べてみたら、...


   FOR I=1 TO 3

    FOR J=1 TO 3

     FOR K=1 TO 3

      :

     NEXT K

    NEXT J

   NEXT I


 のように FOR ループがネストしている場合に NEXT を


   FOR I=1 TO 3

    FOR J=1 TO 3

     FOR K=1 TO 3

      :

   NEXT K,J,I


 とまとめることができるのでした。


 SP5030の独自仕様ではなくて、F-BASICでも同じです。便利なのかな?


 ***

 **

 *


 ループ変数は、普通の数値変数と同様に扱えます。値を参照できるのは当然として、値を変更することもできます。つまり、


   10 FOR I=1 TO 16

   20  PRINT I;

   30  IF I=8 THEN I=9

   40 NEXT I


   > 1 2 3 4 5 6 7 8 10 11 12 13 14 15 16


 このようにループしている途中で、今何時や?と尋ねて9をスキップできるのです。


 これが古典落語「時そば」の原理です。


 ***


 FOR-NEXT について理解が深まりましたね。続きも読んでね!


 ***


 間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!


 ***

2026.5.4 微推敲


評価をするにはログインしてください。
ブックマークに追加
ブックマーク機能を使うにはログインしてください。
― 新着の感想 ―
このエピソードに感想はまだ書かれていません。
感想一覧
+注意+

特に記載なき場合、掲載されている作品はすべてフィクションであり実在の人物・団体等とは一切関係ありません。
特に記載なき場合、掲載されている作品の著作権は作者にあります(一部作品除く)。
作者以外の方による作品の引用を超える無断転載は禁止しており、行った場合、著作権法の違反となります。