[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B. GNU Emacsの内部

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=GNU%20Emacs%20Internals"
"elisp/B.GNUEmacsの内部"へのコメント(無し)

本章では、Lispライブラリをあらかじめロードした実用的なEmacsの実行形式の ダンプ方法、メモリ領域の割り当て方、 Cプログラマに興味があるようなGNU Emacsの内部について述べます。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.1 Emacsの構築方法

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Building%20Emacs"
"elisp/B.1Emacsの構築方法"へのコメント(無し)

本節では、Emacsの実行形式を構築する手順を説明します。 メイクファイルが自動的にこれらすべてを行うので、 Emacsを構築してインストールするために本節のことがらを 読者が知っている必要はありません。 本節の内容は、Emacsの保守者向けです。

ディレクトリ`src'のCソースファイル群をコンパイルすると、 `temacs'と呼ばれる実行形式ファイルが作られます。 これは裸のインピュアEmacs(bare impure Emacs)とも呼びます。 これには、Emacs Lispインタープリタと入出力ルーティンが含まれますが、 編集コマンドは入っていません。

コマンド`temacs -l loadup'で、 実用的なEmacsの実行形式を作るために`temacs'を使います。 これらの引数は、`temacs'に対して ファイル`loadup.el'で指定したLispファイル群を評価するように指示します。 これらのファイルはEmacsの通常の編集環境を作り上げ、 その結果、Emacsは裸ではありませんがまだインピュアです。

標準のLispファイル群をロードするにはかなり時間が必要です。 しかし、読者がEmacsを実行するたびにこれを行う必要はありません。 `temacs'は、必要なファイルをあらかじめロードした`emacs'という 実行形式プログラムとしてダンプできます。 `emacs'はファイル群をロードする必要がないので素早く起動します。 これが通常インストールされるEmacsの実行形式です。

`emacs'を作るにはコマンド`temacs -batch -l loadup dump'を使います。 ここでの`-batch'の目的は、 `temacs'が端末に関するデータを初期化しないようにするためです。 これにより、ダンプしたEmacsでは端末情報の表が空であることを保証できます。 引数`dump'は、`emacs'という名前の新たな実行形式を ダンプするように`loadup.el'に指示します。

ダンプできないオペレーティングシステムもあります。 そのようなシステムでは、Emacsを使うたびに コマンド`temacs -l loadup'でEmacsを起動する必要があります。 これにはかなり時間がかかりますが、多くても1日に1回、あるいは、 ログアウトしなのであれば週に1回Emacsを起動する必要があるだけでしょうから、 余分な時間は重大問題にはならないでしょう。

あらかじめロードしておく追加のファイルは、 それらをロードする`site-load.el'という名前のライブラリを 書くことで指定できます。 追加データのための領域を確保するために `src/puresize.h'のPURESIZEの値を増やす必要があるかもしれません。 (十分な大きさになるまで20000ずつ増やして試すこと。) しかし、マシンが速くなればなるほど、あらかじめロードしておくファイルを 追加することの利点は減少します。 最近のマシンでは、このようにする必要はないでしょう。

`loadup.el'が`site-load.el'を読み終えると、 Snarf-documentation(see 節 23.2 説明文字列の参照)を呼び出して、 基本関数やあらかじめロードした関数(および変数)の説明文字列を それらの説明文字列を格納したファイル`etc/DOC'から探します。

ダンプする直前に実行すべきList式を指定するには、 `site-init.el'という名前のライブラリにそれらのLisp式を入れておきます。 このファイルは、説明文字列を探し終えてから実行されます。

関数定義や変数定義をあらかじめロードしたいときには、 それを行ってあとでEmacsを実行したときにそれらの説明文字列を 参照できるようにする方法が3つあります。

無変更の普通のEmacsにユーザーが期待する機能を変更するようなものを `site-load.el'や`site-init.el'に入れることは勧められません。 読者のサイトでは普通の機能に優先させるべきであると思うときには、 `default.el'でそれを行います。 そうすれば、ユーザーは好みに応じて読者が行った変更を無効にできます。 See 節 37.1.1 概要:始動時の動作手順

Function: dump-emacs to-file from-file
この関数は、Emacsの現在の状態を 実行形式ファイルto-fileへダンプする。 from-file(これは普通は実行形式ファイル`temacs')から シンボルを取り出す。

すでにダンプしたEmacsでこの関数を使うときには、 `-batch'を指定してEmacsを実行すること。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.2 ピュアメモリ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Pure%20Storage"
"elisp/B.2ピュアメモリ"へのコメント(無し)

Emacs Lispでは、ユーザーが作成したLispオブジェクト向けに 2種類のメモリ、普通メモリ(normal storage)と ピュアメモリ(pure storage)を使います。 普通メモリは、Emacsセッション中に新たに作成されるすべてのデータを置く場所です。 普通メモリに関する情報は以下の節を参照してください。 ピュアメモリは、あらかじめロードした標準Lispファイル群の特定のデータ、 つまり、Emacsの実行中にけっして変化しないデータを収めるために使います。

ピュアメモリは、`temacs'があらかじめロードする標準Lispライブラリを ロードしている最中にのみ割り当てられます。 ファイル`emacs'では読み出し専用 (これができるオペレーティングシステムでは)と印が付けられ、 当該マシンで同時に実行されているすべてのEmacsのジョブで メモリ領域を共有できるようにします。 ピュアメモリは拡張できません。 Emacsをコンパイルしたときに固定サイズが割り当てられ、 あらかじめロードするライブラリに対して十分な大きさがないと `temacs'はクラッシュします。 その場合には、ファイル`src/puresize.h'のコンパイルパラメータ PURESIZEを増やす必要があります。 あらかじめロードするライブラリを追加したり標準機能に機能を追加しなければ、 そのようなことは普通は起こらないはずです。

Function: purecopy object
この関数は、ピュアメモリ内にobjectをコピーしそれを返す。 文字列のコピーでは、ピュアメモリ内に同じ文字の新たな文字列を単純に作る。 ベクトルやコンスセルの内容は再帰的にコピーする。 シンボルなどの他のオブジェクトはコピーせずに無変更でそれらを返す。 マーカをコピーしようとするとエラーを通知する。

この関数は、Emacsを構築してダンプするとき以外ではなにもしない。 普通はファイル`emacs/lisp/loaddefs.el'でのみ呼び出されるが、 あらかじめロードするとこれを呼び出すようなパッケージも少数だがある。

Variable: pure-bytes-used
この変数の値は、割り当て済みのピュアメモリのバイト数である。 典型的には、ダンプしたEmacsでは この値は利用可能なピュアメモリの総量にとても近い。 そうでない場合には、あらかじめロードしたライブラリが少ないのであろう。

Variable: purify-flag
この変数は、defunが関数定義をピュアメモリに コピーすべきかどうかを決定する。 nil以外であると、関数定義をピュアメモリにコピーする。

Emacsを構築中の初期段階ですべての基本的な関数をロード中には (これらの関数を共有してガベッジコレクションの対象にしないように)、 このフラグはtである。 実行形式としてEmacsをダンプするときには、 ダンプ前後の実際の値には関係なくこの変数にはnilを書く。

実行中のEmacsでこのフラグを変更するべきではない。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.3 ガベッジコレクション

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Garbage%20Collection"
"elisp/B.3ガベッジコレクション"へのコメント(無し)

プログラムがリストを作成したり、(ライブラリをロードするなどして) ユーザーが新たに関数を定義すると、 それらのデータは普通メモリへ置かれます。 普通メモリが足りなくなると、Emacsはオペレーティングシステムに 1kバイトの倍数のブロックでメモリ割り当てを要求します。 各ブロックは1つの種類のLispオブジェクトに使いますから、 シンボル、コンスセル、マーカなどはメモリの異なるブロックに分離されます。 (ベクトル、長い文字列、バッファ、特定の編集向けデータ型などの 比較的大きなものは各オブジェクトごとに独立のブロックを割り当てるが、 短い文字列は8kバイトのブロックに詰め込む。)

あるメモリ部分をしばらく使ってから、 (たとえば)バッファを削除したり オブジェクトに対する最後の参照を削除するなどして 当該メモリを解放することはよくあることです。 Emacsには、このような放置されたメモリを回収する ガベッジコレクタ(garbage collector)があります。 (この名前は伝統的だが、 『ガベッジリサイクル』のほうがこの機能を直観的に表すかもしれない。)

ガベッジコレクタは、Lispプログラムから現時点で参照可能な すべてのLispオブジェクトを探して印を付けることで動作します。 まず、すべてのシンボル、それらの値、それらに関連付けられた関数定義、 および、スタック上の任意のデータは参照可能であると仮定します。 参照可能なオブジェクトから間接的に辿れる任意のオブジェクトも 参照可能です。

印付けが終ったときには、無印であるすべてのオブジェクトは ゴミ(ガベッジ)です。 Lispプログラムやユーザーがなにをしようと、 無印のオブジェクトに辿り着く方法はないのでそれらを参照することは不可能です。 無印のオブジェクトを使っているものはいないので、 それらのメモリ領域は再利用できます。 ガベッジコレクタの2段目の動作(『掃く』(sweep))は、 無印のオブジェクトのメモリ領域を再利用できるようにすることです。

掃き作業では、未使用のコンスセルを自由リスト(free list)に入れて、 将来の割り当てに備えます。 シンボルやマーカについても同様です。 参照可能な文字列は8kバイトのブロックより小さな領域を占めるように詰め込み、 不要になった8kバイトのブロックは解放します。 ベクトル、バッファ、ウィンドウ、他の大きなオブジェクトは、 mallocfreeを使って個別に割り当てたり解放します。

Common Lispに関した注意: 他のLispと異なり、GNU Emacs Lispでは、 自由リストが空になってもガベッジコレクタを呼び出さない。 そのかわりに、オペレーティングシステムにメモリ割り当てを単純に要求し、 gc-cons-thresholdバイトを使い尽くすまでは処理を継続する。

つまり、ガベッジコレクタを明示的に呼び出した直後のLispプログラムの部分では、 (プログラムのその部分で2度目にガベッジコレクタを呼び出すほど 多くのメモリを使わないと仮定すれば) その部分を実行中にはガベッジコレクタが呼ばれないことを保証できるのである。

コマンド: garbage-collect
このコマンドはガベッジコレクタを実行し、 使用中のメモリ量に関する情報を返す。 (まえのガベッジコレクタの起動後に gc-cons-thresholdバイト以上のLispデータを使うと 自発的なガベッジコレクタの起動を引き起こす。)

garbage-collectが返すリストにはつぎの情報が含まれる。

 
((used-conses . free-conses)
 (used-syms . free-syms)
 (used-miscs . free-miscs)
 used-string-chars 
 used-vector-slots
 (used-floats . free-floats)
 (used-intervals . free-intervals))

例を示す。

 
(garbage-collect)
     => ((106886 . 13184) (9769 . 0)
                (7731 . 4651) 347543 121628
                (31 . 94) (1273 . 168))

各要素の意味はつぎのとおりである。

used-conses
使用中のコンスセルの個数。

free-conses
オペレーティングシステムから得たメモリであるが 現在未使用なコンスセルの個数。

used-syms
使用中のシンボルの個数。

free-syms
オペレーティングシステムから得たメモリであるが 現在未使用なシンボルの個数。

used-miscs
その他の使用中のオブジェクトの個数。 マーカ、オーバレイ、ユーザーに見えないある種のオブジェクトを含む。

free-miscs
オペレーティングシステムから得たメモリであるが 現在未使用なその他のオブジェクトの個数。

used-string-chars
使用中の文字列の総文字数。

used-vector-slots
存在するベクトルの要素の総個数。

used-floats
使用中の浮動小数点数の個数。

free-floats
オペレーティングシステムから得たメモリであるが 現在未使用な浮動小数点数の個数。

used-intervals
使用中のインターバルの個数。 インターバルとはテキスト属性を表現するために使う内部データ構造である。

free-intervals
オペレーティングシステムから得たメモリであるが 現在未使用なインターバルの個数。

User Option: garbage-collection-messages
この変数がnil以外であると、 Emacsはガベッジコレクションの始まりと終りにメッセージを表示する。 デフォルト値はnilであり、そのようなメッセージを表示しない。

User Option: gc-cons-threshold
この変数の値は、ガベッジコレクションのあとで つぎにガベッジコレクションを起こすまでに Lispオブジェクトに割り当てるべきメモリバイト数である。 コンスセルは8バイト、 文字列は1文字1バイトと数バイトのオーバヘッドといった具合である。 バッファの内容に割り当てたメモリ量は数えない。 この閾値を越えてもただちにつぎのガベッジコレクションは起こらず、 つぎにLispのエバリュエータが呼ばれときに起きる。

最初の閾値は400,000である。 より大きな値を指定すると、ガベッジコレクションの起動回数が少なくなる。 ガベッジコレクションに費す時間を減少できるが、 全体のメモリ使用量を増加させる。 大量のLispデータを作成するようなプログラムを実行するときに設定する。

10,000までの小さな値を指定すると、 ガベッジコレクションの回数を増やせる。 10,000未満の値が意味を持つのはつぎにガベッジコレクションが起きるまでである。 garbage-collectは閾値を10,000に戻す。

garbage-collectが返す値は、データ型ごとのLispデータのメモリ使用量です。 対照的に、関数memory-limitは、 Emacsが現在使用中のメモリ総量に関する情報を与えます。

Function: memory-limit
この関数は、Emacsが最後に割り当てた最終バイトのアドレスを 1024で割ったものを返す。 値を1024で割るのは、Lispの整数に収めるためである。

読者の操作がメモリ使用量にどのように影響するかを調べるのに使える。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.4 メモリ使用量

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Memory%20Usage"
"elisp/B.4メモリ使用量"へのコメント(無し)

これらの変数は、Emacsが割り当てたデータ型ごとのメモリ総量に関する 情報を与えます。 これらと(garbage-collect)が返す値との違いに注意してください。 (garbage-collect)の値は現存するオブジェクトを数えますが、 これらの変数は、すでに解放したオブジェクトを含めて 割り当てたオブジェクトの個数やサイズを数えます。

Variable: cons-cells-consed
このEmacsセッションでこれまでに割り当てたコンスセルの総数。

Variable: floats-consed
このEmacsセッションでこれまでに割り当てた浮動小数点数の総数。

Variable: vector-cells-consed
このEmacsセッションでこれまでに割り当てたベクトルセルの総数。

Variable: symbols-consed
このEmacsセッションでこれまでに割り当てたシンボルの総数。

Variable: string-chars-consed
このEmacsセッションでこれまでに割り当てた文字列の総文字数。

Variable: misc-objects-consed
このEmacsセッションでこれまでに割り当てたその他のオブジェクトの総数。 マーカやオーバレイ、ユーザーに見えないある種のオブジェクトを含む。

Variable: intervals-consed
このEmacsセッションでこれまでに割り当てたインターバルの総数。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.5 Emacs基本関数の書き方

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Writing%20Emacs%20Primitives"
"elisp/B.5Emacs基本関数の書き方"へのコメント(無し)

Lisp基本関数は、Cで実装したLisp関数です。 Lispから呼び出すためのCの関数とのインターフェイスの詳細は、 数個のCのマクロで処理しています。 新たにCのコードを書く方法をほんとうに理解する唯一の方法は、 ソースを読むことですが、ここではその一部を説明します。

スペシャルフォームの例は、`eval.c'から引用したorの定義です。 (普通の関数も同じように見える。)

 
DEFUN ("or", For, Sor, 0, UNEVALLED, 0,
  "Eval args until one of them yields non-nil; 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;
  GCPRO1 (args_left);

  do
    {
      val = Feval (Fcar (args_left));
      if (!NULL (val))
        break;
      args_left = Fcdr (args_left);
    }
  while (!NULL (args_left));

  UNGCPRO;
  return val;
}

マクロDEFUNの引数の詳しい説明から始めます。 その雛型はつぎのとおりです。

 
DEFUN (lname, fname, sname, min, max, interactive, doc)

lname
関数名として定義するLispシンボルの名前である。 上の例では、orである。

fname
この関数のCの関数としての名前である。 この関数をCのコードから呼び出すときに使う名前である。 慣習により、Lispでの名前のまえに`F'を付けるが、 Lispでの名前のダッシュ(`-')はすべて下線に置き換える。 したがって、Cのコードからこの関数を呼び出すには、Forを呼び出す。 引数はLisp_Object型である必要があることに注意してほしい。 ファイル`lisp.h'では、 Lisp_Object型の値を作成するためのさまざまなマクロや関数を宣言してある。

sname
これは、Lispでの関数を表現するsubrオブジェクト向けのデータを保持する 構造体に使うCの変数名である。 この構造体は、シンボルを作成しその定義としてsubrオブジェクトを保存する 初期化ルーティンへLispのシンボル名を運ぶ構造体である。 慣習により、この名前はつねに fnameの`F'を`S'に置き換えたものである。

min
関数が必要とする引数の最小の個数である。 関数orは最小0個の引数を許す。

max
関数が許す引数の最大の個数に制限があるときの引数の最大の個数である。 あるいは、評価していない引数を受け取るスペシャルフォームであることを 表すUNEVALLED、 評価済みの引数を何個でも受け取ることを表すMANY&restに等価)でもよい。 UNEVALLEDMANYもマクロである。 maxが数であるときには、 それはminより小さくなく、かつ、7より大きくないこと。

