SICP 読み (380) 5.5 翻訳系
問題 5.51
gauche.h の一部を流用する方向です。相当ズルだと思うんですが、検討な軌跡は全部ログ投入な予定ですので、それで勘弁して下さひ (誰
あと、方向性としては
- とりあえず gc は盛り込まない。別途 BohemGC を使う形にするかも。
- gauche.h からは
- BASIC TYPE
- IMMEDIATE OBJECTS
- BOOLEAN
- FIXNUM
- CHARACTERS
- HEAP ALLOCATED OBJECTS
- CLASS
- PAIR AND LIST
- STRING
- SYMBOL
- NUMBER
- UTILITY
って下の方はヤリ杉感満点だし。とりあえず上から試験書きながらヤッツケる方向で。見ていきながら rudimentary implementation な範疇超えてると判断した時点でスルーか。 (を
もう少し準備しつつ
環境整備してから着手、って準備が長いよ。とりあえず、試験なソースは別ディレクトリにしておいた方が良さげ。Makefile も作らないと。どこかのチュートリアルに autoconf/automake なソレが出ておりましたが、面倒臭いのでこのあたりはスルー。
基本的に Linux で gcc で GNU make で cunit が前提という無理矢理な環境。とりあえず試験なディレクトリを作成してその中で動く Makefile を書こう。微妙ですが、とりあえず動いたのが以下
TARGET=test OBJS=main.o CFLAGS=-I.. LDFLAGS=-lcunit all: $(TARGET) @./$(TARGET) $(TARGET): $(OBJS) $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) clean: rm -rf $(TARGET) $(OBJS) *~
次はその下に Makefile 作って、test なターゲットのみ。
UT: cd test && $(MAKE) clean: @rm -rf *~ && cd test && $(MAKE) clean
とりあえず今はこれだけで OK か。以下なカンジです。
$ ls Makefile gauche.h gauche.h.ORG test/ $ make cd test && make make[1]: ディレクトリ `/home/rms/1.programming/2.boutC/8.cunit/test' に入ります cc -I.. -c -o main.o main.c cc -o test main.o -lcunit CUnit - A Unit testing framework for C - Version 2.1-0 http://cunit.sourceforge.net/ --Run Summary: Type Total Ran Passed Failed suites 1 1 n/a 0 tests 1 1 1 0 asserts 6 6 6 0 make[1]: ディレクトリ `/home/rms/1.programming/2.boutC/8.cunit/test' から出ます $ make clean make[1]: ディレクトリ `/home/rms/1.programming/2.boutC/8.cunit/test' に入ります rm -rf test main.o *~ make[1]: ディレクトリ `/home/rms/1.programming/2.boutC/8.cunit/test' から出ます $
ひさびさに make をサワるんで微妙さ満点。あとは試験なソースを分けるソレで準備完了かなぁ。ソースが増える度に Makefile に手を入れる、とゆーのがちょっとナニですが、そのあたりはおいおい、とゆー事で。
で、現時点でソースツリーが以下
$ find . ./gauche.h ./test ./test/main.c ./test/Makefile ./test/test-PRIMARY_TAG.c ./test/schemeTest.h ./Makefile ./gauche.h.ORG $
現時点の test 配下のソースが以下。最初は main.c
#include <CUnit/CUnit.h> #include <CUnit/Basic.h> #include "schemeTest.h"; int main(void) { CU_pSuite sample_suite; CU_initialize_registry(); sample_suite = CU_add_suite("Sort", NULL, NULL); CU_add_test(sample_suite, "gauche.h (SCM_PTRP)", test_gauche_SCM_PTRP); CU_basic_run_tests(); CU_cleanup_registry(); return 0; }
schemeTest.h が以下
void test_gauche_SCM_PTRP(void);
test-PRIMARY_TAG.c が以下
#include <CUnit/CUnit.h> #include <CUnit/Basic.h> #include "gauche.h" void test_gauche_SCM_PTRP(void) { CU_ASSERT_TRUE(SCM_PTRP(0)); CU_ASSERT_FALSE(SCM_PTRP(1)); CU_ASSERT_FALSE(SCM_PTRP(2)); CU_ASSERT_FALSE(SCM_PTRP(3)); CU_ASSERT_TRUE(SCM_PTRP(4)); }
試験なソースを追加する度に Makefile の修正が必要だし、試験な関数が増える度にヘッダと main.c の修正が必要になるんですが、これは仕方が無いのかなぁ。
とりあえずこれで準備完了と見て、以降で確認作業着手です。
SCM_TAG な試験
も追加。
void test_gauche_SCM_TAG(void) { CU_ASSERT_EQUAL(0, SCM_TAG(0)); CU_ASSERT_EQUAL(1, SCM_TAG(1)); CU_ASSERT_EQUAL(2, SCM_TAG(2)); CU_ASSERT_EQUAL(3, SCM_TAG(3)); CU_ASSERT_EQUAL(0, SCM_TAG(4)); }
これ、コメントとか入れられんのかな。次は即値なマクロの試験を。楽に進捗すると楽しくなるからイケマセン。
IMMEDIATE OBJECTS
調子に乗ってどんどん盛り込み。とりあえず以下に test-IMMEDIATES.c を
#include <CUnit/CUnit.h> #include "gauche.h" void test_gauche_SCM_IMMEDIATEP(void) { CU_ASSERT_FALSE(SCM_IMMEDIATEP(0)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(1)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(2)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(3)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(4)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(5)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(6)); CU_ASSERT_FALSE(SCM_IMMEDIATEP(7)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_FALSE)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_TRUE)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_NIL)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_EOF)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_UNDEFINED)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(SCM_UNBOUND)); } void test_gauche_SCM_ITAG(void) { CU_ASSERT_EQUAL(0, SCM_ITAG(SCM_FALSE)); CU_ASSERT_EQUAL(1, SCM_ITAG(SCM_TRUE)); CU_ASSERT_EQUAL(2, SCM_ITAG(SCM_NIL)); CU_ASSERT_EQUAL(3, SCM_ITAG(SCM_EOF)); CU_ASSERT_EQUAL(4, SCM_ITAG(SCM_UNDEFINED)); CU_ASSERT_EQUAL(5, SCM_ITAG(SCM_UNBOUND)); } void test_gauche_SCM__MAKE_ITAG(void) { int value [] = {6, 22, 38, 54, 70, 86}; int i; for(i = 0; i < 6; i++) { CU_ASSERT_EQUAL(value[i], SCM__MAKE_ITAG(i)); CU_ASSERT_TRUE(SCM_IMMEDIATEP(value[i])); } } void test_gauche_SCM_IMMEDIATEP_2(void) { CU_ASSERT_TRUE(SCM_FALSEP(SCM_OBJ(SCM__MAKE_ITAG(0)))); CU_ASSERT_TRUE(SCM_TRUEP(SCM_OBJ(SCM__MAKE_ITAG(1)))); CU_ASSERT_TRUE(SCM_NULLP(SCM_OBJ(SCM__MAKE_ITAG(2)))); CU_ASSERT_TRUE(SCM_EOFP(SCM_OBJ(SCM__MAKE_ITAG(3)))); CU_ASSERT_TRUE(SCM_UNDEFINEDP(SCM_OBJ(SCM__MAKE_ITAG(4)))); CU_ASSERT_TRUE(SCM_UNBOUNDP(SCM_OBJ(SCM__MAKE_ITAG(5)))); }
BOOLEAN
次は test-BOOLEAN.c
#include <CUnit/CUnit.h> #include "gauche.h" void test_gauche_SCM_BOOLP(void) { CU_ASSERT_TRUE(SCM_BOOLP(SCM_OBJ(6))); CU_ASSERT_TRUE(SCM_BOOLP(SCM_OBJ(22))); CU_ASSERT_TRUE(SCM_BOOLP(SCM_TRUE)); CU_ASSERT_TRUE(SCM_BOOLP(SCM_FALSE)); CU_ASSERT_FALSE(SCM_BOOLP(0)); } void test_gauche_SCM_MAKE_BOOL(void) { CU_ASSERT_TRUE(SCM_BOOLP(SCM_MAKE_BOOL(TRUE))); CU_ASSERT_TRUE(SCM_BOOLP(SCM_MAKE_BOOL(FALSE))); CU_ASSERT_TRUE(SCM_FALSEP(SCM_MAKE_BOOL(FALSE))); CU_ASSERT_TRUE(SCM_TRUEP(SCM_MAKE_BOOL(TRUE))); } void test_gauche_SCM_EQ(void) { CU_ASSERT_EQUAL(TRUE, SCM_EQ(1, 1)); CU_ASSERT_EQUAL(FALSE, SCM_EQ(1, 2)); }
規模がまだ小さいので自分メモで Makefile とかヘッダとかその他モロモロを以下に。まず test/Makefile が以下
TARGET=test OBJS=main.o test-PRIMARY_TAG.o test-IMMEDIATES.o test-BOOLEAN.o CFLAGS=-I.. -Wall LDFLAGS=-lcunit all: $(TARGET) @./$(TARGET) $(TARGET): $(OBJS) $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) clean: rm -rf $(TARGET) $(OBJS) *~
つぎは main.c
#include <CUnit/CUnit.h> #include <CUnit/Basic.h> #include "schemeTest.h" int main(void) { CU_pSuite gauche_h_suite; CU_initialize_registry(); gauche_h_suite = CU_add_suite("gauche.h", NULL, NULL); CU_add_test(gauche_h_suite, "SCM_TAG", test_gauche_SCM_TAG); CU_add_test(gauche_h_suite, "SCM_PTRP", test_gauche_SCM_PTRP); CU_add_test(gauche_h_suite, "SCM_IMMEDIATEP", test_gauche_SCM_IMMEDIATEP); CU_add_test(gauche_h_suite, "SCM_ITAG", test_gauche_SCM_ITAG); CU_add_test(gauche_h_suite, "SCM__MAKE_ITAG", test_gauche_SCM__MAKE_ITAG); CU_add_test(gauche_h_suite, "SCM_IMMEDIATEP 2", test_gauche_SCM_IMMEDIATEP_2); CU_add_test(gauche_h_suite, "SCM_BOOLP", test_gauche_SCM_BOOLP); CU_add_test(gauche_h_suite, "SCM_MAKE_BOOL", test_gauche_SCM_MAKE_BOOL); CU_add_test(gauche_h_suite, "SCM_EQ", test_gauche_SCM_EQ); CU_basic_run_tests(); CU_cleanup_registry(); return 0; }
最後に schemeTest.h
void test_gauche_SCM_TAG(void); void test_gauche_SCM_PTRP(void); void test_gauche_SCM_IMMEDIATEP(void); void test_gauche_SCM_ITAG(void); void test_gauche_SCM__MAKE_ITAG(void); void test_gauche_SCM_IMMEDIATEP_2(void); void test_gauche_SCM_BOOLP(void); void test_gauche_SCM_MAKE_BOOL(void); void test_gauche_SCM_EQ(void);
現時点で make したらこんなカンジ
$ find . ./gauche.h ./test ./test/main.c ./test/test-PRIMARY_TAG.c ./test/Makefile ./test/schemeTest.h ./test/test-IMMEDIATES.c ./test/test-BOOLEAN.c ./Makefile ./gauche.h.ORG $ make cc -I.. -Wall -c -o main.o main.c cc -I.. -Wall -c -o test-PRIMARY_TAG.o test-PRIMARY_TAG.c cc -I.. -Wall -c -o test-IMMEDIATES.o test-IMMEDIATES.c cc -I.. -Wall -c -o test-BOOLEAN.o test-BOOLEAN.c cc -o test main.o test-PRIMARY_TAG.o test-IMMEDIATES.o test-BOOLEAN.o -lcunit CUnit - A Unit testing framework for C - Version 2.1-0 http://cunit.sourceforge.net/ --Run Summary: Type Total Ran Passed Failed suites 1 1 n/a 0 tests 9 9 9 0 asserts 59 59 59 0 $
その内ここで使ってる gauche.h も貼りますが、現時点で BOOLEAN な SCM_EQ マクロまでの試験が終了してます。で、以下の
extern ScmObj Scm_EqP(ScmObj x, ScmObj y); extern ScmObj Scm_EqvP(ScmObj x, ScmObj y); extern ScmObj Scm_EqualP(ScmObj x, ScmObj y);
定義は別途、とゆー事でなるべくカンニングせずに作ってみたいな。eq? と eqv? と equal? の違いって何だったっけ。