外部関数インターフェイス
HCl はCとの簡単な外部関数インターフェイス機能を持っています。実際に
system:unix-argc,system:unix-argv, system:unix-getenvなどは
このメカニズムによって実現されています。これらの関数はuser0.cに記述
されていますから、それを見ればfixnumを引数とする外部関数ならば容易
にインターフェイスできると思います。ユーザーが外部関数を定義するための
窓口としてuser1-4.cがmakefileに既に記述されているので、これらに関数を
定義し、トップレベルのmake(Makefile)を実行することによってCで記述された
関数を含むHCl が作られます。
HCl ではCで定義した関数を外部リンクした場合、イニシャライズを行うことに
よってHCl から通常の関数と同じように見えるようにできます。
user0-4.cにはHCl がスタート時に一度呼び出すエントリ
user0_i,user1_i,user2_i,user3_i,user4_iが定義されています。
これらはfinit.srcが呼び出すものです。user?_iでは
init_xf("SYSTEM","UNIX-ARGC",ux_argc)
の形式でC関数とHCl 関数とが結合されますinit_xfの第一引数はlisp
レベルの関数定義が属するパッケージ名、第二引数はlispレベルの関数名、
第三引数はCレベルの定義名です。この例ではCで定義されたux_argc
がsystem:unix-argcというlisp関数となって現れます。
Cで定義された関数がlispから呼び出された場合、その引数はlispオブジェクト
のままでC関数に渡ります。渡された引数の個数を知る方法はありません
(*)
。
HCl のオブジェクトとCのオブジェクトは内部表現が異なりますからC側での
データ表現を得るためには簡単な処理が必要になります。詳細なデータ構造の
定義については{\tt doc/hclarch.doc}に内部表現の記述があるのでそれを
参考にして下さい。ここでは代表的な場合について簡単に説明します。
- fixnum
- fixnumの場合には実際の値はオブジェクトからオフセット
0xc8000000を引いたものとなります。このオフセット値はhcl2c.h中で
FIXNUM_OFFSETとして
定義されています。
ux_argv(n)
OBJECT n;
{ int x;
x = n - FIXNUM_OFFSET;
.........
}
この例ではnはlispオブジェクトのfixnumですがxはCでの同じ値の整数となります。
- character
- character objectをC側で受け取る場合は下位24bitのみ
が意味を持ちます。従ってタグを取り去るマクロinf(x)を用いて
実際の値を取り出します。
charxmp(c)
OBJECT c;
{ char cc;
cc = inf(c);
.............
}
- double
- double floatの場合は格納場所へのポインタがタグ付きで
渡されます。タグを取り去るマクロ
inf(x)
を用いポインタを得、
それを用いて値を取り出します。
ux_dmy(n)
OBJECT n;
{ double *p,q;
p = (double *)inf(n);
q=*p;
printf("\f",q)
.........
}
この例ではnはHCl のオブジェクトですがqはCのdoubleで同じ値を有します。
- simple-string
- simple-stringの場合にはHCl でのsimple-stringの内部表現を知る必要が
あります。HCl でのsimple-stringはpointer+tagで表現されており、pointer
を得るためにはまずオブジェクトからtagを剥す必要があります。このための
マクロが
inf(x)
です。simple-stringの実体はCの構造体では次のように
定義されます。
struct HCL_STRING {int length;
char ch[SIZE];
}
ここでSIZEはlength分だけアロケートされています。Cとのインターフェースで
扱いにくいのは文字列の最後に0がセットされていない点です。従って
Cプログラム上の文字列として取扱いたい場合には一旦バッファ領域にコピー
する必要があります。
- simple-vector
simple-vector
もsimple-string
と同じく
pointer+tagで表現されており、inf(x)でタグを取り去ったあとで
simple-vectorの構造体へのポインタとして配列要素をアクセスします。
定義は次のようになっています。
struct HCL_VECTOR {int length;
OBJECT elt[SIZE];
}
ここでlengthは要素数の4倍であり、OBJECTはintと同じと考えていいです。
(*)MC88100版HClではC関数に渡せる引数の個数は最大8個に限定されます
Cで記述した関数は1個の値のみを返すことができます。もっとも簡単な場合は
nilを返す場合です。nilは内部では0x0で表現されていますので
(return NIL)
とすることによりそれを返すことが出来ます。
24bit以内の整数の場合はFIXNUM_OFFSETを加えることによってfixnumを作成し
返すことができます。それ以外の場合は一般に勧められません。どうしても
必要ならば副作用を用いるか、静的なオブジェクトの構造体を宣言しそこに
値の実体を格納しpointer+tagの形でオブジェクトを構成することによって
stringやdouble floatを返すことができます。unix0.cにこのメカニズムによって
作成された関数、ux_argv,ux_getenv
がありますので参考にして下さい。
MC88100をCPUとする版ではHCl から呼び出す外部関数の引数
の数は8以下に限定されます。
この制限は暫定的なもので将来は解決されます。
従ってX11のインターフェースでは一部の関数が8個以上の引数を取ります
ので現在のDG AViiON版では使用できません。
もくじ