interactive
この関数の対話指定であり、 Lisp関数においてinteractiveの引数に使う文字列である。 orの場合には0(空ポインタ)であり、 orは対話的に呼び出せないことを表す。 値""は、対話的に呼び出されると この関数は引数を受け取らないことを表す。

doc
説明文字列である。 各行末に`\n\'と書く必要があることを除けば、 Lispで定義する関数の説明文字列のように書く。 特に、最初の行は1つの文であること。

マクロDEFUNの呼び出しのあとには、 Cの関数に必須な引数名の並びを書き、引数に対する普通のCの宣言を続けます。 引数の最大個数が固定されている関数では、 各Lisp引数向けにCの引数宣言を書き、 それらをすべてLisp_Object型にします。 Lisp関数に引数の個数に上限がないとき、 それを実装するCの関数は実際には2つの引数を受け取ります。 第1引数はLisp引数の個数であり、 第2引数はそれらの値を収めたブロックのアドレスです。 引数の型はintLisp_Object *です。

関数For自身の内側では、 マクロGCPRO1UNGCPROを使っていることに注意してください。 GCPRO1は、ガベッジコレクションから変数を『保護』するために使います。 つまり、ガベッジコレクタに対してこの変数を調べてその内容を 参照可能なオブジェクトとみなすように指示します。 FevalFevalを直接/間接的に呼び出すものを呼ぶときには、 このようにする必要があります。 そのような場面では、再度参照する意図がある任意のLispオブジェクトは 保護する必要があります。 UNGCPROは、この関数での変数の保護を取り消します。 これは明示的に行う必要があります。

ほとんどのデータ型では、少なくともそのオブジェクトへの1つのポインタを 保護すれば十分であり、そのオブジェクトに循環がない限り、 そのオブジェクトへのすべてのポインタは正しく保たれます。 文字列にはこれはあてはまりません。 ガベッジコレクタがそれらを移動するからです。 ガベッジコレクタが文字列を移動すると、 それに対する既知のポインタをすべて再配置し、 それ以外のポインタは不正になります。 したがって、ガベッジコレクタが動く可能性のある任意の部分では、 文字列へのすべてのポインタを保護する必要があります。

マクロGCPRO1は1つのローカル変数のみを保護します。 2つ保護したい場合にはかわりにGCPRO2を使います。 GCPRO1を繰り返しても働きません。 GCPRO3GCPRO4のマクロもあります。

これらのマクロはgcpro1などのローカル変数を暗黙のうちに使いますが、 読者はこれらを型struct gcproで明示的に宣言する必要があります。 したがって、GCPRO2を使う場合には、 gcpro1gcpro2を宣言する必要があります。 残念ですが、ここではすべての詳細は説明しきれません。

Emacsをいったんダンプしたあとでも静的やグローバルな変数に書き込むのであれば、 それらの変数にはCの初期化構文を使ってはいけません。 初期化構文を伴うそれらの変数は、Emacsをダンプすると (オペレーティングシステムによっては)その結果として 読み出し専用のメモリ領域に割り当てられます。 See 節 B.2 ピュアメモリ

関数の内側では静的変数を使わずに、 すべての静的変数はファイルのトップレベルに置きます。 オペレーティングシステムによっては Emacsはキーワードstaticを空のマクロと定義することもあるので、 これは必要なことなのです。 (このような定義を使うのは、そのようなシステムは、 初期化構文があろうとなかろうと静的と宣言した変数を ダンプ後には読み出し専用にしてしまうからである。)

Cの関数を定義しただけではLisp基本関数としては使えません。 基本関数に対するLispシンボルを作成し、 その関数セルに適切なsubrオブジェクトを保存する必要があります。 そのコードはつぎのようになります。

 
defsubr (&subr-structure-name);

ここで、subr-structure-nameDEFUNの第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から見えるLisp_Object型のCの変数を作ります。 DEFVAR_INTは、Lispからはつねに整数を値として見える int型のCの変数を作ります。 DEFVAR_BOOLは、Lispからはtnilを値として見える int型のCの変数を作ります。

ファイルだけに有効な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,
  "xSpecify coordinate pair: \nXExpression which evals to window: ",
  "Return non-nil if COORDINATES is in WINDOW.\n\  
COORDINATES is a cons of the form (X . Y), X and Y being distances\n\
...
If they are on the border between WINDOW and its right sibling,\n\
   `vertical-line' is returned.")
  (coordinates, window)
     register Lisp_Object coordinates, window;
{
  int x, y;

  CHECK_LIVE_WINDOW (window, 0);
  CHECK_CONS (coordinates, 1);
  x = XINT (Fcar (coordinates));
  y = XINT (Fcdr (coordinates));

  switch (coordinates_in_window (XWINDOW (window), &x, &y))
    {
    case 0:                     /* NOT in window at all. */
      return Qnil;

    case 1:                     /* In text part of window. */
      return Fcons (make_number (x), make_number (y));

    case 2:                     /* In mode line of window. */
      return Qmode_line;

    case 3:                     /* On right border of window.  */
      return Qvertical_line;

    default:
      abort ();
    }
}

