こんにちは、鈴木です。
「C言語からGaucheを使おう!」シリーズです。
前回の「C言語からGaucheを使おう! (6) Scm_Applyで手続きを呼び出す」で手続きを呼び出す方法を調べたので、今回はいよいよ Scheme プログラムを load する方法を調べよう!と思っていたのですが予定を変更します。
というのも、試行錯誤しながらなので、デバッグ用の道具(エラー表示やデバッグ出力など)を整理しておきたかったからです。
eval や load 時に発生したエラー内容を表示する
Scm_Eval/Scm_EvalCString を紹介した時に、以下のようなエラーハンドリングのコード(例外の内容を表示するコード)を記述しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdio.h> #include <gauche.h> int main() { const char *source = "(+ 10 20)"; ScmEvalPacket eval_packet; GC_INIT(); Scm_Init(GAUCHE_SIGNATURE); if(Scm_EvalCString(source, SCM_OBJ(Scm_UserModule()), &eval_packet) < 0) { printf("[%s] %s\n", SCM_STRING_CONST_CSTRING(Scm_ConditionTypeName(eval_packet.exception)), SCM_STRING_CONST_CSTRING(Scm_ConditionMessage(eval_packet.exception))); } else { printf("%ld\n", SCM_INT_VALUE(eval_packet.results[0])); } return 0; } |
この処理は何度か登場しているので、以下のようなマクロを定義しました。
1 2 3 4 5 6 7 |
/** * ScmEvalPacket や ScmLoadPacket に含まれる例外情報を表示します. */ #define PRINT_EXCEPTION(packet) \ printf("[%s] %s\n", \ SCM_STRING_CONST_CSTRING(Scm_ConditionTypeName(packet.exception)), \ SCM_STRING_CONST_CSTRING(Scm_ConditionMessage(packet.exception))); |
関数ではなくマクロとしている理由は、ScmEvalPacket と ScmLoadPacket の両方を扱いたかったからです。
ScmLoadPacket は今後取り上げる予定の Scm_Load/Scm_LoadFromPort (load 相当の処理を行う関数)で使用する構造体です。
オブジェクトの内容を表示する
※コメントで教えて頂いた Scm_Printf() 関数を使用する方が簡単でしたので、「追記: Scm_Printf() で表示する」もご参照ください。
オブジェクトの内容を表示する方法は「C言語からGaucheを使おう! (2) 基本的な値の生成」でも登場しましたが、データ型に応じて SCM_INT_VALUE や SCM_BOOL_VALUE などを使い分けるのは面倒です。
そこで、Scheme における「(write object)」相当の処理を行う関数 print_object を作成しました。
1 2 3 4 5 6 7 8 9 10 11 |
/** * オブジェクトの内容を表示します. * Scheme における (write object) 相当の処理を行います. */ void print_object(ScmObj object) { ScmObj output = Scm_MakeOutputStringPort(TRUE); Scm_Write(object, output, SCM_WRITE_DISPLAY); printf("%s\n", SCM_STRING_CONST_CSTRING(Scm_GetOutputString(SCM_PORT(output), 0))); Scm_ClosePort(SCM_PORT(output)); } |
追記: Scm_Printf() で表示する
コメントで shiro さんに教えて頂いた Scm_Printf() 関数を使用する方法です。(ありがとうございました)
手軽にオブジェクトの内容を表示したい場合は、この方法がお勧めです。
Scm_Printf() は以下のように、C言語の fprintf() のようなインタフェースで使用することができます。
1 |
Scm_Printf(SCM_CUROUT, "The value is %S\n", obj); |
関数の第一引数には ScmPort* を指定します。
標準出力を表す SCM_CUROUT, 標準エラー出力を表す SCM_CURERR マクロが定義されています。
write.c を確認すると、Scm_Sprintf() や Scm_Vsprintf() など、同じ系統の関数も定義されていましたので、用途に応じて使い分けると良さそうです。
まとめ
今回はデバッグ用の道具ということで、PRINT_EXCEPTION マクロと print_object 関数を作成しました。
次回は Scheme プログラムを load する方法を調べたいと思います。
Comments
C言語からSchemeの値を表示するには、Scm_Printfも便利です。fprintfと似た感じで使えます。
Scm_Printf(SCM_CUROUT, "The value is %S\n", obj);
fprintfのFILE*に相当する第一引数にはScmPort*を渡します。現在の出力SCM_CUROUT, 現在のエラー出力SCM_CURERRというマクロが使えます。
フォーマット指示文字列は%d, %l, %sなどがprintfと同様に使える他、%S, %AでScmObjが表示できます (%Sはwrite、%Aはdisplayによる表示)。また、%CでScmChar が表示できます。
shiro さん、コメントありがとうございます!
Scm_Printf() という関数があったんですね。気付きませんでした(^^;
エントリの内容にも追記させていただきました。