- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!!!繰り返し構造を実装する
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]
[[戻る|ForthImplementation]] [[前へ|ImplementingBranch]] [[次へ|ImplementingDefineWord]]
[[戻る|Forthを作ってみる]] [[前へ|Forthを作ってみる / 条件分岐を実装する]] [[次へ|Forthを作ってみる / ワード定義を実装する]]
{{adsence}}