\section{評価}
\markright{\arabic{section}. 評価}

\subsection{評価関数}

エラーやシグナル(signal)に関する振る舞いを示すために、
あらかじめそれぞれ特別の変数{\bf *error-handler*}と{\bf *signal-handler*}
に適当な関数を設定する。
修正あるいは続行できるエラーはない。
エラーを解析後、現在の実行を{\bf reset}または上位レベルへの適当な{\bf throw}
によって停止しなければならない。
Euslispの最上位レベルで{\tt 0}と名付けられたcatch frameを作成しているので、
{\bf reset}は、{\tt (throw 0 NIL)}と同等である。

エラーハンドラーは、{\em code msg1 form \&optional (msg2)}
という3つあるいは4つの引き数を持つ関数として定義しなければならない。
{\em code}はエラーコードで、システムで定義されたエラーを示す。
例えば、14が'引き数が合わない'、13が'関数が定義されていない'となる。
これらの定義は、"c/eus.h"の中に定義されている。
{\em msg1}と{\em msg2}は、ユーザーに示されるメッセージである。
{\em form}は、エラーによって生じたs表現である。

シグナルハンドラーは、{\em sig}と{\em code}の2つの引き数を受ける関数として
定義されなければならない。
{\em sig}は、1から30までのシグナル番号である。
{\em code}は、シグナル番号の中に定義された補助番号である。

最上位レベルでの\verb+^+D({\em end-of-file})は、Euslispの活動を停止させる。
これは、Euslispをフィルターとしてプログラムされているとき
役に立つ。

{\bf eval-dynamic}は、letやlambda変数として使用されるsymbolに結び付く
動的な変数を捜す関数である。
デバッグするときに役に立つ。

\begin{refdesc}