Cのコードでは、関数がCで定義されていない限り、 関数をその名前で呼び出せないことに注意してください。 Lispで書かれた関数を呼び出す方法は、Lispの関数funcallを 内蔵するFfuncallを使うことです。 Lisp関数funcallは任意個数の引数を受け付けるので、 Cでは2つの引数、Lispレベルの引数の個数と それらの値を収めた一次元の配列を受け取ります。 Lispレベルの最初の引数は呼び出すべきLisp関数であり、 残りはそれに渡す引数です。 Ffuncallはエバリュエータを呼び出すので、 Ffuncallを呼び出す周りでは、 ガベッジコレクションからポインタを保護する必要があります。

Cの関数、call0call1call2などは、 固定個数の引数を受け取るLisp関数を簡便に呼び出す手軽な方法です。 これらはFfuncallを呼び出して動作します。

`eval.c'は例を調べるにはとてもよいファイルです。 `lisp.h'には重要なマクロや関数の定義が入っています。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.6 オブジェクトの内部

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Object%20Internals"
"elisp/B.6オブジェクトの内部"へのコメント(無し)

GNU Emacs Lispは、さまざまな型のデータを扱います。 実際のデータはヒープに保存されていて、 プログラムはポインタを介してそれらを参照します。 ほとんどの実装では、ポインタは32ビット長です。 Emacsをコンパイルしたオペレーティングシステムやマシンの種類に依存しますが、 オブジェクトのアドレスには28ビットを使い、 残りのビットはガベッジコレクションの印や オブジェクトの型を表す識別子であるタグに使います。

