- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!!! コンソールの複数行入力対応
ふと気がついた。
プロンプト上で、以下のようにif以降を1行に書かないで実行すると、
$ ./moiforth.exe
>0 if
反応がなくなる。
理由が分かった。構文解析関数parse()で、ifワードが現れたときの処理はこうである:
} else if (strcmp(token, "if") == 0) {
prog[idx] = CODE_IF;
push_branch_stack(idx + 1);
idx += 2;
それと、内部インタプリタ関数proc_prog()のif処理部は以下のようになっている:
case CODE_IF:
if (pop()) {
prog_cnt += 2;
} else {
prog_cnt = prog[prog_cnt + 1];
}
break;
条件が真のときは、prog_cntは次の番地に進み、そのコードが0、CODE_ENDなので、プログラムは終了し、入力待ちプロンプトを表示する。
しかし、条件が偽のときは、ジャンプ先がCODE_IFの次のコードとなっているが、プロンプト入力はifで終わっているため、次のコードはCODE_END、つまり0である。
ということは、0番地に飛んでしまい、いつまで経っても終了しない。
どうすればよいか。
対策として、組となるワード、例えばifに対するelseやthen、が現れるまで内部インタプリタの呼び出しを行わないようにする。
char proc_disable_cnt; /**< 1以上のとき、プロンプトからの実行を禁止する */
この変数を用意し、parse()内でカウントする。ifの場合は+1し、thenの場合は-1する。
} else if (strcmp(token, "if") == 0) {
prog[idx] = CODE_IF;
push_branch_stack(idx + 1);
idx += 2;
proc_disable_cnt++;
} else if (strcmp(token, "else") == 0) {
prog[idx] = CODE_ELSE;
prog[pop_branch_stack()] = idx + 2;
push_branch_stack(idx + 1);
idx += 2;
} else if (strcmp(token, "then") == 0) {
prog[idx] = CODE_THEN;
prog[pop_branch_stack()] = idx + 1;
idx++;
proc_disable_cnt--;
また、parse()内の変数idxは、いったん関数を抜けると位置を保持できないので、グローバル変数にして、構文解析を続けられるようにする。
if (!proc_disable_cnt) {
parse_idx = 0;
}
対話環境では、proc_disable_cntが0以下ならば、プログラムを実行する。
while (!quit_enabled) {
printf(">");
scanf("%100[^\n]%*[^\n]", cmd_buf);
getchar();
parse(cmd_buf);
if (!proc_disable_cnt) {
proc_prog();
}
}
実行してみた。
$ ./moiforth.exe
>2 if
> 2 3 + .
>else
> 3 3 + .
>then
5>0 if
> 1 1 + .
>else
> 3 3 + .
>then
6>
成功。これでif〜thenの複数行の入力に対応した。
[[戻る|ForthImplementation]] [[前へ|Make32bitForth]] [[次へ|Forthを作ってみる / スレッディングの変更]]
{{adsence}}
[[Forthを作ってみる / コンソールの複数行入力対応]]に移動しました。