\funcdesc{identity}{obj}{
{\em obj}自身を返す。
{\bf idnetity}と{\bf quote}との違いに注意すること。
{\bf identity}が関数であるのに対して{\bf quote}は、特殊書式(special form)
である。
したがって、{\tt (identity 'abc)}は{\tt abc}と評価されるが、
{\tt (quote 'abc) == (quote (quote abc))}は{\tt 'abc}と評価される。
{\bf identity}は、多くの一般列関数の{\em :key}パラメータのデフォルト値
としてしばしば用いられる。}

\funcdesc{eval}{form \&optional environment}{
{\em form}を評価して、その値を返す。
もし、{\bf *evalhook*}に{\em form}や{\em environment}を受ける関数を
設定するならば、hook関数を評価に入る前に呼び出すことができる。}

\funcdesc{apply}{func \&rest args}{
{\em args}に{\em func}を適用する。
{\em func}は、関数symbolかlambda書式かclosureでなければならない。
マクロと特殊書式(special form)は適用出来ない。
{\em args}の最後の要素は、他の{\em args}が空の引き数であるなら
引き数のリストでなければならない。
このように、もし、{\em args}の最後がNILであったならば、
{\bf apply}はほとんど{\bf funcall}と同じである。
ただし、{\bf apply}は{\bf funcall}より1つ多くの引き数を持つことができる。
{\tt (apply \#'max 2 5 3 '(8 2)) --> 8}.}

\funcdesc{funcall}{func \&rest args}{
{\em args}に{\em func}を適用する。
{\em args}の数は、{\em func}で要求されている引き数の数と一致しなければ
ならない。}

\specialdesc{quote}{obj}{
{\em obj}自身を評価する。}

\specialdesc{function}{func}{
closure関数を作る。
もし、{\em func}がsymbolならば、その関数定義が検索される。}

\funcdesc{evalhook}{hookfunc form \&optional env}{
{\em hookfun}を{\bf *evalhook*}に結び付けた後、{\em form}を一度評価する。}

\funcdesc{eval-dynamic}{variable}{
スタックにある{\em variable}(symbol)の値を捜す。}

\funcdesc{macroexpand}{form}{
もし、{\em form}がマクロcallであるなら、それを展開する。
もし、展開したものがまだマクロcallを含んでいるならば、
マクロcallのない結果となるまでくり返し展開する。}

\specialdesc{eval-when}{situation \&rest forms}{
{\em situation}は{\tt compile, load, eval}のリストである。
{\em form}は、現在の実行モードが{\em situation}と一致するときに評価される。
{\bf eval-when}は、コンパイラでの動作や環境を制御するために重要なものである。
もし、{\tt compile}が指定されたならば、{\em form}はコンパイラによって
評価されるので、その結果はコンパイル結果に影響を及ぼすことになる。
例えば、{\bf defmacro}はコンパイル時にマクロcallを展開するためにコンパイラで
評価されなければならない。
もし、{\tt load}が{\em situation}のリストに与えられたならば、
{\em form}はload時にloadまたは評価されるためにコンパイルされる。
すなわち、load時にコンパイルされた関数が定義される。
これは、コンパイラに期待される一般的な機能である。
{\tt load}は、コンパイラの環境を制御するために使用される。
もし、{\tt eval}が{\em situation}のリストに含まれているならば、
{\em form}はソースコードがloadされるときに評価される。}

\specialdesc{the}{type form}{
{\em form}を{\em type}として宣言する。
{\em type}は、{\tt :integer, :fixnum, :float}で示されるクラスオブジェクト
のどれかである。}

\specialdesc{declare}{\&rest declarations}{
それぞれ{\em declaration}は、宣言指定や整数あるいは目的のsymbolのリストである。
宣言は、コンパイラが高速なコードを生成するために重要である。
\begin{description}
\item {special} 特殊変数を宣言する。
\item {type} 変数の型を宣言する。; {\tt (type integer count)};
有効な型指定子は{\em integer}, {\em :integer}, {\em fixnum},
{\em :float}と{\em float}である。型指定子がここに示したものの１つである
ならば、{\bf type}キーワードを削除しても良い。そのため、
{\tt (integer count)}は正しい宣言である。
{\em float-vector},{\em integer-vector}などのような、その他の型（クラス）では、
{\tt (type float-vector vec1)}のように{\bf type}を前に付ける必要がある。
\item {ftype} 関数の結果の型を宣言する。
\item {optimize} コンパイラの*optimize*パラメータに値(0--3)を設定する。
\item {safety} コンパイラの*safety*パラメータに値(0--3)を設定する。
\item {space}  コンパイラの*space*パラメータに値(0--3)を設定する。
\item {inline} 認識しない。
\item {not-inline} 認識しない。
\end{description}}

\funcdesc{proclaim}{proclamation}{
変数やコンパイラオプションをグローバルに宣言する。
同様な宣言は、{\bf declare}特殊書式によって記述することができる。
しかしながら、{\bf proclaim}は、1つの引数を持つ関数であり、
宣言を評価する。}

\funcdesc{warn}{format-string \&rest args}{
{\em format-string}と{\em args}で与えられる警告メッセージを
{\bf *error-output*}に出力する。}

\funcdesc{error}{format-string \&rest args}{
{\bf *error-handler*}に結び付く現在のエラーハンドラー関数を呼び出す。
デフォルトのエラーハンドラー'euserror'を{\bf *error-output*}に最初に出力し
{\em format-string}と{\em args}を{\bf format}を用いて出力する。
その後、新しい最上位レベルのセッション(session)に入る。
プロンプトには、エラーセッションの深さを示す。
{\bf throw}にその番号を与えることにより、低いエラーレベルのセッションへ戻ることができる。}

\end{refdesc}

マルチスレッドEuslispにおいて、特殊変数はスレッド間で共有され、
同じ{\bf *error-handler*}が異なったスレッドから参照される。
この不自由を避けるために、マルチスレッドEuslispは{\bf install-error-handler}
関数を備えている。その関数は、それぞれのスレッドに対して
異なったエラーハンドラーをインストールする。

\begin{refdesc}

\funcdesc{lisp::install-error-handler}{handler}{
{\em handler}を現在のスレッドのエラーハンドラーとしてインストールする。}

\end{refdesc}

\newpage

\subsection{最上位レベルの対話}

EusLispの標準の最上位レベルの入力−評価−出力のループ(loop)は、{\bf eustop}
により制御されている。
% which is also responsible for the initial loading of files.
euslispが呼び出されたとき、
{\bf eustop}は、ホームディレクトリから{\tt ".eusrc"}というファイルを
あるいは{\tt EUSRC}環境変数で指定されたファイルをロードする。
それから、euslispは、引き数リストで指定されたファイルをロードする。
これらのロードが終了後、{\bf eustop}は、普通の対話セッション(session)に入る。

{\bf *standard-input*}にユーザーのTTYが接続されたとき、
{\bf eustop}は、{\bf *prompt-string*}（デフォルトとして{\tt "eus\$"}が
設定されている）に設定されたプロンプトを出力する。
そして、{\bf *terminal-io*}ストリームから命令を入力する。
もし、その入力がカッコで括られた行ならば、
{\bf eval}によってlisp書式として扱われる。
もし、入力行の最初のsymbolに関数定義があった場合、その行に自動的に
カッコが入れられ、評価される。
もし、関数定義が見つからなかった場合、その特殊値(special value)が
調査され、その値が出力される。
もし、そのsymbolになにも定義されてないならば、
その行はUNIX命令とみなされ、sh(Bourn's shell)へ渡される。
もし、shが一致するUNIX命令を捜せなかったとき、
"command unrecognized"というメッセージを出力する。
このように、{\bf eustop}はlispのインタープリタおよびUNIXのシェルとして動作する。
もし、入力をUNIX命令として実行したくないとき、
行の最初にコンマ','を付ければよい。
これは、対話実行(interpretive execution)でエラーが発生したとき、
動的な値を見るときに役に立つ。
Euslispはローカルなスコープ(lexical scope)を採用しているので
ローカル変数の値をspecialとして宣言されていない限りスコープの外から
調査することは出来ない。

入力は、それぞれ行番号とともに{\bf *history*}ベクトルに記憶される。
cshの上と同じ様に{\bf !}関数を入力することにより入力の詳細を
呼び出すことができる。
cshの履歴との違いは、{\bf !}が関数であるため{\bf !}の次に最低１つの
スペースが必要である。
また、コントロールキーを用いることによりemacsのように対話的に
行を編集することができる。

通常\verb+^+D (EOF)でEuslispは終了する。
上位レベル(普通はcsh)に異常終了コードを返すためには、適当な条件コードをつけた
{\bf exit}を使用すること。

{\bf eustop}は、SIGINTとSIGPIPEのためにシグナルハンドラーを設定する。
そして、他のシグナルはcatchしない。
このため、SIGTERMやSIGQUITのようなシグナルでEuslispを終了できる。
終了を避けたいとき、これらのシグナルをcatchするためには、
{\bf unix:signal}関数でユーザーで定義したシグナルハンドラーを設定すること。

\begin{refdesc}

%% Use functiondescription to avoid being added to the help function,
%% which would shadow basic operator functions

\functiondescription{-}{}{変数}{
現在の入力}

\functiondescription{+}{}{変数}{
直前の入力}

\functiondescription{++}{}{変数}{
２つ前の入力}

\functiondescription{+++}{}{変数}{
３つ前の入力}

\functiondescription{*}{}{変数}{
直前の結果}

\functiondescription{**}{}{変数}{
２つ前の結果}

\functiondescription{***}{}{変数}{
３つ前の結果}

\vardesc{*prompt-string*}{
{\bf eustop}で使用されるプロンプト文字列}

\vardesc{*program-name*}{
このEuslispが呼び出された命令。例えば、{\tt eus,eusx,eusxview}やユーザーで作った
euslispなど。}

\funcdesc{eustop}{\&rest argv}{
デフォルトの最上位ループ}

\funcdesc{eussig}{sig code}{
SIGPIPEのデフォルトシグナルハンドラー。
{\bf eussig}は、SIGPIPEが到着したり他の最上位レベルループに入るとき
シグナル番号を出力する。}

\funcdesc{sigint-handler}{sig code}{
SIGINT(control-C)のデフォルトシグナルハンドラー。
このシグナルで新しい最上位セッションへ入る。}

\funcdesc{euserror}{code message \&rest arg}{
デフォルトのエラーハンドラーで、
{\em message}を出力し、新しいエラーセッションへ入る。}

\funcdesc{reset}{}{
エラーループから脱出して、最後の{\bf eustop}セッションへ戻る。}

\funcdesc{exit}{\&optional termination-code}{
Euslispプロセスを終了し、プロセスの状態コードとして{\em termination-code}
(0..255)を返す。}

\vardesc{*top-selector*}{
複数のストリームによる非同時関数呼び出しを管理するport-selectorオブジェクト。}

\funcdesc{h}{}{
{\bf *history*}の中に記憶されている入力履歴を
関連する列番号とともに出力する。}

\funcdesc{!}{\&optional (seq 0)}{
列番号{\em seq}に関連する入力行を呼び出す。
{\em seq}が0のとき、もっとも最近の命令が呼び出される。
もし、{\em seq}が負の場合、現在行から相対的な位置にある行が
呼び出される。
呼び出された行が表示され、その行の最後にカーソルを移動する。
次のコントロールキーが使用出来る。
control-H (backspace)かcontrol-Bで１文字戻る。
control-Fかcontrol-Kで１文字進む。
control-Aで行の最初に移動する。
control-Lで行の最後に移動する。
control-Cで行の修正をキャンセルする。
control-M (carriage-return)かcontrol-J (line-feed)で
行修正を終了して、修正した行を評価する。
もし、{\em seq}が番号でなくsymbolまたは文字列の場合、
履歴リストを古い方に向かって検索し、
symbolまたは文字列が含まれている命令行を返す。}

\funcdesc{new-history}{depth}{
{\em depth}の長さを持つように{\bf *history*}を初期化する。
{\em depth}行が記憶される。
現在の{\bf *history*}に記録された入力行は、すべて消滅する。}

\end{refdesc}

\newpage


\subsection{コンパイル}\label{compiler}

Euslispコンパイラは、Lispプログラムの実行を高速化するために使用される。
実行時間の5〜30倍の高速化とマクロ展開によるガーベージコレクション
時間の大幅な減少が期待できる。

euscompは、計算処理とベクトル処理のための最適化を行う。
ときどきコンパイラが最適化を効率良く実行するために、固有の型宣言が必要となる。

{\bf compile-function}は、1つずつ関数をコンパイルする。
{\bf compile-file}は、すべてのソースファイルをコンパイルする。
{\bf compile-file}を実行している間、ファイル内のすべての書式が読み込まれ
評価される。
これは、現在のEuslispの環境を変化させる。
例えば、{\bf defparameter}はsymbolに新しい値を設定するし、
{\bf defun}はコンパイルされていない関数をコンパイルされた関数に
置き換える。
これらの予期しない影響を避けるためには、{\tt compile}指定のない{\bf eval-when}を
使用したり、{\bf euscomp}を使用して別プロセスとしてコンパイラを実行したりする。

{\bf euscomp}はUNIXのコマンドで、普通{\bf eus}にシンボリックリンクされている。
幾つかのオプションを持っている。
-OフラグはCコンパイラの最適化を指示し、
-O1,-O2, -O3 はそれぞれEuslispコンパイラの最適化のレベルを指示する。
これは、{\tt (optimize 1 or 2 or 3)}と宣言するのと同等である。
-S0, -S1, -S2, -S3は、{\bf compiler:*safety*}に0,1,2,3を設定する。
もし{\bf *safety*}が2より小さければ、割り込みチェックのためのコードを発行しない。
もし、プログラムが無限ループに入ったとき、制御を失うことになる。
もし{\bf *safety*}が0のときは、引き数の数をチェックしない。
-Vフラグは、コンパイルされている関数名を表示する。
-cフラグは、ccの実行やforkを防ぐ。
-Dは、{\bf *features*}リストに続く引き数を置く。
これは、読み込みマクロ{\tt \#-}と{\tt \#+}
を用いた条件付きコンパイルのために使用することができる。

コンパイラは"xxx.l"という名のEuslispソースプログラムを
中間Cプログラムファイル"xxx.c"
とヘッダーファイル"xxx.h"に変換する。
それから、Cコンパイラが実行され、"xxx.o"が生成される。
中間ファイル"xxx.c"と"xxx.h"はクロスコンパイルの目的のために残される。
したがって、違うアーキテクチャーの機械の上で使用したいとき、UNIX命令のccで
"xxx.c"ファイルをコンパイルするだけでよい。
コンパイルされたコードは、'{\tt (load "xxx")}'によってEuslispにロードされる。

中間ファイルはそれぞれ、"eus.h"ヘッダーファイルを参照する。
このファイルは、{\tt *eusdir*/c}ディレクトリに置かれていると仮定している。
{\tt *eusdir*}は、{\tt EUSDIR}環境変数からコピーされる。
もし設定されてなければ、{\tt /usr/local/eus/}がデフォルトディレクトリ
として扱われる。

コンパイルされたとき、中間のCプログラムは普通元のソースコードよりも
かなり大きくなる。例えば、1,161行のlispソースコード"l/common.l"は、
8,194行の"l/common.c"と544行の"l/common.h"に展開される。
1,000行のlispソースをコンパイルするのは、難しい作業ではないが、
10,000行近いCのプログラムを最適コンパイルすることは、長い時間(数分)かかる
とともに、たくさんのディスク空間を消費する。
そのため、もし相対的に大きなプログラムのコンパイルをするならば、
/var/tmpに十分なディスクがあるかどうかを確認すること。
そうでなければ、CCは死ぬだろう。
{\tt TMPDIR}環境変数をもっと大きなディスク部分に設定することが助かる道である。

リンクがロード時または実行時に実行されるので、
eusのカーネルがバージョンアップされても再コンパイルする必要はない。
もう一方で、実行時リンクは不便なことがある。
２つの関数AとBが"x.l"ファイルにありAがBを呼び出していると仮定する。
"x.l"をコンパイル後、"x.o"をロードし内部でBを呼び出しているAを呼び出そうとする。
それから、Bの中でbugを見つけると、たぶんBを再定義しようとするだろう。
ここで、コンパイルされたAとコンパイルされていないBとができる。
再びAを呼び出したとすると、Aはまだ古いコンパイルされているBを呼び出す。
これは、Aが最初にBを呼び出したとき固定的にリンクされるからである。
この問題を避けるためには、Aを再定義しなおすかあるいは"x.o"がロードされた直後で
Aを呼び出す前にBを再定義しなければならない。

コンパイルされたコードがロードされるとき、一般的にdefunやdefmethodの
列である最上位コードが実行される。
この最上位コードはロードモジュールのエントリ関数として定義されている。
コンパイラがそのエントリ関数の名前を付け、
ローダがこの関数の名前を正確にわからなければならない。
状況を簡単にするために、コンパイラとローダの両方とも
そのエントリ関数の名前としてオブジェクトファイルのbasenameと同一のもの
と仮定する。
例えば、もし"fib.l"をコンパイルしたならば、
コンパイラは"fib.c"のエントリ関数として"fib(...)"を生成する。
そして、ローダはオブジェクトファイル"fib.o"の中から"fib"を探す。
最終的にオブジェクトファイルはUnixの"cc"や"ld"で生成されるので、
このエントリ関数名は、C関数の命名ルールを満足しなければならない。
したがって、ファイル名としてCの予約キーワード（例えば、
"int", "struct", "union", "register", "extern"など）や"c/eus.h"に
定義されているプライベート指示語（例えば、"pointer", "cons",
"makeint"など）を避けなければならない。
もし、ソースファイルの名前としてこれらの予約語の内の１つを
使用しなければならないならば、コンパイラやローダの
{\em :entry}引数を別に指定すること。

closureの使用には制限がある。
closureの中の{\bf return-from}特殊書式と{\bf unwind-protect}の中のclean-up書式は
いつも正しくコンパイルされるわけではない。

{\bf disassemble}は、実現されていない。
コンパイルされたコードを解析するためには中間Cプログラムを見るかあるいは
{\bf adb}を使用する。

\begin{refdesc}

\functiondescription{euscomp}{\&rest filename}{UNIXコマンド}{
Euslispコンパイラを呼びだす。}

\longdescription{関数}{compile-file}{srcfile \&key \= (verbose nil) \hspace{43mm} \= \\
\> (optimize 2) (c-optimize 1) (safety 1) \> {\rm ; optimization level} \\
\> (pic t)  \> {\rm ; position independent code} \\
\> (cc t) \> {\rm ; run c compiler} \\
\> (entry (pathname-name file))}{
ファイルをコンパイルする。
".l"が{\em srcfile}の拡張子として仮定される。
もし、{\em :verbose}がTならば、コンパイルされた関数やメソッド名が表示される。
これは、エラーが発生した箇所を簡単に探すのに役立つ。
{\em :optimize, :c-optimize}と{\em :safety}は、最適化のレベルを
指定する。
モジュールが作成中にEuslispのコアにハードリンクされていないかぎり、
{\em :pic}は、Tに設定すべきである。}

\funcdesc{compile}{funcname}{
関数をコンパイルする。{\bf compile}は、最初に関数定義をテンポラリファイルに
出力する。そのファイルは、{\bf compile-file}によってコンパイルされ、
それから{\bf load}によってロードされる。
テンポラリファイルは削除される。}

\funcdesc{compile-file-if-src-newer}{srcfile \&key compiler-options}{
{\em srcfile}が対応するオブジェクトファイルよりも新しい（最近変更された）
ならば、コンパイルする。そのオブジェクトファイルは、".o"拡張子を
持っていると仮定される。}

\vardesc{compiler:*optimize*}{
コンパイラの最適化レベルを制御する。}

\vardesc{compiler:*verbose*}{
non-NILが設定されたとき、コンパイルされている関数名やメソッド名そして
コンパイルに要した時間を表示する。}

\vardesc{compiler:*safety*}{
安全性レベルを制御する。}

\end{refdesc}

\newpage

\subsection{プログラムロード}
\begin{refdesc}

\longdescription{関数}{load}{fname \&key \= (verbose *load-verbose*) \\
 \> (package *package*) \\
 \> (entry (pathname-name fname)) \\
 \> (symbol-input nil) \\
 \> (symbol-output "") \\
 \> (print nil) \\
 \> (ld-option "")}{
{\bf load}はソースファイルあるいはコンパイルされたオブジェクトファイル
をEuslispに読み込むための関数である。
もし、{\em fname}で指定されたファイルが存在するとき、
Euslispはロードする。
そのファイルがソースとバイナリーの内どちらかは、magic numberを見ることにより
自動的にチェックされる。
もし、そのファイルが存在しないが'.o'の型のファイルが存在する場合、
そのファイルをオブジェクトファイルとしてロードする。
%型が'.q'のファイルもまた、引用ベクトルファイルとして読み込まれる。
%(コンパイルの節を参照のこと)
その他、'.l'のファイルが見つかったならば、ソースプログラムとしてロードする。
もし、ファイル名の最初に"/"を付ける絶対パスを指定していない場合、
{\bf load}は、グローバル変数{\tt *load-path*}に指定されているディレクトリ
の中からファイルを検索する。
例えば、{\tt *load-path*}が{\tt ("/user/eus/" "/usr/lisp/")}であり、
{\em fname}として{\tt "llib/math"}が与えられたとき、
{\bf load}は{\tt "/user/eus/llib/math.o", 
"/usr/lisp/llib/math.o", "/user/eus/llib/math.l"},
{\tt "/usr/lisp/llib/math.l"}をこの順番に捜す。
適当なファイルが見つからなければ、エラーを返す。

{\it :entry}オプションは、ロードモジュールを初期化する入力アドレスを
指定する。
たとえば、{\tt :entry "\_myfunc"}オプションは{\tt \_myfunc}から実行を始める
ことを意味する。
デフォルト入力アドレスは、\ref{compiler}節に記述されているように
ロードされたファイル名のbasenameである。
ライブラリモジュール名は{\em :ld-option}オプション文字列の中に指定
することができる。
たとえば、suncoreライブラリを使用するモジュールをリンクするために、
{\em :ld-option}には {\tt "-lsuncore -lsunwindow -lpixrect -lm -lc"}
を与える必要がある。Solarisシステム以外では、
ライブラリがリンクされるとき{\bf ld}は2度実行される。
１度はサイズを決定するため、2度目は固有のメモリーに実際にリンクするため。

{\em :symbol-input}と{\em :symbol-output}オプションはあるオブジェクト
モジュールから他のモジュールへの参照を解決するため、あるいは
ライブラリーの2重ロードを避けるために使用される。
A,B２つのオブジェクトモジュールがあり,BがAの中で定義されているsymbolを
参照しているとする。
{\tt :symbol-output ="a.out"}を指定してモジュールAをロードする。
このリンクによって生成されたsymbol情報は、{\tt a.out}に書き込まれる。
モジュールBをロードするためには、BからAへの参照を解決する
{\tt :symbol-input = "a.out"}を指定しなければならない。}

\end{refdesc}
Solaris2 OSにおいて、コンパイルコードのロードは、動的ロードライブラリの中の
{\em dlopen}を呼び出すことにより実行している。
{\em dlopen}の使用は、共有オブジェクトに制限されている。
そのオブジェクトは、位置に依存するようにコンパイルされるために、
"-K pic"オプションを指定する。
また、{\em dlopen}は同じファイルを2度オープンすることができないので、
既にロードされているファイルに関しては、{\em dlclose}を最初に
実行する。
\begin{refdesc}

\funcdesc{load-files}{\&rest files}{
{\tt :verbose}にTを設定し、{\em files}を連続的にロードする。}

\vardesc{*modules*}{
これまでにロードされたモジュールの名前のリストを持つ。}

\funcdesc{provide}{module-name \&rest version-info}{
{\em module-name}と{\em version-info}のconsを、すでにロードされた
モジュールの名前として{\tt *modules*}の中に加える。
{\em module-name}はsymbolあるいは文字列でなければならない。
{\bf require}の呼び出しは、完全なモジュールを構成するファイルの最初に
存在しなければならない。}

\funcdesc{require}{module-name \&rest load-arg}{
{\tt *modules*}の中に{\em module-name}が見つからなかったとき、
{\em module-name}か{\em load-arg}の第一要素によって
示されているファイルをロードする。
{\bf provide}と{\bf require}は、モジュールの中の依存を制御し、
基本モジュールの2重ロードを避けるために使用される。
1つの基本モジュール"A"と2つの応用モジュール"B"と"C"があったとし、
"B"と"C"は互いに依存しないが"A"に依存しているとする。
それぞれのファイルの最初に{\bf provide}でモジュール名を宣言する。
"A"モジュールがどのモジュールにも依存していないなら、なにも{\bf require}
しなくてよい。
"B"や"C"の中の{\bf provide}呼び出しに続いて{\tt (require "A" "a.o")}が
実行される。
もし"B"をロードするとき、{\tt *modules*}の中に"A"が見つからなければ
"a.o"もロードし、{\tt *modules*}に"A"と"B"のモジュール名を追加する。
その後、もし"C"がロードされるなら、"A"モジュールはロードされず、"C"が
{\tt *modules*}に追加されるのみである。}

\longdescription{関数}{system:binload}{opath qpath \&optional \= (entry (pathname-name opath)) \\
\> (symfile "/usr/local/bin/eus")  \\
\> (symout "a.out") \\
\> (ldopt "")}{
バイナリファイルをロードしリンクする。}

\fundesc{system::txtload}{fname}

\end{refdesc}

\newpage

\subsection{デバッグ補助}

\begin{refdesc}

\funcdesc{describe}{obj \&optional (stream *standard-output*)}{
{\bf describe}はオブジェクトのslotごとの中身を表示する。}

\funcdesc{describe-list}{list \&optional (stream *standard-output*)}{
{\em list}内のそれぞれの要素に{\bf describe}を実行する。}

\macrodesc{inspect}{obj}{
{\bf inspect}は{\bf describe}の対話版である。
オブジェクトのそれぞれのslotを表示するためにサブ命令を受けたとき、
slotの中に深く入ったりあるいは新しい値をslotに設定したりする。
'?'命令でサブ命令のメニューを見ることができる。}

\funcdesc{more}{\&rest forms}{
{\bf *standard-output*}にテンポラリーファイルを結び付けて
{\em forms}を評価した後、そのテンポラリーファイルをUNIXの'more'命令
を使用して{\bf *standard-output*}に出力する。
{\bf more}は{\bf describe}のような関数によって発生した長い出力を
見るときに役に立つ。}

\funcdesc{break}{\&optional (prompt ":: ")}{
breakループに入る。
現在バインドされている環境が実施されている間、入力の前に","を付ける
ことによりローカル変数を見ることができる。
breakを終了したいとき、control-Dを入力する。}

\funcdesc{help}{topic}{
{\bf help}は、{\em topic}に関して短い説明を表示する。
{\em topic}は、ふつう関数symbolである。
文章はKCLのマニュアルから借りているため、説明がEuslisp関数のものといつも
合っているとは限らない。}

\funcdesc{apropos}{strng \&optional pack}{
{\bf apropos}は、関数や変数の正確な名前を忘れていて、その一部あるいは
不確かな名前しか知らないときに役に立つ。
symbol-nameの中に部分文字列として{\em strng}を含むすべてのsymbolを表示する。
{\em pack}が与えられた時、そのパッケージに属するシンボルのみ表示する。}

\funcdesc{apropos-list}{strng \&optional pack}{
{\bf apropos}と似ているが表示はしない、しかしリストとして結果を返す。}

\funcdesc{constants}{\&optional (string  "") (pkg *package*)}{
{\em pkg}の中に定数として定義され{\em string}と合うsymbolをすべてリスト
出力する。}

\funcdesc{variables}{\&optional (string  "") (pkg *package*)}{
{\em pkg}の中にグローバル値として割り当てられ{\em string}と合う
symbolをすべてリスト出力する。}

\funcdesc{functions}{\&optional (string  "") (pkg *package*)}{
{\em pkg}の中にグローバル関数として定義され{\em string}と合う
symbolをすべてリスト出力する。}

\funcdesc{btrace}{\&optional (depth 10)}{
{\em depth}レベルの履歴を呼び出し表示する。}

\fundesc{step-hook}{form env}

\funcdesc{step}{form}{
{\bf step}と{\bf trace}は関数の上でのみ正確に働く。マクロや特殊書式では
働かない。}

\funcdesc{trace}{\&rest functions}{
{\em functions}のトレースを始める。
{\em functions}が呼び出されたときはいつでも、その引き数と結果を表示する。}

\funcdesc{untrace}{\&rest functions}{
トレースを終了する。}

\macrodesc{timing}{count \&rest forms}{
{\em forms}を{\em count}回実行し、{\em forms}の1回の実行に要する
時間を計算する。}

\macrodesc{time}{function}{
{\em function}によって経過した時間を測定し始める。}

\funcdesc{sys:list-all-catchers}{}{
すべての{\bf catch}タグを返す。}

\funcdesc{sys:list-all-instances}{aclass \&optional scan-sub}{
すべてのヒープの中から{\em aclass}で指定されるインスタンスをすべて
探し、集める。
もし、{\em scan-sub}がNILなら、{\em aclass}の確実なインスタンスを
リストする。そうでなければ、{\em aclass}のインスタンスあるいはサブクラス
が集められる。}

\funcdesc{sys:list-all-bindings}{}{
バインドされるスタックを探し、
アクセス可能な値すべてをリストで返す。}

\funcdesc{sys:list-all-special-bindings}{}{
スタックを捜し、値をすべてリストアップする。}

\end{refdesc}

\newpage

\subsection{ダンプオブジェクト}
EusLispのリーダとプリンタは、どのようなオブジェクトも再読みだし可能な書式
でファイルに出力できるように設計されている。
オブジェクトは相互参照あるいは再帰参照を持っていてもよい。
{\tt *print-circle*}と{\tt *print-object*}にTを設定したとき、この特徴は
は可能となる。
次の関数はこれらの変数をTにし、ファイルをオープンし、オブジェクトを表示する。
これらの関数のもっとも重要な用途は、相互参照を持つ3Dモデルの
構造体をダンプすることである。

\begin{refdesc}

\fundesc{dump-object}{file \&rest objects}

\funcdesc{dump-structure}{file \&rest objects}{
再び読み戻しができるような書式で{\em file}に{\em objects}をダンプする。}

\funcdesc{dump-loadable-structure}{file \&rest symbols}{
{\em symbol}にバインドされたオブジェクトを{\em file}にダンプする。
その{\em file}は簡単にロードすることによって読み戻すことができる。}

\end{refdesc}

\begin{verbatim}
(setq a (make-cube 1 2 3))

;; sample for dump-object
(dump-object "a-cube.l" a)
(with-open-file
  (f "a-cube.l" :direction :input)
  (setq a (read f)))
(print a)

;; sample for dump-structure
(dump-structure "a-cube.l" a)
(with-open-file
  (f "a-cube.l" :direction :input)
  (setq a (read f)))
(print a)

;; sample for dump-loadable-structure
(dump-loadable-structure "a-cube.l" a)
(load "a-cube.l")
(print a)
\end{verbatim}

\subsection{プロセスイメージ保存}
このプロセスイメージ保存は、Solarisの動的ロード機能に深く依存しているため、
Solaris2のEuslispにおいてサポートされていない。
Solarisの動的ロード機能は、共有するオブジェクトを{\tt sbrk}点の上の
位置に依存した形でロードする。

\begin{refdesc}

\funcdesc{sys:save}{path \&optional (symbol-file "") starter}{
{\bf save}は、現在のEuslisp処理の環境をファイルにダンプする。
そのファイルは、後でUNIX命令として呼び出すことができる。
もし関数名が{\em starter}によって指定されているなら、
その関数はその命令の実行が始まるときに評価される。
それぞれの命令行の引き数はEuslispの中で強制的に文字列にされ、
引き数として{\em starter}に受け渡される。
それで、命令行を解析できる。
{\bf *standard-input*}と{\bf *standard-output*}を除くすべてのストリームを
確実にクローズしていなければならない。
ファイルがオープンされた状態を保存することはできない。
また、{\bf mmap}を試そうとしてはならない。
{\bf mmap}はインターネットのソケットストリームを作るとき、見えない所で実行されている。
Sunのネットワークライブラリはhost-by-nameのようなNIS情報をメモリ上に
いつも展開し、プロセスの最上位に置くため保存できない。
そのため、保存されたイメージが実行されるても、ネットワークライブラリへの
アクセスはどれも失敗し、コアダンプが生じる。
Xwindowもこのライブラリを使用している。
それで、一度Xserverに接続されたプロセスイメージを保存することはできない。}

\end{refdesc}

\subsection{最上位レベルのカスタマイズ}
EuslispがUNIXから呼び出されるとき、{\bf *toplevel*}にバインドされる
最上位関数によって実行が始められる。
この関数は、{\tt eus}の中の{\tt eustop}と{\tt eusx}の中の{\tt xtop}である。
{\bf save}の3番目の引き数に独自の関数を指定することによりこの最上位
関数を変更することができる。\index{save}

この最上位関数は、任意の数の引き数を受け取れるようにプログラムすべきである。
その命令行の上の引き数はそれぞれ、強制的に文字列にされ、最上位関数に渡される。
以下に示すプログラムは、最初の引き数に与えられたファイルからくり返し読み込み、
2番目の引き数のファイルに整形表示する。

\begin{verbatim}
(defun pprint-copy (infile outfile)
  (with-open-file (in infile)
     (with-open-file (out outfile :direction :output)
        (let ((eof (cons nil nil)) (exp))
           (while (not (eq (setq exp (read in nil eof)) eof))
              (pprint exp out))))))
(defun pprint-copy-top (&rest argv)
   (when (= (length argv) 2)
      (pprint-copy (first argv) (second argv))))
\end{verbatim}

一度これらの関数をEuslispの中に定義すれば、
{\tt (save "ppcopy" "" 'pprint-copy-top)}で{\tt ppcopy}という名のUNIXで実行
可能な命令を作る。

Solaris上のEuslispにおいて、{\bf save}がないので、
最上位評価関数はこの手法では変更できない。
代わりに、独自の最上位評価関数を定義するために{\tt lib/eusrt.l}を
修正し、{\bf *toplevel*}に設定することができる。
{\tt lib/eusrt.l}には、Euslispの起動時に評価される初期化手続きを
定義している。

\subsection{その他の関数}

\begin{refdesc}

\funcdesc{lisp-implementation-type}{}{
{\tt "EusLisp"}を返す。}

\funcdesc{lisp-implementation-version}{}{
このEuslispの名前、バージョン、作成日を返す。
この文字列が起動時にも表示される。
{\tt "MT-EusLisp 7.50 X 1.2 for Solaris Sat Jan  7 11:13:28 1995"}}

\end{refdesc}

\newpage