Lispオブジェクトはタグ付ポインタとして表現しますから、 任意のオブジェクトのLispデータ型を判定することが可能です。 CのデータLisp_Objectは、任意のデータ型のLispオブジェクトを保持できます。 普通の変数はLisp_Object型ですから、 Lispの任意の値の任意の型を保持できます。 実際のデータ型は、実行中にのみ判定できます。 関数引数についても同じことがいえます。 特定の型の引数のみを受け付る関数が必要な場合には、 適切な述語(see 節 2.5 型述語) を使って型を明示的に検査する必要があります。

B.6.1 バッファの内部    Components of a buffer structure.
B.6.2 ウィンドウの内部    Components of a window structure.
B.6.3 プロセスの内部    Components of a process structure.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.6.1 バッファの内部

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Buffer%20Internals"
"elisp/B.6.1バッファの内部"へのコメント(無し)

バッファには、Lispプログラマが直接には参照できないフィールドがあります。 それらをCのコードで使っている名前で以下に述べます。 多くはLisp基本関数を介してLispプログラムから間接的に参照できます。

name
バッファ名はバッファを指名する文字列である。 これは一意であることが保証される。 see 節 26.3 バッファ名

save_modified
このフィールドは、バッファが最後に保存された時刻を整数で保持する。 see 節 26.5 バッファの変更

