nptのドキュメントです。
参照元:ANSI Common Lisp npt
前へ:脱出の操作
次へ:Paperオブジェクト
本章ではC言語にて、nptをどのようにして開始するかを説明します。
C言語ではmain関数から実行されますが、Windowsの場合はWinMain関数ですので、 両者でどのようにnptを初期化するのかを説明します。
nptを開始するには、まずは次の関数を実行します。
void lisp_init(void);この関数は、npt内のC言語で使用される静的変数を初期化し、 使用準備ができたことを宣言します。
対応する解放処理は下記の関数になります。
void lisp_free(void);初期化処理を実行したあとは、関数ポインタの登録を実行することができます。
関数ポインタの登録とは、例えば下記の関数を用いた処理のことです。
void lisp_compiled_rest(int index, lisp_calltype_rest call);関数ポインタの値は一度実行してしまえばlisp_freeで解放するまで持続します。
コマンド引数とは、main関数のargc, argv, envのことです。
読み込みに使用する関数は下記のとおりです。
struct lispargv *lispargv_main(int argc, char *argv[], char *env[]);エラー時にはNULLが返却されます。
動的にメモリが確保されますので、終了時には下記の解放処理が必要です。
void lispargv_free(struct lispargv *ptr);実行例を下記に示します。
int main(int argc, char *argv[], char *env[])
{
struct lispargv *args;
lisp_init();
args = lispargv_main(argc, argv, env);
if (args == NULL) {
fprintf(stderr, "argv error\n");
return 1;
}
/* ここにnptの処理を記載する */
/* free */
lispargv_free(args);
lisp_free();
return 0;
}lispargv_main関数は、Windows環境で実行するとargc, argv, envは全て無視され、 代わりに下記の関数を強制的に実行します。
struct lispargv *lispargv_windows(void);この関数はlispargv_mainと同等ですが、 引数と環境変数の情報をWIN32APIから取得します。
もしWinMain関数から起動する場合は、 argcのような引数は存在しないため、上記の関数を使用するしかないはずです。
しかしWindows環境でもmain関数を使用することはできます。
そのような場合でも、文字コードを正しく処理するために、 強制的にlispargv_windowsが使用されます。
もしlispargv_windowsではなく、 main関数の引数から実行したい場合は 下記の関数を使用してください。
struct lispargv *lispargv_main_force(int argc, char *argv[], char *env[]);この関数は、Windows環境であっても強制的に引数を読み込みます。
もし、argc, argv, envが存在しないか、 あるいは指定したくない場合は下記のように実行をして下さい。
args = lispargv_main_force(0, NULL, NULL);nptをC言語に組み込んで使用する場合には、 引数で変更されては困るものも存在します。
今回は次のように実行して、 standaloneモードでの実行を強制することにします。
args->mode_core = 0;
args->mode_degrade = 0;
args->mode_standalone = 1;
args->nocore = 1;
args->noinit = 1;
args->debugger = 1;
args->debuggerp = 0;
args->quit = 1;もしメモリの大きさを変更したい場合は次のようにします。
args->heap = 1024UL * 1024UL*1024UL; /* 1G */
args->local = 256UL * 1024UL*1024UL; /* 256M */heapは、heap領域の大きさです。
localは、stack領域の大きさです。
どちらもnptが実行される初期段階でmallocにより確保されます。
以上のことをまとめると、代表的なmain関数は下記のようになります。
int main(int argc, char *argv[], char *env[])
{
int result;
struct lispargv *args;
/* initialize */
lisp_init();
args = lispargv_main(argc, argv, env);
if (args == NULL) {
fprintf(stderr, "argv error\n");
return 1;
}
/* main_argv */
args->mode_core = 0;
args->mode_degrade = 0;
args->mode_standalone = 1;
args->nocore = 1;
args->noinit = 1;
args->debugger = 1;
args->debuggerp = 0;
args->quit = 1;
result = main_argv(args);
/* free */
lispargv_free(args);
lisp_free();
return result;
}以降はmain_argv関数を作成していきます。
もし引数に--helpなどが指定されていた場合は、 この段階で情報の表示を行い、実行を終了させます。
static int main_argv(struct lispargv *args)
{
if (args->mode_help)
return lisp_main_help(stdout);
if (args->mode_version)
return lisp_main_version(args, stdout);
if (args->mode_degrade)
return lisp_main_degrade(args);
/* 途中 */
return 0
}これで下記の引数に対応できました。
--help--version--version-script--degrademain_lispの実行次に行うことは、npt環境の整備です。
下記の命令にて実行します。
int lisp_argv_init(struct lispargv *ptr);
int lisp_argv_run(struct lispargv *ptr);lisp_argv_init関数で準備し、lisp_argv_runでLispを実行します。
これまでの例文のように、main_lisp関数を実行するには、 args->callを変更することで実現できます。
実行例を下記に示します。
int main_lisp(void *call_ptr)
{
return 0;
}
static int main_argv(struct lispargv *args)
{
/* mode */
if (args->mode_help)
return lisp_main_help(stdout);
if (args->mode_version)
return lisp_main_version(args, stdout);
if (args->mode_degrade)
return lisp_main_degrade(args);
/* execute */
args->call = main_lisp;
args->call_ptr = NULL;
lisp_argv_init(args);
lisp_argv_run(args);
return lisp_code? 1: lisp_result;
}本来であればlisp_argv_initとlisp_argv_runの 戻り値をチェックする必要があるのですが、 もしエラーが生じていた場合はlisp_codeの値が1になり、 さらにlisp_argv_run関数が必ず失敗するのでチェックは無視します。
args->callに登録したmain_lisp関数は、 args->call_ptrを引数として呼び出されます。
なぜ関数ポインタで登録する必要があるかというと、 Common Lispとして正しく動作するさせるためには 様々な設定をしてから実行する必要があるためです。
一例をあげるなら、warn関数で使用するhandler-bindの処理です。
main_lisp関数は脱出関数ですが、 普通の脱出関数とは少々違っており、 もし非脱出時に0以外の値が返却された場合は 異常終了とみなして後の処理を全て無視して、 終了コード1で終了します。
以上の内容をまとめますと、 最初にnptをC言語で使用するで説明した 例文そのものになります。
下記に例文を示します。
int main_lisp(void *call_ptr)
{
return lisp_format8_(NULL, "Hello~%", NULL);
}
static int main_argv(struct lispargv *args)
{
/* mode */
if (args->mode_help)
return lisp_main_help(stdout);
if (args->mode_version)
return lisp_main_version(args, stdout);
if (args->mode_degrade)
return lisp_main_degrade(args);
/* execute */
args->call = main_lisp;
args->call_ptr = NULL;
lisp_argv_init(args);
lisp_argv_run(args);
return lisp_code? 1: lisp_result;
}
int main(int argc, char *argv[], char *env[])
{
int result;
struct lispargv *args;
/* initialize */
lisp_init();
args = lispargv_main(argc, argv, env);
if (args == NULL) {
fprintf(stderr, "argv error\n");
return 1;
}
/* main_argv */
args->mode_core = 0;
args->mode_degrade = 0;
args->mode_standalone = 1;
args->nocore = 1;
args->noinit = 1;
args->debugger = 1;
args->debuggerp = 0;
args->quit = 1;
result = main_argv(args);
/* free */
lispargv_free(args);
lisp_free();
return result;
}実行結果は下記のとおりです。
Hello