SICP 読み (391) 5.5 翻訳系

ざっくり以下なカンジの試験を作っていました。

static void test_priv_CopyList(ScmObj x, ScmObj y)
{
    ScmObj tmp_x, tmp_y;
    for(tmp_x = x, tmp_y = y; SCM_PAIRP(tmp_x); ) {
       
        tmp_x = SCM_CDR(tmp_x);
        tmp_y = SCM_CDR(tmp_y);
    }
}

void test_scheme_Scm_CopyList(void)
{
    ScmObj base, copy, tmp_b, tmp_c;
    base = ScmCons(Scm_MAKE_INT(1),
                   Scm_Cons(SCM_MAKE_INT(2),
                            Scm_Cons(SCM_MAKE_INT(3), SCM_NIL)));
    copy = Scm_CopyList(base);
    test_priv_CopyList(base, copy);
}

とほほ。リハビリ必要だ。
前回のエントリでは

手順としては cdr をめくっていきながら (cdr が pair でなくなったら停止) car について

  • 型が同じか (同じでないとダウト)
  • immediate、fixnum、character ならポインタ値が同じでないとダウト
  • pair だったらポインタ値が同じだとダウト
  • pair の場合は中身 (car と cdr) の検証
  • pair の場合は再帰にせざるを得ない??

みたいなコトを書いています。てーコトはこんな感じ??

static void test_priv_CopyList(ScmObj x, ScmObj y)
{
	ScmObj tmp_x, tmp_y;
	for(tmp_x = x, tmp_y = y; SCM_PAIRP(tmp_x); ) {
		CU_ASSERT_EQUAL(SCM_TRUE, SCM_XTYPEP(SCM_CAR(tmp_x), 
											 SCM_CLASS_OF(SCM_CAR(tmp_y))));
		if(SCM_IMMEDIATEP(SCM_CAR(tmp_x)) !! 
		   SCM_INTP(SCM_CAR(tmp_x)) !! 
		   SCM_CHARP(SCM_CAR(tmp_x)))
			CU_ASSERT_TRUE(SCM_EQ(SCM_CAR(tmp_x), SCM_CAR(tmp_y)));

		if(SCM_PAIRP(SCM_CAR(tmp_x))) {
			CU_ASSERT_FALSE(SCM_EQ(SCM_CAR(tmp_x), SCM_CAR(tmp_y)));
			test_priv_CopyList(SCM_CAR(tmp_x), SCM_CAR(tmp_y));
		}

		tmp_x = SCM_CDR(tmp_x);
		tmp_y = SCM_CDR(tmp_y);
	}
}

void test_scheme_Scm_CopyList(void)
{
	ScmObj base, copy, tmp_b, tmp_c;
	base = ScmCons(Scm_MAKE_INT(1), 
				   Scm_Cons(SCM_MAKE_INT(2),
							Scm_Cons(SCM_MAKE_INT(3), SCM_NIL)));
	copy = Scm_CopyList(base);
	test_priv_CopyList(base, copy);

	base = Scm_List(SCM_MAKE_CHAR('a'),
					SCM_FALSE,
					SCM_TRUE,
					Scm_List(SCM_MAKE_INT(1),
							 SCM_MAKE_INT(2),
							 SCM_MAKE_INT(3)),
					SCM_NIL);
	copy = Scm_CopyList(base);
	test_priv_CopyList(base);
}

なんか微妙。面倒だからこのままどんどんやっちゃえ (何

ScmObj Scm_CopyList(ScmObj list)
{
	return NULL;
}

こんなのデッチ上げて make してみたらコンパイルエラーがばんばん出る。

  • 関数の名前やら引数の数やら全然駄目
  • 論理和な演算子が ! になってる

しかも make が通った、と思ったら試験にパスしてやがる。何故だ、と言いつつ試験な main に追加した試験を盛り込んでませんでした。ばたばたしてる中でリハビリ気味に進めるのは色んな意味で微妙。

最初こんな実装だったのですが

ScmObj Scm_CopyList(ScmObj list)
{
    ScmObj tmp, ret = SCM_NIL, end;
    for(tmp = list; SCM_PAIRP(tmp); tmp = SCM_CDR(tmp)) {
        if(SCM_PAIRP(SCM_CAR(tmp)))
            tmp = Scm_CopyList(tmp);
        SCM_APPEND1(ret, end, tmp);
    }
    return ret;
}

試験に通らんのは何故、と言ってたら car するのを忘れてます (@SCM_APPEND1)。次はリストの中にリストがあるケイス。再度試験を以下に。

static void test_priv_CopyList(ScmObj x, ScmObj y)
{
    ScmObj tmp_x, tmp_y;
    for(tmp_x = x, tmp_y = y; SCM_PAIRP(tmp_x); ) {
        if(SCM_PTRP(SCM_CAR(x)))
            CU_ASSERT_TRUE(SCM_XTYPEP(SCM_CAR(tmp_x), 
                                      SCM_CLASS_OF(SCM_CAR(tmp_y))));

        if(SCM_IMMEDIATEP(SCM_CAR(tmp_x)) ||
           SCM_INTP(SCM_CAR(tmp_x)) ||
           SCM_CHARP(SCM_CAR(tmp_x)))
            CU_ASSERT_TRUE(SCM_EQ(SCM_CAR(tmp_x), SCM_CAR(tmp_y)));

        if(SCM_PAIRP(SCM_CAR(tmp_x))) {
            CU_ASSERT_FALSE(SCM_EQ(SCM_CAR(tmp_x), SCM_CAR(tmp_y)));
            test_priv_CopyList(SCM_CAR(tmp_x), SCM_CAR(tmp_y));
        }

        tmp_x = SCM_CDR(tmp_x);
        tmp_y = SCM_CDR(tmp_y);
    }
}

void test_scheme_Scm_CopyList(void)
{
    ScmObj base, copy;
    base = Scm_Cons(SCM_MAKE_INT(1), 
                    Scm_Cons(SCM_MAKE_INT(2),
                             Scm_Cons(SCM_MAKE_INT(3), SCM_NIL)));
    copy = Scm_CopyList(base);
    test_priv_CopyList(base, copy);

    base = Scm_List(SCM_MAKE_CHAR('a'),
                    SCM_FALSE,
                    SCM_TRUE,
                    Scm_List(SCM_MAKE_INT(1),
                             SCM_MAKE_INT(2),
                             SCM_MAKE_INT(3),
                             SCM_NIL),
                    SCM_NIL);
    copy = Scm_CopyList(base);
    test_priv_CopyList(base, copy);
}

二つめの試験でループしている模様。よく見りゃ car がペアだった場合の処理が滅茶苦茶だし、ここでも car 取ってない。以下の修正して試験パス。

ScmObj Scm_CopyList(ScmObj list)
{
    ScmObj tmp, ret = SCM_NIL, end, pair;
    for(tmp = list; SCM_PAIRP(tmp); tmp = SCM_CDR(tmp)) {
        if(SCM_PAIRP(SCM_CAR(tmp))) {
            pair = Scm_CopyList(SCM_CAR(tmp));
            SCM_APPEND1(ret, end, pair);
        } else {
            SCM_APPEND1(ret, end, SCM_CAR(tmp));
        }
    }
    return ret;
}

それにしても SCM_APPEND1 ってマクロは便利。

ってか

そろそろ面倒臭くなりはじめています。gauche の実装カンニングしたひ。eq? とかのあたり特に。