modtime
このフィールドは、訪問しているファイルの更新時刻を保持している。 これはファイルを読み書きしたときに設定される。 バッファをファイルに書き込むたびに、 このフィールドとファイルの更新時刻を比較する。 see 節 26.5 バッファの変更

auto_save_modified
このフィールドは、バッファを最後に自動保存した時刻を保持する。

last_window_start
このフィールドは、バッファをウィンドウに最後に表示したときの バッファのwindow-start(表示開始)位置を保持する。

undo_list
このフィールドは、バッファのアンドゥリストを保持する。 see 節 31.9 アンドゥ

syntax_table_v
このフィールドは、バッファの構文テーブルを保持する。 see 節 34. 構文テーブル

downcase_table
このフィールドは、テキストを小文字に変換するための変換表を保持する。 see 節 4.9 大文字小文字テーブル

upcase_table
このフィールドは、テキストを大文字に変換するための変換表を保持する。 see 節 4.9 大文字小文字テーブル

case_canon_table
このフィールドは、大文字小文字を区別しない探索のために テキストを正則にするための変換表を保持する。 see 節 4.9 大文字小文字テーブル

case_eqv_table
このフィールドは、大文字小文字を区別しない探索のための 同値テーブルを保持する。 see 節 4.9 大文字小文字テーブル

