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

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

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

エラーが発生しました。

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

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

エピ13.3 FOR ループがネストしたらどうなる


 ***


 エピ13.3 FOR ループがネストしたらどうなる


 ***


 FOR ループのネストの例です。九九の表を作ります。


   10 FOR I=1 TO 9

   20  FOR J=1 TO 9

   30   PRINT I*J,

   40  NEXT J

   50  PRINT

   60 NEXT I


 BASICを始めたら誰でもやるよね。罫線を入れたり、桁を綺麗に揃えたり、...しているうちに徐々に文字列の扱いを覚えるのさ。


 *

 *

 *


 さて。ネストしている FOR 命令文の処理を観察しましょう。


 1D7Dh 番地以降の処理ですが、少し前の 1D6Fh から見ますね。


 *


 ネストしていない場合は次のように実行ステップが進みました。


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

   1D72: DE = [47F0h] # DE = 2049h = 'I',20h ループ変数名

   1D76: A = [4803h] # A = 00h ネスト数1

   1D79: inc A # A = 01h

 _1D7A:

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

   1D7B: jr Z, 1D9Ch # JR

   :

   :スキップ

   :

 _1D9Ch:

   1D9C: HL = 4804h # HL = 4804h

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


 ネスト数1を調べて0なので、1D7Bh 番地から 1D9Ch 番地にジャンプです。


 *


 ネスト数1が1の場合は次のようになります。


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

   1D72: DE = [47F0h] # DE = 204Ah = 'J',20h ループ変数名

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

   1D79: inc A # A = 02h

 _1D7Ah:

   1D7A: dec A # A = 01h; Zf = 0

   1D7B: jr Z, 1D9Ch # ジャンプしない(2回目はジャンプ)

   :

   1D7D: ex AF,AF'

   1D7E: A = [HL] # A = 49h = 'I' FOR領域の変数名の1文字目

   1D7F: A -= E # A = FFh

   1D80: B = A # B = FFh

   1D81: inc HL # HL = 4775h

   1D82: A = [HL] # A = 20h FOR領域の変数名の2文字目

   1D83: A -= D # A = 00h

   1D84: A |= B # A = FFh

   1D85: BC = 0012h

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

   1D89: jr Z, 1D8Eh # 変数名が不一致なのでジャンプしない

   1D8B: ex AF,AF'

   1D8C: jr 1D7Ah # ループ

 _1D8Eh:

   :

 _1D9Ch:

   1D9C: HL = 4804h

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


 1D7Bh 番地では、ネスト数1が1なのでジャンプせず、1D7Dh 以降の処理に進みます。


 1D7Dh 以降では、新しく始まる FOR ループのループ変数名(47F0h)とFOR領域に保存された既存の変数名(4648h)とを比較します。

 新しい変数名は 'J' で、既存の変数名は 'I' なので一致せずです。

 それで 1D8Ch 番地から 1D7Ah 番地にジャンプして、2回目の 1D7Bh 番地で 1D9Ch にジャンプです。


 FOR ループがネストする際に、外側の FOR ループで使用しているループ変数と同じ変数名だったら不具合なのでエラーにするんですね。きっと。


 *

 *

 *


 ...、と思っていたら違いました。次のプログラムの場合、


   10 FOR J=1 TO 3 :PRINT J;

   20 FOR J=11 TO 13 :PRINT J;

   30 NEXT J

   40 END


 エラーにはならなくて、PRINT 文で、


   1 11 12 13


 と表示されます。文番号 10 の FOR 命令文が、文番号 20 で上書きされているかのような動き。


 なんならね。次のようなプログラムだと、


   10 FOR A=1 TO 3

   20  FOR B=1 TO 4

   30   FOR C=1 TO 5

   40    FOR D=1 TO 6

   50  FOR B=1 TO 7

   60   PRINT A,B,C,D

   70  NEXT

   80 NEXT


 エラーにならないし、文番号 20, 30, 40 の FOR 命令文が無かったかのような動きをするのです。


 *


 1D8Eh 番地からの処理を確認しましょう。


   1D8E: [4648h] = HL # HL = 4787h FOR領域の使用中の番地を更新

   1D91: ex AF,AF'

   1D92: dec A # A = 00h

   1D93: HL = 4803h

   1D96: B = [HL] # B = 01h

   1D97: [HL] = A # HL = 4803h; A = 00h ネスト数1を更新

   1D98: A -= B # A = FFh

   1D99: inc HL # HL = 4804h

   1D9A: A += [HL] # A = 00h

   1D9B: [HL] = A # HL = 4804h; A = 00h ネスト数2を更新


 [4648h] を更新して 4787h にしています。ネスト数1とネスト数2は -1 して 00h にしています。つまり外側の FOR ループの情報を消して、ネストが無かったことに。


 これで仕様通りなのか。何か意図があってのコードなのだろうけど。これで良いのか。謎すぎるよ。


 ***


 ひとつの可能性としてですが。FOR ループを Break したいときに使うと言うのはどうでしょう?


   10 FOR A=1 TO 9999999

   20  :

   90 NEXT A


 のような FOR ループを始めてしまった後で、ループを止めたいときに、


   10 FOR A=1 TO 9999999

   20  :

   30  IF ... THEN FOR A=1 TO 1:GOTO 90

   40  :

   90 NEXT A


 とすれば、次の NEXT でループが終わる。最終値が不明でも使えて便利では。


 *


 もうひとつの可能性ですが。


   10 S=0

   20 FOR A=1 TO 3

   30  FOR B=1 TO 4

   40   FOR C=1 TO 5

   50    S=A+B+C

   60    IF ... GOTO 10

   70   NEXT

   80  NEXT

   90 NEXT


 文番号 60 から文番号 10 に戻った場合、FOR ループの状況によらずに最初からやり直しができる。


 あるいは、...


   10 S=0

   20 GOSUB 100:PRINT S

   30  :

   40 GOSUB 100:PRINT S

   50  :

   60 END


   100 FOR A=1 TO 100

   110  S=S+A

   110  IF ... THEN RETURN

   120 NEXT

   130 RETURN


 GOSUB したルーチンで FOR ループがあってループ中にリターンする場合、FOR ループを Break する処理をせずにリターンしてもOKだ(次にこのルーチンを GOSUB してエラーにならない)


 意外と利用できる状況があるのかな。...、でもバグを作りそうで利用したくないかも。BASICにはローカル変数など言う概念は無いからね。利用するなら自己責任で変数を管理してね。


 ***


 そもそも。ネスト数を 4803h と 4804h の2つで管理しているのが謎。見た感じでは同様に増減しているけれど、全く同じなら2つある意味がない。どこかで差異があるのか。それはどこなのか?


 手掛かりを求めてアマゾンの奥地に向かうべきか。


 ***

 **

 *


 ***

 **

 *


 NEXT I の I は省略可能なのですけど、省略した方がよいのか考えてみました。


 メモリが2バイト(少くとも1バイト)節約できるのは確かだけど。速度はどうだろう?


 'NEXT' 命令のコードを見る限りでは、ループ変数名 I の有無で影響を受けるのは


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


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


 の2つのルーチン。


 2556h のルーチンは、ループ変数名が省略されていると、NEXT のすぐ次が ":" だったら7ステップ目でリターンです。変数名があると、...あれ長い、... NEXT I のように NEXT と I の間にスペースがあるとそれをスキップするだけで5ステップ、I をチェックして、...25 ステップ目でリターンします。


 1E41h のルーチンはループ変数名があればコールはされないのでステップ数は0です。省略したらコールされて5ステップでリターンします。


  省略しない場合: 0 + 25 = 25 ステップ

  省略した場合 : 5 + 7 = 12 ステップ


 これだけを比べると省略した方が良さそう。FOR と NEXT が自明に対応しているなら省略するものアリですね。


 FOR と NEXT がケース文などでダイナミックに対応する場合は、


    :

   10 IF S>=0 THEN FOR I=1 TO 2

   20 IF S =0 THEN FOR J=2 TO 4

   30 IF S<=0 THEN FOR K=3 TO 6

   40 ...

    :

   (何かの処理)

    :

   50 IF S=0 THEN GOTO 40

   60 IF S<0 THEN NEXT K

   70 IF S=1 THEN NEXT I

   80 IF S>2 THEN NEXT J


 ループ変数名が付いているとデバックが捗るはかどるかもだけど。どう思う?


 ***

 **

 *


 ...。そう言えば数式の処理は?


   F = A + B * C + D * E


 とかは、括弧がなければ3値で処理かな?


 2251h ってとても面倒なのですけど。こちらを調べてみたら良さそうな?(明らかな逃避行)


 ***


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


 ***

2026.3.22 エピタイ修正

2026.5.3 エピタイ修正


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

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