トップ 差分 一覧 Farm ソース 検索 ヘルプ RSS ログイン

Forthを作ってみる / コンソールの複数行入力対応

コンソールの複数行入力対応

ふと気がついた。プロンプト上で、以下のように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の複数行の入力に対応した。

戻る 前へ 次へ