display_table
このフィールドは、バッファの表示テーブルを保持する。 表示テーブルがなければnilである。 see 節 38.14 表示テーブル

markers
このフィールドは、バッファを現在指しているすべてのマーカの連鎖を 保持している。 バッファからテキストを削除したり、バッファのギャップが移動すると、 これらのマーカのおのおのを検査し更新する必要がある。 see 節 30. マーカ

backed_up
このフィールドは、このバッファで訪問しているファイルの バックアップファイルを作成したかどうかを表すフラグである。

mark
このフィールドは、バッファのマークを保持する。 マークはマーカであり、そのためリストmarkersにも含まれている。 see 節 30.7 マーク

mark_active
バッファのマークが活性であれば、 このフィールドはnil以外である。

local_var_alist
このフィールドは、このバッファにバッファローカルな変数を記述した 連想リストを保持している。 バッファオブジェクトに特別な場所がある組み込みのバッファローカルな変数は 含まない。 (それらはこの一覧では省いた。) see 節 10.10 バッファローカルな変数

base_buffer
このフィールドは、(間接バッファであれば)バッファの基底バッファ、あるいは、 nilを保持する。

keymap
このフィールドは、バッファのローカルキーマップを保持する。 see 節 21. キーマップ

overlay_center
このフィールドは、現在のオーバレイの中央位置を保持する。 see 節 38.8 オーバレイ

