Next: Object Internals, Previous: C Dialect, Up: GNU Emacs Internals [Contents][Index]
LispプリミティブとはCで実装されたLisp関数です。Lispから呼び出せるようにC関数インターフェースの詳細はCのマクロで処理されます。新たなCコードの記述のしかたを真に理解するにはソースを読むのが唯一の方法ですが、ここではいくつかの事項について説明します。
スペシャルフォームの例として以下はeval.cのor
です(通常の関数は同様の一般的な外観をもつ)。
DEFUN ("or", For, Sor, 0, UNEVALLED, 0, doc: /* Eval args until one of them yields non-nil, then return that value. The remaining args are not evalled at all. If all args return nil, return nil.
usage: (or CONDITIONS ...) */) (Lisp_Object args) { register Lisp_Object val = Qnil; struct gcpro gcpro1;
GCPRO1 (args);
while (CONSP (args)) { val = eval_sub (XCAR (args)); if (!NILP (val)) break; args = XCDR (args); }
UNGCPRO; return val; }
ではDEFUN
マクロの引数について詳細に説明しましょう。以下はそれらのテンプレートです:
DEFUN (lname, fname, sname, min, max, interactive, doc)
これは関数名として定義するLispシンボル名。上記例ではor
。
これは関数のC関数名。これはCコードでその関数を呼び出すために使用される名前。名前は慣習として‘F’の後にLisp名をつけて、Lisp名のすべてのダッシュ(‘-’)をアンダースコアに変更する。つまりCコードから呼び出す場合にはFor
を呼び出す。
これはLispでその関数を表すsubrオブジェクト用にデータ保持のための構造体に使用されるC変数名。この構造体はそのシンボルを作成してそれの定義にsubrオブジェクトを格納する初期化ルーチンでLispシンボル名を伝達する。慣習により常にfnameの‘F’を‘S’に置き換えた名前になる。
これは関数が要求する引数の最小個数。関数or
は最小で0個の引数を受け入れる。
これは関数が受け入れる引数の最大個数が定数なら引数の最大個数。あるいはUNEVALLED
なら未評価の引数を受け取るスペシャルフォーム、MANY
なら評価される引数の個数に制限がないことを意味する(&rest
と等価)。UNEVALLED
とMANY
はいずれもマクロ。maxが数字ならminより大きく8より小さいこと。
これはLisp関数でinteractive
の引数として使用されるようなインタラクティブ仕様(文字列)。or
の場合は0(nullポインター)であり、それはor
がインタラクティブに呼び出せないことを示す。値""
はインタラクティブに呼び出す際に関数が引数を引き受けるべきではないことを示す。値が‘"(’で始まる場合には、その文字列はLispフォームとして評価される。たとえば:
DEFUN ("foo", Ffoo, Sfoo, 0, UNEVALLED, "(list (read-char-by-name \"Insert character: \")\ (prefix-numeric-value current-prefix-arg)\ t))", doc: /* … /*)
これはドキュメント文字列。複数行を含むために特別なことを要しないので、これにはCの文字列構文ではなくCコメント構文を使用する。‘doc:’の後のコメントはドキュメント文字列として認識される。コメントの開始と終了の区切り文字‘/*’と‘*/’はドキュメント文字列の一部にはならない。
ドキュメント文字列の最後の行がキーワード‘usage:’で始まる場合には、その行の残りの部分は引数リストをドキュメント化するためのものとして扱われる。この方法によりCコード内で使用される引数名とは異なる引数名をドキュメント文字列内で使用することができる。その関数の引数の個数に制限がなければ‘usage:’は必須。
Lispコードでのドキュメント文字列にたいするすべての通常ルール(Documentation Tipsを参照)はCコードのドキュメント文字列にも適用される。
DEFUN
マクロ呼び出しの後には、そのC関数にたいする引数リストを引数のタイプを含めて記述しなければなりません。そのプリミティブがLispで固定された最大個数をもつ引数を受け入れるならLisp引数それぞれにたいして1つのC引数をもち、各引数のタイプはLisp_Object
でなければなりません(ファイルlisp.hではタイプLisp_Object
の値を作成する種々のマクロと関数が宣言されている)。そのプリミティブのLispの最大引数個数に上限がなければ正確に2つのC引数をもたなければなりません。1つ目はLisp引数の個数で、2つ目はそれらの値を含むブロックのアドレスです。これらはそれぞれint
、Lisp_Object *
のタイプをもちます。Lisp_Object
は任意のデータ型と任意のLispオブジェクトを保持できるので実行時のみ実際のデータ型を判断できます。特定のタイプの引数だけを受け入れるプリミティブを記述したければ適切な述語を使用してタイプを明確にチェックしなければなりません(Type Predicatesを参照)。
関数For
自身の中では、マクロGCPRO1
とUNGCPRO
の使用に注意してください。これらのマクロは、Emacsのデフォルトであるスタックマーキングを使用したガーベージコレクションを使用しない、いくつかのプラットフォームのために定義されています。GCPRO1
マクロは、ガーベージコレクションにその変数とコンテンツすべてがアクセス可能でなければならないと、明示的にガーベージコレクションに通知して、ガーベージコレクションから変数を“保護”します。直接または間接的に、サブルーチンとしてeval_sub
かFeval
を呼び出してLisp評価を行うかもしれないすべての関数で、GC保護は必要です。
各オブジェクトにたいして、それを指すポインターが少なくとも1つあれば、GCからの保護を確実に満足することができます。つまり、ある特定のローカル変数が、(GCPRO
をもつ別のローカル変数のような)別のポインターにより保護されるであろうオブジュクトを指すことが確実なら、保護なしでこれを行うことができます。それ以外なら、そのローカル変数にはGCPRO
が必要になります。
マクロGCPRO1
は、ただ1つのローカル変数を保護します。2つの変数を保護したい場合には、かわりにGCPRO2
を使用します。GCPRO1
を繰り返しても、機能しないでしょう。GCPRO3
、GCPRO4
、GCPRO5
、GCPRO6
のマクロもあります。これらのマクロのすべては、gcpro1
のようなローカル変数を暗黙に使用します。あなたはこれらをタイプstruct
gcpro
で、明示的に宣言しなければなりません。つまりGCPRO2
を使用するなら、gcpro1
とgcpro2
を宣言しなければなりません。
UNGCPRO
は、カレントの関数内で保護された、変数の保護を取り消します。これは明示的に行う必要があります。
Emacsが一度ダンプされた後に変数に何か書き込まれているときには、その静的変数やグローバル変数にCの初期化を使用してはなりません。初期化されたこれらの変数はEmacsのダンプの結果として、(特定のオペレーティングシステムでは)読み取り専用となるメモリーエリアに割り当てられます。Pure Storageを参照してください。
C関数の定義だけではLispプリミティブを利用可能にするのに十分ではありません。そのプリミティブにたいしてLispシンボルを作成して関数セルに適切なsubrオブジェクトを格納しなければなりません。このコードは以下のようになるでしょう:
defsubr (&sname);
ここでsnameはDEFUN
の3つ目の引数として使用する名前です。
すでにLispプリミティブが定義されたファイルにプリミティブを追加する場合には、(そのファイル終端付近にある)syms_of_something
という名前の関数を探してdefsubr
の呼び出しを追加してください。ファイルにこの関数がない、または新たなファイルを作成する場合にはsyms_of_filename
(例:
syms_of_myfile
)を追加します。それからemacs.cでそれらの関数が呼び出されるすべての箇所を探してsyms_of_filename
の呼び出しを追加してください。
関数syms_of_filename
はLisp変数として可視となるすべてのC変数を定義する場所でもあります。DEFVAR_LISP
はタイプLisp_Object
のC変数をLispから可視にします。DEFVAR_INT
はタイプint
のC変数を常に整数となる値をもつようにしてLispから可視にします。DEFVAR_BOOL
はタイプint
のC変数を常にt
かnil
のいずれかとなる値をもつようにしてLispから可視にします。DEFVAR_BOOL
で定義された変数はバイトコンパイラーに使用されるリストbyte-boolean-vars
に自動的に追加されることに注意してください。
Cで定義されたLisp変数をdefcustom
で宣言された変数のように振る舞わせたければcus-start.elに適切なエントリーを追加してください。
タイプLisp_Object
のファイルをスコープとするC変数を定義する場合には、以下のようにsyms_of_filename
内でstaticpro
を呼び出してガーベージコレクションから保護しなければなりません:
staticpro (&variable);
以下はより複雑な引数をもつ別の関数例です。これはwindow.cからのコードであり、Lispオブジェクトを操作するためのマクロと関数の使用を示すものです。
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p, Scoordinates_in_window_p, 2, 2, 0, doc: /* Return non-nil if COORDINATES are in WINDOW. ...
or `right-margin' is returned. */) (register Lisp_Object coordinates, Lisp_Object window) { struct window *w; struct frame *f; int x, y; Lisp_Object lx, ly;
CHECK_LIVE_WINDOW (window); w = XWINDOW (window); f = XFRAME (w->frame); CHECK_CONS (coordinates); lx = Fcar (coordinates); ly = Fcdr (coordinates); CHECK_NUMBER_OR_FLOAT (lx); CHECK_NUMBER_OR_FLOAT (ly); x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH(f); y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH(f);
switch (coordinates_in_window (w, x, y)) { case ON_NOTHING: /* NOT in window at all. */ return Qnil;
...
case ON_MODE_LINE: /* In mode line of window. */ return Qmode_line;
...
case ON_SCROLL_BAR: /* On scroll-bar of window. */ /* Historically we are supposed to return nil in this case. */ return Qnil;
default: abort (); } }
Cコードは、それらがCで記述されていなければ、名前で呼び出すことはできないことに注意してください。Lispで記述された関数を呼び出すには、関数funcall
を具現化したFfuncall
を使用します。Lisp関数funcall
は個数制限なしの引数を受け付けるので、Cでの引数はLispレベルでの引数個数と、それらの値を含む1次元配列という、2個の引数になります。Lispレベルでの1つ目の引数は呼び出す関数で、残りはそれに渡す引数です。Ffuncall
は評価機能(evaluator)を呼び出すかもしれないので、Ffuncall
の呼び出し前後でガーベージコレクションからポインターを保護しなければなりません。
C関数call0
、call1
、call2
、...は個数が固定された引数でLisp関数を手軽に呼び出す便利な方法を提供します。これらはFfuncall
を呼び出すことにより機能します。
eval.cは例を探すのに適したファイルです。lisp.hには重要なマクロと関数の定義がいくつか含まれています。
副作用をもたない関数を定義する場合には、コンパイラーのオプティマイザーに知らせるためにside-effect-free-fns
とside-effect-and-error-free-fns
をバインドするbyte-opt.el内のコードを更新してください。
Next: Object Internals, Previous: C Dialect, Up: GNU Emacs Internals [Contents][Index]