関数のいくつかと特殊フォーム(の全て)は C で書かれています。 (使いやすい)インタ フェースがマクロの集まりとして提供されています。 C のコードの書きかたを(本当 に) 理解する唯一の方法は、ソースを読むことですが、ここではある程度の情報を示し ておきます。
特殊フォーム(ある程度よく現われる通常の関数) の例として or の定義を `eval.c' から取りました。
/* NOTE!! Every function that can call EVAL must protect its args and temporaries from garbage collection while it needs them. The definition or `For' show what you have to do. */
DEFUN ("or", For, Sor, 0, UNEVALLED, 0, "Eval args until one of them yields non-NIL, then return that value.\n\ The remaining args are not evalled at all.\n\ If all args return NIL, return NIL.") (args) Lisp_Object args; { register Lisp_Object val; Lisp_Object args_left;
struct gcpro gcpro1;
if (NULL(args)) return Qnil;
args_left = args; GCPR01 (args_left);
do { val =Feval (Fcar (arg_left)); if (!NULL (val)) break; args_left = Fcdr (args_left); } while (!NULL(args_left));
UNGCPR0; return val; }
DEFUN マクロに対するアーギュメントの(詳細な)説明を以下に示します。
最初のアーギュメントは、Lisp における関数名です。これは `or' と名付けられま す。
2 番目のアーギュメントは、この関数に対する C の関数の名前です。これは C コード からこの関数を呼ぶ際、用いられる名前です。この名前は (慣例として) Lisp 名にお ける - (訳注:dash) を全て _ (訳注:underscore) に変え、頭に `F' を付けたもの となります。このように、(あなたの) C コードがこの関数を呼ぶ場合、それは For(...) を呼ぶことになります。アーギュメントは Lisp_Objects でなくてはいけな いことを覚えておいて下さい。Lisp_Objects を作る様々なマクロと関数は、ファイル lisp.h に与えられています。
3 番目のアーギュメントは、この関数が記述する Lisp primitive を指す C の変数で す。この名前は慣例として (関数名を作る場合と同じように) 名前の頭に "S" を付け たものとなります。
4 番目のアーギュメントは、与えられなくてはいけないアーギュメントの数の最小値を 示します。i.e. 必要とされるアーギュメントの数。例の場合、アーギュメントは必要 とされません。
5 番目のアーギュメントは、与えられうるアーギュメントの最大値を示します。アー ギュメントを評価しないことを示すマクロ UNEVALLED がこの数になっているため、こ れは特殊フォームであることになります (訳注:??)。 &rest アーギュメントに等価な ものを持つ関数は、この場所にマクロ MANY を持つことになります。このアーギュメン トは、これらのマクロのどれかか、少なくとも 4番目のアーギュメントの大きさの数で なくてはいけません。
6 番目のアーギュメントは、Lisp で与えられているのと(全く)同じ interactive 指示 です。例の場合、これは 0 (null ポインタ) で、この関数をインタラクティブに呼ぶ ことはできないことを示します。値 "" はアーギュメントを取らないインタラクティブ 関数を示します。
最後のアーギュメントは、ドキュメンテーションストリングです。
アーギュメントのリストは与えられなくてはならず、その(全て Lisp のオブジェクト である)もののタイプは宣言されなくてはいけません。
すでに(その中で) Lisp の primitive を定義しているファイルを修正する場合、(その ファイルの終り近くにある) syms-of-<何か> という名前の関数を探し
defsubr (&S名前);
という形式の行を追加して下さい。
ファイルがこの関数を持たない場合や新しくファイルを作る場合、 syms_of_ファイル 名 e.g. syms_of_eval を追加し、`emacs.c' でこれらの関数が呼ばれている場所を探 します。そこにシンボルの初期化のための関数を追加します。これにより、サブルーチ ン (primitives) の全てを Lisp から用いることができるようになります。
次に、より複雑なアーギュメントを持つ(別の)関数を示します。これは X ウィンドウ システム用のコードからのもので、 Lisp オブジェクトを操作するマクロと関数の使用 方法を示します。
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p, Scoordinates_in_window_p, 2, 2, "xSpecify coordinate pair: \nXExpression which evals to window: ", "Return non-nil if POSITIONS (a list, (SCREEN-X SCREEN-Y)) is in WINDOW.\n\ Returned value is list of positions expressed\n\ relative to window upper left corner.") (coordinate, window) register Lisp_Object coordinate, window; { register Lisp_Object xcoord, ycoord;
if (!LISTP (coordinate)) wrong_type_argument (Qlistp, coordinate); CHECK_WINDOW (window, 2); xcoord = Fcar (coordinate); ycoord = Fcar (Fcdr (coordinate)); CHECK_NUMBER (xcoord, 0); CHECK_NUMBER (ycoord, 1); if ((XINT (xcoord) < XINT (XWINDOW (window)->left)) || (XINT (xcoord) >= (XINT (XWINDOW (window)->left)) XINT (XWINDOW (window)->width)))) { return Qnil; }
XFSTING (xcoord) -= XFASTINT (XWINDOW (window)->left); if (XINT (ycoord) == (screen_height -1)) return Qnil; if ((XINT (ycoord) < XINT (XWINDOW (window)->top)) || (XINT (ycoord) >= (XINT (XWINDOW (window)->top)) XINT (XWINDOW (window)->height)) -1)) { return Qnil; } XFASTINT (ycoord) -= XFASTINT (XWINDOW (window)->top); return (Fcons (xcoord, Fcons (ycord, Qnil))); }
同様に、defvar と defconst に対応するものが存在しています。また Lisp インタプ リタに対応するものが存在しないものもいくつか存在します。
Lisp で定義された関数を直接呼び出すことはできない点に注意して下さい。例えば、 上の例では (訳注:かわりに) Fcons を呼んでいます。 For の例で行なったように、 適切な Lisp フォームを作り、ガベージコレクションから全てを守り、そのフォームを Feval しなくてはいけません。
例になるものを探すには、`eval.c' は (大変)適したファイルです。`lisp.h' はいく つか重要なマクロや関数の定義を含んでいます。