overlays_before
このフィールドは、バッファの現在のオーバレイの中央位置か それよりまえで終るこのバッファのオーバレイのリストを保持している。 それらは終了位置が減る順に並んでいる。

overlays_after
このフィールドは、バッファの現在のオーバレイの中央位置より うしろで終るこのバッファのオーバレイのリストを保持している。 それらは開始位置が増える順に並んでいる。

enable_multibyte_characters
このフィールドは、enable-multibyte-charactersの バッファローカルな値を保持しており、 tnilである。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.6.2 ウィンドウの内部

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Window%20Internals"
"elisp/B.6.2ウィンドウの内部"へのコメント(無し)

ウィンドウには以下のような参照可能なフィールドがあります。

frame
このウィンドウがあるフレーム。

mini_p
このウィンドウがミニバッファ用ウィンドウであればnil以外。

buffer
このウィンドウで表示しているバッファ。 これはウィンドウの生存期間中にしばしば変化する。

dedicated
このウィンドウがそのバッファ専用であるとnil以外である。

pointm
これは、このウィンドウが選択されていたときの カレントバッファのポイント値である。 選択されていないときには、まえの値が保持される。

start
ウィンドウに表示する最初の文字のバッファ内位置である。

force_start
このフラグがnil以外であると、 Lispプログラムが明示的にウィンドウをスクロールしたことを表す。 ポイントがスクリーンからはみ出しているとつぎの再表示の動作に影響する。 ポイントの周りのテキストをウィンドウに表示するようにスクロールするかわりに、 スクリーン上に位置するようにポイントを移動する。

