Schemeをつくろう(4) エラー処理

そろそろエラー処理を真面目に作らないと。


エラーがあったら強制終了なんてのも一つの手だけど、ちょっとくらいのエラーなら回復してもう一度入力を促したい。


エラー処理にはsetjmp,longjmpを使うようなので使ってみたいと思います。


まずは、グローバル変数に環境を保存する入れ物を用意します。

#include <setjmp.h>

jmp_buf err_env;

jmp_bufにはスタックフレームとレジスタ情報が入るのかな。後で調べる。


エラーがあったらmainまで戻ってくることにします。

int main(void)
{
    int err_number;

    /* 略 */

    GC_INIT();
    
    if ((err_number = setjmp(err_env)) != 0 ) {
        /* エラー回復 */
        printf("continue\n");
    }
    while((o = read_to_stream(&s)) != NULL) {
        /* メイン処理 */
    }
}

戻したい場所の環境を保存しておいて、致命的エラーで無い場合は処理を続けたいと思います。

GCが無いと今まで確保したメモリを回収するという面倒な処理が必要なのでGC必修かと。


さて、エラーハンドラを書いてっと。

void error(char *message)
{
    printf("ERROR : %s\n", message);
    longjmp(err_env, 1);
}


飛んでみます。

    case ')' :
        error("not close");

括弧が閉じてない時には、エラーメッセージを表示して、処理を続けます。

input> ) (+ 1 1)
ERROR : not close
continue
2

うっは、ジャンプした!!


ジャンプしたというよりは環境を戻したという感じかな?

  • なんでも継続
    • setjmp,longjmpは継続の一種。しかし、Schemeとの継続とはちょっと違う。
    • スパッと切った感じは似てるのかな。
    • やっと最初の方が理解できてきた気がする。


GCがあるって幸せ。

追記

調べた。

typedef int __jmp_buf[6];

全部じゃないらしい。

    • 杉浦さん変態杉っす。

追記2

errorはリターンしないので、GCC拡張で、

__attribute__((noreturn)) void error(char *message)

と書いた方が良さげ。/* NOTREACHED */の効果はイマイチ不明。

そういえば、exitもリターンしない関数だ。