!!!繰り返し構造を実装する Forthの繰り返し構造は色々あるが、DO〜LOOPを実装する。 10 0 DO I . LOOP 10がループカウンタの終値、0が初期値で、このループはカウンタが0から9まで繰り返したあと、終了する。 ちなみに'I'は、ループカウンタの現在値をスタックに積む。 上記の処理結果は、 0 1 2 3 4 5 6 7 8 9 となる。 ところで、DOワードは終値<初期値でもループ内を1回は実行する。 C言語のdo〜whileみたいなもの。 ちなみにpForthでは、終値<初期値だと止まらない。 もしかして終了条件が「カウンタ = 終値」になってるんだろうか? コード化されたプログラムは、次のようになる: doコード, ループ内処理, loopコード, ループ内先頭番地, ループ外処理 構文解析時の動作は、こんな感じ。 "do"を見つけたら、 *doコードを現在番地に保存する *doの次の番地(ループ内処理の先頭番地)をloopの飛び先として保存する "loop"を見つけたら、 *loopコードを現在番地に保存する *先に保存した、ループ内処理の先頭番地を保存する do-loopもネスト可能にするため、loopの飛び先を保存する場所は、if-else-thenで使用した分岐スタックif_stackを用いる。 実行時の動作は、 "do"を見つけたら、 *スタックに積まれた初期値と終値を取り出し、それぞれ、ループ制御領域のカウンタ初期値と終値として保存する "loop"を見つけたら、 *ループ制御領域のカウンタをインクリメントし、終値と比較する カウント値が終値に達していたら、ループを抜ける。達していない時、ループ内の先頭の命令にジャンプする !!コード 構文解析用に、parse()に以下のコードを追加する。 doの処理: } else If (strcmp(token, "do") == 0) { prog[idx] = CODE_DO; /* doコードを現在番地に保存する */ push_branch_stack(idx + 1); /* doの次の番地(ループ内処理の先頭番地)をloopの飛び先として保存する */ idx++; loopの処理: } else if (strcmp(token, "loop") == 0) { prog[idx] = CODE_LOOP; /* loopコードを現在番地に保存する */ prog[idx + 1] = pop_branch_stack(); /* 先に保存した、ループ内処理の先頭番地を保存する */ idx += 2; push_branch_stack(), pop_branch_stack()は以前はpush_if_stack(), pop_if_stack()から名前を変更した。 実行時用に、proc_prog()に以下のコードを追加する。 doの処理: case CODE_DO: call_do(); prog_cnt++; break; /* ワード'do'を実行する */ void call_do(void) { loop_pos--; /* スタックの内容をループスタックに入れる */ loop_cnt_stack[loop_pos] = pop(); loop_end_stack[loop_pos] = pop(); } loopの処理: case CODE_LOOP: call_loop(); break; /* ワード'loop'を実行する */ void call_loop(void) { loop_cnt_stack[loop_pos]++; if (loop_cnt_stack[loop_pos] >= loop_end_stack[loop_pos]) { /* ループを抜ける */ loop_pos++; prog_cnt += 2; } else { /* ループ先頭に戻る */ prog_cnt = prog[prog_cnt + 1]; } } 同様にiとcr(改行する)を追加した。 iの処理: /* ワード'i'を実行する */ void call_i(void) { /* スタックに一番内側のループカウンタをpushする */ push(loop_cnt_stack[loop_pos]); prog_cnt++; } crの処理: /* ワード'cr'を実行する */ void call_cr(void) { printf("\n"); prog_cnt++; } 以下のコード(testfile/test5)を試してみる。 5 0 do i . cr loop 結果: $ moiforth.exe testfile/test5 0 1 2 3 4 できた。 test6はdoがネストしている。 [ソースコード|http://moi2.sakura.ne.jp/fswiki/wiki.cgi?page=ImplementingRepeat&file=moiforth%2D0%2E4%2Etar%2Egz&action=ATTACH] [[戻る|Forthを作ってみる]] [[前へ|Forthを作ってみる / 条件分岐を実装する]] [[次へ|Forthを作ってみる / ワード定義を実装する]] {{adsence}}