last_modified
このウィンドウの最後の再表示が完了した時点での ウィンドウのバッファのフィールドmodifiedである。

last_point
このウィンドウの最後の再表示が完了した時点での バッファのポイント値である。

left
コラム数で数えたウィンドウの左端である。 (スクリーンの最左端コラムは0コラム目。)

top
行数で数えたウィンドウの上端である。 (スクリーンの最上端行は0行目。)

height
行数で数えたウィンドウの高さ。

width
コラム数で数えたウィンドウの幅。

next
これは、兄弟関係でつぎのウィンドウである。 兄弟関係で最右端か最下端であるウィンドウではnilである。

prev
これは、兄弟関係でまえのウィンドウである。 兄弟関係で最左端か最上端であるウィンドウではnilである。

parent
内部的にはEmacsはウィンドウを木に並べている。 兄弟関係の各グループには親ウィンドウがあり、 親ウィンドウの領域はその兄弟すべての領域を含む。 このフィールドはウィンドウの親を指す。

親ウィンドウはバッファを表示せず、 その子ウィンドウの形以外には、表示に関してはなんの役割も持たない。 Emacs Lispプログラムでは親ウィンドウを参照せず、 バッファを実際に表示する木の葉にあるウィンドウを操作する。

hscroll
これは、ウィンドウの表示を水平方向左向きにスクロールしているコラム数。 これは普通は0である。

use_time
これは、このウィンドウが選択されていた最後の時刻。 関数get-lru-windowがこのフィールドを使う。

display_table
ウィンドウの表示テーブル。 指定されていなければnilである。

update_mode_line
nil以外であると、ウィンドウのモード行を更新する必要があることを表す。

base_line_number
バッファの特定の位置の行番号である。 あるいはnil。 これは、モード行にポイント位置の行番号を表示するために使われる。

base_line_pos
行番号が既知のバッファ内位置。 既知でなければnilである。

region_showing
このウィンドウでリージョン(やその一部)を強調表示しているときには、 このフィールドは、当該リージョンの一方の端を表すマーク位置を保持している。 さもなければこのフィールドはnilである。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

B.6.3 プロセスの内部

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Process%20Internals"
"elisp/B.6.3プロセスの内部"へのコメント(無し)

プロセスにはつぎのようなフィールドがあります。

name
プロセスの名前である文字列。

command
このプロセスを開始するために使用されたコマンド引数から成るリスト。

filter
バッファのかわりにプロセスからの出力を受け取るために使用する関数。 あるいはnil

sentinel
プロセスがシグナルを受け取るたびに呼ばれる関数。 あるいはnil

buffer
プロセスに対応付けられたバッファ。

pid
UNIXのプロセスIDである整数。

childp
フラグであり、これが実際に子プロセスであるとnil以外である。 ネットワーク接続であるとnil以外。

mark
プロセスからの最後の出力をバッファに挿入した箇所の末尾位置を表すマーカ。 これはしばしばバッファの末尾であるが、つねにではない。

kill_without_query
これがnil以外であると、このプロセスが動作中にEmacsを終了しようとしても プロセスをキルすることに関して確認を求めない。

raw_status_low
raw_status_high
これらの2つのフィールドは、 システムコールwaitで返されるプロセス状態の各16ビットを記録する。

status
process-statusが返すべきプロセス状態。

tick
update_tick
この2つのフィールドが等しくないと、 番兵を実行するかプロセスのバッファにメッセージを挿入するかして、 プロセスの状態変化を報告する必要がある。

pty_flag
サブプロセスとの通信にPTY(疑似端末)を 使用している場合にはnil以外であり、 パイプを使用している場合にはnilである。

infd
このプロセスからの入力用ファイル記述子。

outfd
このプロセスへの出力用ファイル記述子。

subtty
サブプロセスが使用している端末のファイル記述子。 (これを記録する必要のないシステムもあり、その場合には値はnilである。)

tty_name
サブプロセスが使用している端末の名前。 パイプを使用しているときにはnilである。

[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端] [?]