繰り返し構造を実装する
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がネストしている。
moiforth-0.4.tar.gz
moiforth-0.4.zip