/* # skkinput (Simple Kana-Kanji Input)
 * lispeval.c --- Evaluate lisp code
 * This file is part of skkinput.
 * Copyright (C) 1997
 * Takashi SAKAMOTO (sakamoto@yajima.kuis.kyoto-u.ac.jp)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with skkinput; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "commondef.h"
#include "lispeval.h"
#include "lispparse.h"
#if defined(MYEVAL_ONLY)
static char *skkinput_version = "myeval-test 1.00" ;
#else
#undef main_c
#include "version.h"
#endif

#undef DEBUG
/*
 * プロトタイプ宣言。
 */
static struct skkinputlisp_entity *stringIsString
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *stringIsAtom
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *stringIsInteger
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *stringIsVariable
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *stringIsArray
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *stringIsFunction
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop ) ;
static void free_entity( struct skkinputlisp_entity *entity ) ;
static struct skkinputlisp_entity *conslist2conspair
( struct conslist *node,
  struct skkinputlisp_variable *localVariableListTop ) ;
static void free_unreferred_entity
( struct skkinputlisp_entity *entity ) ;

static int isIntegerP( struct myChar *string ) ;
static int isStringP( struct myChar *string ) ;
static int isArrayP( struct myChar *string ) ;

static int isNilStringP( struct myChar *string ) ;

static struct skkinputlisp_entity *myevalLambdaForm
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;

struct skkinputlisp_entity *string2entity
( struct myChar *string, 
  struct skkinputlisp_variable *localVariableListTop ) ;

/*
 *
 */
static struct skkinputlisp_entity *skkinputlisp_quote
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_car
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_cdr
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_cons
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_set
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_setq
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_and
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_or
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_cond
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_if
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_concat
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_make_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_substring
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_current_time_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_j_date
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_skk_version
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_aref
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_aset
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_defun
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_lambda
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_multiply
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_plus
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_divide
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_minus
( struct conslist *top, 
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_string_to_int
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_int_to_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_progn
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;
static struct skkinputlisp_entity *skkinputlisp_load_file
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop ) ;

#if !defined(MYEVAL_ONLY)
extern int j_date_ad
( struct myChar *buffer, int bufsize, int date_ad, int number_style ) ;
extern unsigned char *expand_file_name( unsigned char *path ) ;
extern int check_skkinput_jisyo_code( unsigned char *path ) ;
#else
int j_date_ad
( struct myChar *buffer, int bufsize, int date_ad, int number_style ) ;
unsigned char *expand_file_name( unsigned char *path ) ;
int check_skkinput_jisyo_code( unsigned char *path ) ;
#endif

/* 実体をつないだリスト。*/
static struct skkinputlisp_entity *entityListTop = NULL ;
static struct skkinputlisp_variable *globalVariableListTop = NULL ;
static struct skkinputlisp_ufunction
*userDefinedFunctionListTop = NULL ;

static struct skkinputlisp_function skkinputlispFunctionTable[] = {
  { "quote",			skkinputlisp_quote },
  { "car",			skkinputlisp_car }, 
  { "cdr",			skkinputlisp_cdr }, 
  { "cons",			skkinputlisp_cons }, 
  { "set",			skkinputlisp_set }, 
  { "setq",			skkinputlisp_setq }, 
  { "and",			skkinputlisp_and }, 
  { "or",			skkinputlisp_or }, 
  { "cond",			skkinputlisp_cond },
  { "if",			skkinputlisp_if },
  { "concat",			skkinputlisp_concat },
  { "make-string",		skkinputlisp_make_string },
  { "substring",		skkinputlisp_substring },
  { "current-time-string",	skkinputlisp_current_time_string },
  { "j-date",			skkinputlisp_j_date },
  { "skk-version",		skkinputlisp_skk_version },
  { "aref",			skkinputlisp_aref },
  { "aset",			skkinputlisp_aset },
  { "defun",			skkinputlisp_defun },
  { "lambda",			skkinputlisp_lambda },
  { "*",			skkinputlisp_multiply },
  { "+",			skkinputlisp_plus },
  { "/",			skkinputlisp_divide },
  { "-",			skkinputlisp_minus },
  { "string-to-int",		skkinputlisp_string_to_int },
  { "int-to-string",		skkinputlisp_int_to_string },
  { "progn",			skkinputlisp_progn },
  { "load-file",		skkinputlisp_load_file },
  { NULL, 			NULL },
} ;

/*
 * 文字を数値に直す関数。
 */
static int char_to_number( struct myChar chara )
{
  if( !MYCHAR_IS_ALPHABETIC( chara ) )
    return ERR ;
  /* a から f の間に入る場合。*/
  if( chara.chara >= 'a' && chara.chara <= 'f' )
    return ( ( chara.chara - 'a' ) + 10 ) ;
  /* A から F の間に入る場合。*/
  if( chara.chara >= 'A' && chara.chara <= 'F' )
    return ( ( chara.chara - 'A' ) + 10 ) ;
  /* それ以外は数値。*/
  return ( chara.chara - '9' ) ;
}

/*------------------------------------------------------------------------
 * ここから先は skklisp の解釈を行う部分である。
 *-----------------------------------------------------------------------*/

/*
 * 実体を表示する関数。
 */
static void print_entity( struct skkinputlisp_entity *entity )
{
  int i, length ;
  struct skkinputlisp_entity **ptr ;
  if( entity == NULL )
    return ;
  switch( entity->type ){
  case ENTITY_ATOM :
    myCharFputstring( stdout, entity->data.string ) ;
    break ;
  case ENTITY_STRING :
    fputc( 0x22, stdout ) ;
    myCharFputstring( stdout, entity->data.string ) ;
    fputc( 0x22, stdout ) ;
    break ;
  case ENTITY_INTEGER :
    fprintf( stdout, "%d", entity->data.integer ) ;
    break ;
  case ENTITY_CONS :
    fprintf( stdout, "(" ) ;
    print_entity( entity->data.conspair.left ) ;
    fprintf( stdout, " . " ) ;
    print_entity( entity->data.conspair.right ) ;
    fprintf( stdout, ")" ) ;
    break ;
  case ENTITY_ARRAY :
    fprintf( stdout, "[" ) ;
    ptr = entity->data.array.array ;
    length = entity->data.array.length - 1 ;
    if( length >= 0 ){
      for( i = 0 ; i < length ; i ++, ptr ++ ){
	print_entity( *ptr ) ;
	fprintf( stdout, " " ) ;
      }
      print_entity( *ptr ) ;
    }
    fprintf( stdout, "]" ) ;
    break ;
  default :
    fprintf( stdout, "unknown entity.\n" ) ;
    break ;
  }
  return ;
}

/*
 * 実体を探すのに利用する関数。
 */
static struct skkinputlisp_entity *search_entity
( struct skkinputlisp_entity *entity )
{
  struct skkinputlisp_entity *node ;

  if( ( node = entityListTop ) == NULL )
    return NULL ;
  /* リストを線型探索する…(たこ) */
  for( ; node != NULL ; node = node->next ){
    /* 型が異なっていれば当然内容を比較するまでもない。*/
    if( node->type != entity->type )
      continue ;
    /* 型によって比較の方法が異なる。*/
    switch( entity->type ){
    case ENTITY_ATOM :
    case ENTITY_STRING :
      if( !myCharStrcmp( node->data.string, entity->data.string ) )
	return node ;
      break ;
    case ENTITY_INTEGER :
      if( node->data.integer == entity->data.integer )
	return node ;
      break ;
    case ENTITY_CONS :
      /* いきなりポインタとして比較しているけど…いいのかなあ？ */
      if( node->data.conspair.left == entity->data.conspair.left &&
	  node->data.conspair.right == entity->data.conspair.right )
	return node ;
      break ;
    default :
      break ;
    }
  }
  return NULL ;
}

/*
 * 新しい実体を作成するのに利用される関数。
 */
static struct skkinputlisp_entity *create_newEntity( void )
{
  struct skkinputlisp_entity *sklentity ;
  sklentity = malloc( sizeof( struct skkinputlisp_entity ) ) ;
  if( sklentity == NULL ){
    fprintf( stdout, "(skkinput) ** Fatal ** Memory fault.\n" ) ;
    exit( 1 ) ;
  }
  sklentity->type  = ENTITY_EMPTY ;
  sklentity->prev = sklentity->next = NULL ;
  sklentity->count = 0 ;
  return sklentity ;
}

static void link_newEntity( struct skkinputlisp_entity *entity )
{
  /* 一番先頭の前は NULL である。*/
  entity->prev = NULL ;
  /* 一番先頭の次はモト先頭だった人になる。*/
  entity->next = entityListTop ;
  /* もし、モト先頭だった人が実在していたのなら、その人の前の人になる。*/
  if( entityListTop != NULL ){
    entityListTop->prev = entity ;
  }
  /* 現在の先頭の人を覚える。*/
  entityListTop = entity ;
  return ;
}

/*
 * 実体が存在するか探し、存在しなければ実体を作成する関数。
 */
static struct skkinputlisp_entity *searchIfNotFindCreateStringEntity
( struct myChar *dstring )
{
  struct skkinputlisp_entity *node, *ret ;
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  node->type = ENTITY_STRING ;
  node->data.string = dstring ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    link_newEntity( node ) ;
    return node ;
  }
  /* 不要になった文字列を解放する。*/
  free( dstring ) ;
  /* 不要になったノードを解放する。*/
  free( node ) ;
  /* 値を返す。*/
  return ret ;
}

/*
 * 引数に与えられた文字列を解釈して entity に変換する関数。
 */
struct skkinputlisp_entity *stringIsString
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct myChar *dptr, *dstring ;
  int mode, num, tmpnum, len ;

  string ++ ;
  /* メモリの確保に失敗したら、NULL を返す。*/
  dstring = dptr = malloc
    ( sizeof( struct myChar ) * ( myCharStrlen( string ) + 1 ) ) ;
  if( dstring == NULL )
    return NULL ;

  num = len = 0 ;
  mode = SKKLISP_STRING_NORMAL ;
  /* 文字列のコピーを開始する。*/
  while( !IS_END_OF_STRING( *string ) && !IS_ASCII_EQUAL( *string, 0x22 ) ){ 
    switch( mode ){
    case SKKLISP_STRING_NORMAL :
      if( IS_ASCII_EQUAL( *string, '\\' ) ){ 
	mode = SKKLISP_STRING_BACKSLASH ;
	string ++ ;
	num = 0 ;
	continue ;
      }
      *dptr ++ = *string ++ ;
      len ++ ;
      break ;
    case SKKLISP_STRING_BACKSLASH :
      if( IS_ASCII_CHARA( *string ) ){
	if( string->chara == 'x' ){
	  mode = SKKLISP_STRING_HEX ;
	} else if( ( string->chara >= 'a' && string->chara <= 'f' ) ||
		   ( string->chara >= 'A' && string->chara <= 'F' ) ){
	  /* 続く文字がアルファベットの a から f の中にあれば。*/
	  mode = SKKLISP_STRING_HEX ;
	  num  = char_to_number( *string ) ;
	} else if( string->chara >= '0' && string->chara <= '7' ){
	  /* 続く文字が数字だった場合には 8 進数だと思って勘定する。*/
	  mode = SKKLISP_STRING_OCT ;
	  num  = string->chara - '0' ;
	} else {
	  /* それ以外の文字だった場合の処理。*/
	  switch( string->chara ){
	    /* 改行コードは残す。*/
	  case 'r' :
	  case 'n' :
	    MYCHAR_SET_CHARA( *dptr, '\n' ) ;
	    dptr ++ ;
	    len ++ ;
	    mode = SKKLISP_STRING_NORMAL ;
	    break ;
	    /* 面倒なのでタブはスペース一つに変換する。*/
	  case 't' :
	    MYCHAR_SET_CHARA( *dptr, ' ' ) ;
	    dptr ++ ;
	    len ++ ;
	    mode = SKKLISP_STRING_NORMAL ;
	    break ;
	  default :
	    *dptr ++ = *string ;
	    len ++ ;
	    mode = SKKLISP_STRING_NORMAL ;
	    break ;
	  }
	}
      } else {
	*dptr ++ = *string ;
	len ++ ;
	mode = SKKLISP_STRING_NORMAL ;
      }
      string ++ ;
      break ;
    case SKKLISP_STRING_HEX :
      tmpnum = char_to_number( *string ) ;
      if( tmpnum > 0 ){
	tmpnum += ( num << 4 ) ;
	/* 巨大になり過ぎないように注意する。*/
	if( tmpnum >= 0x80 ){
	  MYCHAR_SET_CHARA( *dptr, num ) ;
	  dptr ++ ;
	  len ++ ;
	  *dptr ++ = *string ;
	  len ++ ;
	  mode = SKKLISP_STRING_NORMAL ;
	} else {
	  num = tmpnum ;
	}
      } else {
	/* 数値でなくなったのなら停止する。*/
	MYCHAR_SET_CHARA( *dptr, num ) ;
	dptr ++ ;
	len ++ ;
	mode = SKKLISP_STRING_NORMAL ;
	continue ;
      }
      string ++ ;
      break ;
    case SKKLISP_STRING_OCT :
      if( IS_ASCII_CHARA( *string ) &&
	  string->chara >= '0' &&
	  string->chara <= '7' ){
	tmpnum = ( string->chara - '0' ) + num * 8 ;
	if( tmpnum >= 0x80 ){
	  /* 数値でなくなったのなら停止する。*/
	  MYCHAR_SET_CHARA( *dptr, num ) ;
	  dptr ++ ;
	  len ++ ;
	  *dptr ++ = *string ;
	  len ++ ;
	  mode = SKKLISP_STRING_NORMAL ;
	} else {
	  num = tmpnum ;
	}
      } else {
	/* 数値でなくなったのなら停止する。*/
	MYCHAR_SET_CHARA( *dptr, num ) ;
	dptr ++ ;
	len ++ ;
	mode = SKKLISP_STRING_NORMAL ;
	continue ;
      }
      string ++ ;
      break ;
    default :
      break ;
    }
  }
  if( mode == SKKLISP_STRING_OCT || mode == SKKLISP_STRING_HEX ){
    MYCHAR_SET_CHARA( *dptr, num ) ;
    dptr ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *dptr ) ;
  return searchIfNotFindCreateStringEntity( dstring ) ;
}

/*
 * nil を表わす実体を作成する。
 */
struct skkinputlisp_entity *nilEntity( void )
{
  struct skkinputlisp_entity *node, *ret ;
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  /* 名前が nil というアトムを作成する。*/
  node->type = ENTITY_ATOM ;
  node->data.string = malloc( sizeof( struct myChar ) * 4 ) ;
  myCharCharStrcpy( node->data.string, "nil" ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( node ) ;
    return node ;
  }
  /* 不要になった文字列を解放する。*/
  free( node->data.string ) ;
  /* 不要になったノードを解放する。*/
  free( node ) ;
  return ret ;
}

/*
 * t を表わす実体を作成する。
 */
static struct skkinputlisp_entity *tEntity( void )
{
  struct skkinputlisp_entity *node, *ret ;
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  /* 名前が nil というアトムを作成する。*/
  node->type = ENTITY_ATOM ;
  node->data.string = malloc( sizeof( struct myChar ) * 2 ) ;
  MYCHAR_SET_CHARA( node->data.string[ 0 ], 't' ) ;
  MYCHAR_SET_END_OF_STRING( node->data.string[ 1 ] ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( node ) ;
    return node ;
  }
  /* 不要になった文字列を解放する。*/
  free( node->data.string ) ;
  /* 不要になったノードを解放する。*/
  free( node ) ;
  return ret ;
}

/*
 * nil を表わす実体を作成する。
 */
struct skkinputlisp_entity *emptyStringEntity( void )
{
  struct skkinputlisp_entity *node, *ret ;
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  /* 名前が nil というアトムを作成する。*/
  node->type = ENTITY_STRING ;
  node->data.string = NULL ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( node ) ;
    return node ;
  }
  /* 不要になったノードを解放する。*/
  free( node ) ;
  return ret ;
}

/*
 * 引数が数値だと考えて作る場合…。
 */
static struct skkinputlisp_entity *stringIsInteger
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct myChar *sptr = string ;
  int value = 0, flag ;
  struct skkinputlisp_entity *node, *ret ;

  flag = 1 ;
  if( IS_ASCII_EQUAL( *sptr, '?' ) ){
    sptr ++ ;
    value = sptr->chara ;
  } else {
    flag = 1 ;
    if( IS_ASCII_EQUAL( *sptr, '+' ) ){
      sptr ++ ;
    } else if( IS_ASCII_EQUAL( *sptr, '-' ) ){
      sptr ++ ;
      flag = -1 ;
    }
    /* 文字列を調べる。*/
    while( !IS_END_OF_STRING( *sptr ) ){
      value = value * 10 + ( sptr->chara - '0' ) ;
      sptr ++ ;
    }
    value = value * flag ;
  }
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  /* 名前が nil というアトムを作成する。*/
  node->type = ENTITY_INTEGER ;
  node->data.integer = value ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( node ) ;
    return node ;
  }
  /* 不要になったノードを解放する。*/
  free( node ) ;
  return ret ;
}

static struct skkinputlisp_entity *stringIsAtom
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *node, *ret ;

  if( string == NULL )
    return NULL ;
  if( isStringP( string ) ){
    return stringIsString( string, localVariableListTop ) ;
  } else if( isIntegerP( string ) ){
    return stringIsInteger( string, localVariableListTop ) ;
  } else if( isNilStringP( string ) ){
    return nilEntity() ;
  } else if( IS_ASCII_EQUAL( string[ 0 ], 't' ) && 
	     IS_END_OF_STRING( string[ 1 ] ) ){
    return tEntity() ;
  } else if( isArrayP( string ) ){
    return stringIsArray
      ( string, localVariableListTop ) ;
  }
  /* まず仮の実体を作成する。*/
  if( ( node = create_newEntity() ) == NULL )
    return NULL ;
  node->type = ENTITY_ATOM ;
  node->data.string = malloc
    ( sizeof( struct myChar ) * ( myCharStrlen( string ) + 1 ) ) ;
  /* メモリが不足している？ */
  if( node->data.string == NULL ){
    free( node ) ;
    return NULL ;
  }
  /* アトムの名前をコピーする。*/
  myCharStrcpy( node->data.string, string ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( node ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( node ) ;
    return node ;
  }
  free( node->data.string ) ;
  /* 不要になったノードを解放する。*/
  free( node ) ;
  return ret ;
}

/*
 * 変数の検索を行う関数。
 */
static struct skkinputlisp_variable *search_localVariable
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_variable *node ;
  node = localVariableListTop ;
  while( node != NULL ){
    if( !myCharStrcmp( node->name, string ) )
      return node ;
    node = node->next ;
  }
  return NULL ;
}

static struct skkinputlisp_variable *search_globalVariable
( struct myChar *string )
{
  return search_localVariable( string, globalVariableListTop ) ;
}

static struct skkinputlisp_variable *create_newVariable( void )
{
  struct skkinputlisp_variable *node ;
  /* メモリの確保に失敗しますか？ */
  if( ( node = malloc( sizeof( struct skkinputlisp_variable ) ) ) == NULL ){
    return NULL ;
  }
  node->name  = NULL ;
  node->value = NULL ;
  /* 作成した時点でリストにつないでしまう…。*/
  node->next  = globalVariableListTop ;
  globalVariableListTop = node ;
  return node ;
}

static void increment_entity_count
( struct skkinputlisp_entity *entity )
{
  if( entity->type == ENTITY_CONS ){
    increment_entity_count( entity->data.conspair.left ) ;
    increment_entity_count( entity->data.conspair.right ) ;
  } else if( entity->type == ENTITY_ARRAY ){
    int i ;
    struct skkinputlisp_entity **node ;
    node = entity->data.array.array ;
    for( i = 0 ; i < entity->data.array.length ; i ++, node ++ ){
      increment_entity_count( *node ) ;
    }
  }
  entity->count ++ ;
  return ;
}

static int link_variable_to_entity
( struct skkinputlisp_variable *variable,
  struct skkinputlisp_entity *entity )
{
  if( variable->value != NULL ){
    /* 実体が参照されているという情報を減らす。*/
    free_entity( variable->value ) ;
  }
  variable->value = entity ;
  /* 参照されている数を一つ増やす。*/
  increment_entity_count( entity ) ;
  return True ;
}

static int isIntegerP( struct myChar *string )
{
  /* 先頭が数字だった場合には、もしや数値ではないかと疑う。*/
  if( !IS_ASCII_CHARA( *string ) )
    return False ;
  if( string->chara == '?' ) 
    return True ;
  if( string->chara == '+' || string->chara == '-' )
    string ++ ;
  if( IS_ASCII_CHARA( *string ) && 
      string->chara >= '0' && 
      string->chara <= '9' ){
    struct myChar *ptr = string ;
    /* ずっと数字じゃないと数値ではない。*/
    while( !IS_END_OF_STRING( *ptr ) ){
      if( !IS_ASCII_CHARA( *ptr ) || ptr->chara < '0' || ptr->chara > '9' )
	break ;
      ptr ++ ;
    }
    /* そうだよ、数値だよ。値は何だろう？ そうそう。浮動小数点は扱
       えないからね。*/
    if( IS_END_OF_STRING( *ptr ) )
      return True ;
  }
  return False ;
}

static int isStringP( struct myChar *string )
{
  if( IS_ASCII_EQUAL( *string, 0x22 ) )
    return True ;
  return False ;
}

static int isArrayP( struct myChar *string )
{
  if( IS_ASCII_EQUAL( *string, '[' ) ){
    return True ;
  }
  return False ;
}

static int isNilStringP( struct myChar *string )
{
  struct myChar *ptr ;
  if( !IS_ASCII_EQUAL( string[ 0 ], 'n' ) ||
      !IS_ASCII_EQUAL( string[ 1 ], 'i' ) ||
      !IS_ASCII_EQUAL( string[ 2 ], 'l' ) )
    return False ;
  ptr = string + 3 ;
  skip_space( &ptr ) ;
  if( IS_END_OF_STRING( *ptr ) )
    return True ;
  return False ;
}

/*
 * 配列の大きさを数えるよに利用する関数。
 */
static int countArraySizeFromConslist
( struct conslist *top )
{
  int number_of_items ;
  struct conslist *node ;
  /* 0 になるのはいきなり 0 だった時のみ。*/
  if( ( node = top ) == NULL )
    return 0 ;
  number_of_items = 1 ;
  /* 右に人がいる限り進む。*/
  while( node->right.value.next != NULL &&
	 node->right.type == TYPE_CONSLIST_ARRAY ){
    number_of_items ++ ;
    node = node->right.value.next ;
  }
  return number_of_items ;
}

static struct skkinputlisp_entity *conslist2array
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct conslist *node ;
  struct skkinputlisp_entity **eptr, *entity ;
  int number_of_items, count ;

  number_of_items = countArraySizeFromConslist( top ) ;
  if( ( entity = create_newEntity() ) == NULL ){
    return NULL ;
  }
  entity->type = ENTITY_ARRAY ;
  if( number_of_items <= 0 ){
    entity->data.array.length = 0 ;
    entity->data.array.array = NULL ;
    return entity ;
  } else {
    entity->data.array.length = number_of_items ;
    entity->data.array.array = 
      malloc( sizeof( struct skkinputlisp_entity *) * number_of_items ) ;
  }
  if( entity->data.array.array == NULL ){
    free_unreferred_entity( entity ) ;
    return NULL ;
  }
  eptr = entity->data.array.array ;
  count = 0 ;
  node = top ;
  while( node != NULL && number_of_items > count ){
#if 0
    if( node->right.type != TYPE_CONSLIST_ARRAY )
      break ;
#endif
    switch( node->left.type ){
    case TYPE_CONSLIST_ARRAY :
      *eptr = conslist2array
	( node->left.value.next, localVariableListTop ) ;
      if( *eptr == NULL )
	goto conslist2array_error ;
      increment_entity_count( *eptr ) ;
      break ;
    case TYPE_CONSLIST_CONSPAIR :
      if( node->left.value.next == NULL ){
	*eptr = nilEntity() ;
      } else {
	*eptr = conslist2conspair
	  ( node->left.value.next, localVariableListTop ) ;
      }
      if( *eptr == NULL )
	goto conslist2array_error ;
      increment_entity_count( *eptr ) ;
      break ;
    case TYPE_CONSLIST_STRING :
      *eptr = stringIsAtom
	( node->left.value.string, localVariableListTop ) ;
      if( *eptr == NULL )
	goto conslist2array_error ;
      increment_entity_count( *eptr ) ;
      break ;
    default :
#if defined(DEBUG)
      fprintf( stdout, "(conslist2array) unknown data type\n" ) ;
#endif
      break ;
    }
    eptr ++ ;
    count ++ ;
    node = node->right.value.next ;
  }
  return entity ;

conslist2array_error:
  eptr = entity->data.array.array ;
  while( count > 0 ){
    free_entity( *eptr ) ;
    eptr ++ ;
    count -- ;
  }
  return NULL ;
}

/*
 * 与えられた文字列が配列(ベクトル？)だと考えて、実体を探す関数。
 */
static struct skkinputlisp_entity *stringIsArray
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct conslist *top ;
  struct skkinputlisp_entity *entity ;

  if( !IS_ASCII_EQUAL( *string, '[' ) )
    string ++ ;
  if( ( top = string2conslist( &string ) ) == NULL )
    return NULL ;
#if defined(DEBUG)
  print_conslist( top ) ;
  fprintf( stdout, "\n" ) ;
#endif
  entity = conslist2array( top->left.value.next, localVariableListTop ) ;
  free_conslist( top ) ;
  return entity ;
}

/*
 * 与えられた文字列が変数名だと考えて、実体を探す関数。
 */
static struct skkinputlisp_entity *stringIsVariable
( struct myChar *string,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_variable *node ;

  /* t と nil は絶対に atom だった…しまったねえ。*/
  if( IS_ASCII_EQUAL( string[ 0 ], 't' ) &&
      IS_END_OF_STRING( string[ 1 ] ) ){
    return tEntity() ;
  } else if( isNilStringP( string ) ){
    return nilEntity() ;
  } else if( isIntegerP( string ) ){
    return stringIsInteger
      ( string, localVariableListTop ) ;
  } else if( isStringP( string ) ){
    return stringIsString
      ( string, localVariableListTop ) ;
  } else if( isArrayP( string ) ){
    return stringIsArray
      ( string, localVariableListTop ) ;
  }
  /* まず定義されている変数リストを探索する。*/
  node = search_localVariable( string, localVariableListTop ) ;
  if( node == NULL ){
    node = search_globalVariable( string ) ;
  }
  /* で、実際に定義されている変数でしたか？ */
  if( node == NULL ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Symbol's value as variable is void: " ) ;
    myCharFputString( stdout, string ) ;
    fprintf( stdout, "\n" ) ;
    fflush( stdout ) ;
#endif
    return NULL ;
  }
  /* スペシャルフォームである setq なんかがあった場合には void なん *
   * て言ってはいけないのだから…関数チェックのところが要注意である */
  return node->value ;
}


/*
 * 何の芸もないただ配列を線型探索するだけの関数。
 */
struct skkinputlisp_function *search_skkinputlispfunction
( struct myChar *name )
{
  struct skkinputlisp_function *node ;
  if( ( node = skkinputlispFunctionTable ) == NULL )
    return NULL ;
  while( node->name != NULL ){
    if( !myCharCharStrcmp( name, node->name ) )
      return node ;
    node ++ ;
  }
  return NULL ;
}

/*
 * ユーザ定義されている関数を探すのに利用される関数。
 */
static struct skkinputlisp_ufunction
*search_skkinputlispUserDefinedFunction( struct myChar *name )
{
  struct skkinputlisp_ufunction *node ;
  if( ( node = userDefinedFunctionListTop ) == NULL )
    return NULL ;
  while( node != NULL ){
    if( !myCharStrcmp( name, node->name ) )
      return node ;
    node = node->next ;
  }
  return NULL ;
}

static struct skkinputlisp_ufunction
 *create_newUserDefinedFunctionEntry( void )
{
  struct skkinputlisp_ufunction *node ;
  node = malloc( sizeof( struct skkinputlisp_ufunction ) ) ;
  if( node == NULL )
    return NULL ;
  return node ;
}

static void link_userDefinedFunctionEntry
( struct skkinputlisp_ufunction *node )
{
  node->next = userDefinedFunctionListTop ;
  userDefinedFunctionListTop = node ;
  return ;
}

/*
 * conslist を評価実行するのに利用される関数。
 */
struct skkinputlisp_entity *myevalConslist
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_function *node ;
  struct skkinputlisp_ufunction *unode ;

  /* conslist の car を調べる。conslist の car が関数名になるから。*/
  if( top == NULL ){
    /* () の場合には NULL になるので。*/
    return nilEntity() ;
  }
  if( top->left.type == TYPE_CONSLIST_CONSPAIR ){
    struct conslist *node = top->left.value.next ;
    /* lambda 式かどうか判定する。*/
    if( node->left.type != TYPE_CONSLIST_STRING ||
	node->left.value.string == NULL )
      return NULL ;
    if( myCharCharStrcmp( node->left.value.string, "lambda" ) )
      return NULL ;
    /* lambda 式だったけど…。*/
    return myevalLambdaForm( top, localVariableListTop ) ;
  } else if( top->left.type != TYPE_CONSLIST_STRING ){
    /* array だったりしたら処置なし。*/
    return NULL ;
  } else if( IS_END_OF_STRING( top->left.value.string[ 0 ] ) ){
    return nilEntity() ;
  }
  unode = search_skkinputlispUserDefinedFunction
    ( top->left.value.string ) ;
  if( unode != NULL ){
    free( top->left.value.string ) ;
    top->left.type = TYPE_CONSLIST_CONSPAIR ;
    /* コピーに失敗した場合には NULL を返す。*/
    top->left.value.next = copy_conspair( unode->function ) ;
    if( top->left.value.next == NULL )
      return NULL ;
    /* copy した分には、これを呼び出した側が conslist を解放することに
       なっている筈…。*/
    /* 再帰されるとはまらない？ 自分で自分を定義した関数とかは？ 
     * 再帰の深さをチェックする必要があるが…。*/
    return myevalConslist( top, localVariableListTop ) ;
  }
  node = search_skkinputlispfunction( top->left.value.string ) ;
  if( node == NULL ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Symbol's value as function is void: %s\n", 
	top->left.value.string ) ;
#endif
    return NULL ;
  }
  return ( node->func )( top, localVariableListTop ) ;
}


/*
 * 与えられた文字列が関数だと考えて、実体を求める関数。
 */
static struct skkinputlisp_entity *stringIsFunction
( struct myChar *string, 
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *top ;
#if defined(DEBUG)
  fprintf( stdout, "(string2conslist) %s\n", string ) ;
#endif
  if( !IS_ASCII_EQUAL( *string, 0x27 ) )
    string ++ ;
  top = string2conslist( &string ) ;
#if defined(DEBUG)
  print_conslist( top ) ;
  fprintf( stdout, "\n" ) ;
#endif
  entity = myevalConslist( top, localVariableListTop ) ;
  free_conslist( top ) ;
  return entity ;
}

static void free_local_entity( struct skkinputlisp_entity *entity )
{
  /* 相手によって処理が違う。*/
  switch( entity->type ){
  case ENTITY_ATOM :
  case ENTITY_STRING :
    if( entity->data.string != NULL )
      free( entity->data.string ) ;
    break ;
  case ENTITY_CONS :
    break ;
  case ENTITY_INTEGER :
  default :
    break ;
  }
  /* もし前の人がいたら、前の人に自分は抜けるから自分の次の人が君
     のすぐ後ろだよと教える。*/
  if( entity->prev != NULL ){
    entity->prev->next = entity->next ;
  } else {
    /* 前の人がいないということはボクは先頭だったのだから、先生に
       先頭の人がかわりますと伝える。*/
    entityListTop = entity->next ;
  }
  /* もし後ろに人がいたら、ボクは抜けるから今ボクの前の人が君の前
     の人になるのだよと教える。*/
  if( entity->next != NULL ){
    entity->next->prev = entity->prev ;
  }
  free( entity ) ;
  return ;
}

/*
 * 配列を解放する時に利用される関数。
 */
static void free_entity_array( struct skkinputlisp_entity *entity )
{
  struct skkinputlisp_entity **node ;
  int i ;
  node = entity->data.array.array ;
  for( i = 0 ; i < entity->data.array.length ; i ++, node ++ ){
    free_entity( *node ) ;
  }
  return ;
}

/*
 * 実体を解放する時に利用される関数。
 */
static void free_entity( struct skkinputlisp_entity *entity )
{
  if( entity == NULL )
    return ;
  if( entity->type == ENTITY_CONS ){
    free_entity( entity->data.conspair.left  ) ;
    free_entity( entity->data.conspair.right ) ;
  } else if( entity->type == ENTITY_ARRAY ){
    free_entity_array( entity ) ;
  }
  /* 自分を指しているカウンタを減らす。*/
  if( entity->count > 0 ){
    entity->count -- ;
  }
  if( entity->count <= 0 ){
    free_local_entity( entity ) ;
  }
  return ;
}

static void free_unreferred_entity
( struct skkinputlisp_entity *entity )
{
  if( entity == NULL )
    return ;
  if( entity->count > 0 )
    return ;
  if( entity->type == ENTITY_CONS ){
    /* 明らかに自分自身が消去される時にしか子供を減らさない。*/
    free_entity( entity->data.conspair.left  ) ;
    free_entity( entity->data.conspair.right ) ;
  } else if( entity->type == ENTITY_ARRAY ){
    free_entity_array( entity ) ;
  }
  free_local_entity( entity ) ;
}

/*
 * 文字列を実体に直すのに利用される関数。
 */
struct skkinputlisp_entity *string2entity
( struct myChar *string, 
  struct skkinputlisp_variable *localVariableListTop )
{
  /* NULL だったら、評価のしようがない。*/
  if( string == NULL )
    return NULL ;
  /* 文字列の先頭にある空白文字をスキップする。*/
  skip_space( &string ) ;
#if defined(DEBUG)
  fprintf( stdout, "(string2entity) " ) ;
  myCharFputstring( string ) ;
  fputc( '\n', fp ) ;
  fflush( stdout ) ;
#endif
  if( IS_ASCII_EQUAL( *string, '(' ) ||
      IS_ASCII_EQUAL( *string, 0x27  ) ){
    /* この場合には関数である。評価しないといけない。*/
    return stringIsFunction( string, localVariableListTop ) ;
  }
#if 0
  /* 先頭が数字だった場合には、もしや数値ではないかと疑う。*/
  if( isIntegerP( string ) ){
    return stringIsInteger( string, localVariableListTop ) ;
    /* もしかすると、文字列じゃないかい？ */
  } else if( isStringP( string ) ){
    /* そうだよ、文字列だよ。*/
    return stringIsString( string, localVariableListTop ) ;
  }
#endif
  /* この場合には変数である。変数として評価しなければならない。*/
  return stringIsVariable( string, localVariableListTop ) ;
}

/*
 * ゴミ収集をしてくれる関数。無茶苦茶重いぞ…これは…。手を抜き過ぎた
 * かも。
 */
void skkinputlisp_garbagecollector( void )
{
  struct skkinputlisp_entity *node, *nextNode ;
  int type ;

  node = entityListTop ;
  while( node != NULL ){
    if( node->count <= 0 ){
      type = node->type ;
      nextNode = node->next ;
      free_entity( node ) ;
      /* うげ。もしかすると次の人はいなくなっている可能性があって、前
	 の人もいなくなっている可能性があって、しかも自分もいなくなっ
	 ているとわ…。*/
      if( type == ENTITY_CONS ){
	node = entityListTop ;
      } else {
	node = nextNode ;
      }
    } else {
      node = node->next ;
    }
  }
  return ;
}

static int isNilEntity( struct skkinputlisp_entity *node )
{
  if( node->type == ENTITY_ATOM &&
      !myCharCharStrcmp( node->data.string, "nil" ) )
    return True ;
  return False ;
}

static int isEntityListp( struct skkinputlisp_entity *entity )
{
  if( entity->type == ENTITY_CONS )
    return True ;
  if( isNilEntity( entity ) )
    return True ;
  return False ;
}

/*
 * conslist を眺めてリストかどうかを判断する関数。
 * "Wrong type argument: listp, hogehoge" の判定に用いる。
 */
static int isConslistNodeListP
( struct consnode *node )
{
  if( node->type == TYPE_CONSLIST_CONSPAIR )
    return True ;
  /* nil は通す。*/
  if( node->value.string == NULL )
    return True ;
  if( !myCharCharStrcmp( node->value.string, "nil" ) ||
      IS_END_OF_STRING( node->value.string[ 0 ] ) )
    return True ;
  return False ;
}

#if 0
static int isConslistNodeSequenceP
( struct consnode *node )
{
  if( node->type == TYPE_CONSLIST_CONSPAIR ||
      node->type == TYPE_CONSLIST_ARRAY )
    return True ;
  /* nil は通す。*/
  if( node->value.string == NULL )
    return True ;
  if( !strcmp( node->value.string, "nil" ) ||
      node->value.string[ 0 ] == '\0' )
    return True ;
  return False ;
}
#endif

/*
 *
 */
static struct skkinputlisp_entity *conslist2conspair
( struct conslist *node,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *ret ;

  if( ( entity = create_newEntity() ) == NULL )
    return NULL ;
  entity->type = ENTITY_CONS ;
  entity->data.conspair.left = entity->data.conspair.right = NULL ;
  /* まず左手から。*/
  if( node->left.type == TYPE_CONSLIST_STRING ){
    entity->data.conspair.left =
      stringIsAtom( node->left.value.string, localVariableListTop ) ;
  } else {
    if( node->left.value.next != NULL ){
      entity->data.conspair.left =
	conslist2conspair( node->left.value.next, localVariableListTop ) ;
    } else {
      entity->data.conspair.left = nilEntity() ;
    }
  }
  /* 確保失敗。*/
  if( entity->data.conspair.left == NULL ){
    free_entity( entity ) ;
    return NULL ;
  }
  /* cons の場合は指されていることが明確にならないといけない？ */
  increment_entity_count( entity->data.conspair.left ) ;
  if( node->right.type == TYPE_CONSLIST_STRING ){
    entity->data.conspair.right =
      stringIsAtom( node->right.value.string, localVariableListTop ) ;
  } else {
    if( node->right.value.next != NULL ){
      entity->data.conspair.right =
	conslist2conspair( node->right.value.next, localVariableListTop ) ;
    } else {
      entity->data.conspair.right = nilEntity() ;
    }
  }
  /* 確保失敗。*/
  if( entity->data.conspair.right == NULL ){
    free_entity( entity ) ;
    return NULL ;
  }
  /* cons の場合は指されていることが明確にならないといけない？ */
  increment_entity_count( entity->data.conspair.right ) ;

  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( ret = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
    return entity ;
  }
  /* 不要になったノードを解放する。リンクがあるから、それを削るのを忘
     れない。*/
  free_entity( entity ) ;
  /* 見付かったやつはきちんと指されるようにしないといけない。*/
  increment_entity_count( ret ) ;
  return ret ;
}

/*
 * () の car を eval する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_eval_car
( struct conslist *node,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity ;

  if( node == NULL )
    return nilEntity() ;

  if( node->left.type == TYPE_CONSLIST_STRING ){
    entity = stringIsVariable
      ( node->left.value.string, localVariableListTop ) ;
  } else if( node->left.type == TYPE_CONSLIST_ARRAY ){
    entity = conslist2array
      ( node->left.value.next, localVariableListTop ) ;
  } else {
    /* cdr の car を選んでは順に eval する。*/
    entity = myevalConslist
      ( node->left.value.next, localVariableListTop ) ;
  }
  return entity ;
}

/*
 * (cdr node) が sequence かどうかを判定する関数。
 *----
 * sequence であるというのは、リストであるか配列であるかのいずれかの条
 * 件を満足する時である。 
 */
static int skkinputlisp_sequencepCheck
( struct conslist *node )
{
  if( !isConslistNodeListP( &node->right ) && 
      node->right.type != TYPE_CONSLIST_ARRAY ){
#if defined(DEBUG)
    fprintf
      ( stdout,
	"Wrong type argument: sequencep, %s\n",
	node->right.value.string ) ;
#endif      
    return False ;
  }
  return True ;
}

/*
 * (cdr node) が list かどうかを判定する関数。
 *----
 * list であるというのは、conspair であるか nil であるかのいずれかの条
 * 件を満足する時である。
 */
static int skkinputlisp_listpCheck
( struct conslist *node )
{
  if( !isConslistNodeListP( &node->right ) ){
#if defined(DEBUG)
    fprintf
      ( stdout,
	"Wrong type argument: listp, %s\n",
	node->right.value.string ) ;
#endif      
    return False ;
  }
  return True ;
}

static struct skkinputlisp_entity *skkinputlisp_evalCarAndCheckType
( struct conslist *node, 
  struct skkinputlisp_variable *localVariableListTop,
  int type )
{
  struct skkinputlisp_entity *entity ;
#if defined(DEBUG)
  const char *err_msgs[] = {
    "atomp", "stringp", "integerp", "listp", "arrayp", "listp", 
  } ;
#endif
  /* 引数を評価していく。*/
  if( ( entity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    return NULL ;
  }
  switch( type ){
  case ENTITY_LIST :
    if( entity->type != ENTITY_CONS && !isNilEntity( entity ) )
      goto type_error ;
    break ;
  default :
    /* 型のチェック。*/
    if( entity->type != type )
      goto type_error ;
    break ;
  }
  return entity ;

type_error:
#if defined(DEBUG)
  if( type >= 0 )
    fprintf
      ( stdout, "Wrong type argument: %s, ", err_msgs[ type ] ) ;
  print_entity( entity ) ;
  fprintf( stdout, "\n" ) ;
#endif    
  free_unreferred_entity( entity ) ;
  return NULL ;
}

/*
 * conslist の形で式が与えられた時に引数の数を数える関数。
 */
static int count_argument_number( struct conslist *node )
{
  int i = 0 ;
  while( node != NULL ){
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ){
      if( node->right.value.string == NULL ||
	  IS_END_OF_STRING( node->right.value.string[ 0 ] ) )
	break ;
    }
    i ++ ;
    node = node->right.value.next ;
  }
  return i ;
}

/*
 * ユーザ定義された関数を登録するのに利用される関数。
 *----
 * しかし、ローカルな関数定義ってあるのだろうか？ これだと大域に変化し
 * てしまうのだが…。
 */
static int skkinputlisp_registerUserDefinedFunction
( struct myChar *name, struct conslist *top )
{
  struct skkinputlisp_ufunction *fnode ;
  fnode = search_skkinputlispUserDefinedFunction( name ) ;
  if( fnode == NULL ){
    /* 新規の登録の場合。*/
    if( ( fnode = create_newUserDefinedFunctionEntry() ) == NULL )
      return False ;
    /* 名前を覚えておく。*/
    fnode->name = malloc
      ( sizeof( struct myChar ) * ( myCharStrlen( name ) + 1 ) ) ;
    if( fnode->name == NULL ){
      free( fnode ) ;
      return False ;
    }
    myCharStrcpy( fnode->name, name ) ;
    link_userDefinedFunctionEntry( fnode ) ;
  } else {
    /* そうじゃなくて、既にあるものを上書きする場合。*/
    free_conslist( fnode->function ) ;
  }
  fnode->function = top ;
  return True ;
}

/*
 * マクロであるところの quote を特別に実行する関数。
 *---
 * defmacro が無いので、こういうことをしている。defmacro を実装する日
 * は来るのか？ 
 */
static struct skkinputlisp_entity *skkinputlisp_quote
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity ;
  struct conslist *node ;

  if( top->right.type != TYPE_CONSLIST_CONSPAIR ||
      top->right.value.next == NULL ){
#if defined(DEBUG)
    fprintf( stdout, "Wrong number of arguments: #<subr quote>, 0\n" ) ;
#endif
    return NULL ;
  }
  node = ( top->right.value.next ) ;
  if( node->left.type == TYPE_CONSLIST_CONSPAIR ){
    if( node->left.value.next == NULL ){
      entity = nilEntity() ;
    } else {
      entity = conslist2conspair
	( node->left.value.next, localVariableListTop ) ;
    }
  } else if( node->left.type == TYPE_CONSLIST_ARRAY ){
    entity = conslist2array
      ( node->left.value.next, localVariableListTop ) ;
  } else {
    /* atom を作成する。*/
    entity = stringIsAtom
      ( node->left.value.string, localVariableListTop ) ;
  }
  return entity ;
}

/*
 * (car) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_car
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node ;

  if( top->right.type != TYPE_CONSLIST_CONSPAIR ||
      top->right.value.next == NULL ){
#if defined(DEBUG)
    fprintf( stdout, "Wrong number of arguments: #<subr car>, 0\n" ) ;
#endif
    return NULL ;
  }
  node = top->right.value.next ;
  while( node != NULL ){
    entity = skkinputlisp_eval_car
      ( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    if( !isEntityListp( entity ) ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: listp, " ) ;
      print_entity( entity ) ;
      fprintf( stdout, "\n" ) ;
#endif
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    node = node->right.value.next ;
    if( node != NULL ){
#if defined(DEBUG)
      fprintf( stdout, "Wrong number of arguments: #<subr car>, 2\n" ) ;
#endif
      free_unreferred_entity( entity ) ;
      return NULL ;
    } else {
      break ;
    }
  }
  /*
   * 引数が nil であった場合のために、cons かどうかを判定している。
   */
  return ( ( entity->type != ENTITY_CONS )? entity : 
    ( entity->data.conspair.left ) ) ;
}

/*
 * (cdr) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_cdr
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node ;

  if( top->right.type != TYPE_CONSLIST_CONSPAIR ||
      top->right.value.next == NULL ){
#if defined(DEBUG)
    fprintf( stdout, "Wrong number of arguments: #<subr cdr>, 0\n" ) ;
#endif
    return NULL ;
  }
  node = top->right.value.next ;
  while( node != NULL ){
    entity = skkinputlisp_eval_car
      ( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    if( !isEntityListp( entity ) ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: listp, " ) ;
      print_entity( entity ) ;
      fprintf( stdout, "\n" ) ;
#endif
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    node = node->right.value.next ;
    if( node != NULL ){
#if defined(DEBUG)
      fprintf( stdout, "Wrong number of arguments: #<subr cdr>, 2\n" ) ;
#endif
      free_unreferred_entity( entity ) ;
      return NULL ;
    } else {
      break ;
    }
  }
  /*
   * 引数が nil であった場合のために、cons かどうかを判定している。
   */
  return ( ( entity->type != ENTITY_CONS )? entity : 
	   ( entity->data.conspair.right ) ) ;
}

/*
 * (cons) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_cons
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *lEntity, *rEntity, *tmpEntity ;
  struct conslist *node ;
  int i ;

  node = top ;
  i = 0 ;
  while( node != NULL ){
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ||
	node->right.value.next == NULL )
      break ;
    i ++ ;
    node = node->right.value.next ;
  }
  if( i != 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Wrong number of arguments: #<subr cons>, %d\n", i ) ;
#endif
    return NULL ;
  }
  node = top->right.value.next ;
  lEntity = skkinputlisp_eval_car
    ( node, localVariableListTop ) ;
  node = node->right.value.next ;
  rEntity = skkinputlisp_eval_car
    ( node, localVariableListTop ) ;
  if( lEntity == NULL || rEntity == NULL ){
    goto skkinputlisp_cons_error ;
  }
  if( ( entity = create_newEntity() ) == NULL ){
    goto skkinputlisp_cons_error ;
  }
  entity->type = ENTITY_CONS ;
  entity->data.conspair.left  = lEntity ;
  increment_entity_count( lEntity ) ;
  entity->data.conspair.right = rEntity ;
  increment_entity_count( rEntity ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;

skkinputlisp_cons_error:
  free_unreferred_entity( lEntity ) ;
  free_unreferred_entity( rEntity ) ;
  return NULL ;
}

/*
 * (set) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_set
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity ;
  struct skkinputlisp_variable *varnode ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  /* 引数の数をチェックする。*/
  argc = count_argument_number( top->right.value.next ) ;
  if( argc != 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Wrong number of arguments: #<subr set>, %d\n", argc ) ;
#endif    
    return NULL ;
  }
  node = top->right.value.next ;
  entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
  if( entity == NULL )
    return NULL ;
  if( entity->type != ENTITY_ATOM ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Wrong type argument: symbolp, " ) ;
    print_entity( entity ) ;
    fprintf
      ( stdout, "\n" ) ;
#endif
    free_unreferred_entity( entity ) ;
    return NULL ;
  }
  /* まず定義されている変数リストを探索する。*/
  varnode = search_localVariable
    ( entity->data.string, localVariableListTop ) ;
  if( varnode == NULL ){
    varnode = search_globalVariable( entity->data.string ) ;
  }
  if( varnode == NULL ){
    if( ( varnode = create_newVariable() ) == NULL )
      return NULL ;
    varnode->name = malloc
      ( sizeof( struct myChar ) *
	( myCharStrlen( entity->data.string ) + 1 ) ) ;
    if( varnode->name == NULL ){
      free( varnode ) ;
      return NULL ;
    }
    myCharStrcpy( varnode->name, entity->data.string ) ;
  }
  free_unreferred_entity( entity ) ;
  node = node->right.value.next ;
  entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
  if( entity == NULL )
    return NULL ;
  link_variable_to_entity( varnode, entity ) ;
  return entity ;
}

/*
 * (setq) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_setq
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct skkinputlisp_variable *varnode ;
  struct conslist *node ;

  if( top->right.type != TYPE_CONSLIST_CONSPAIR ||
      top->right.value.next == NULL ){
    return nilEntity() ;
  }
  node = top->right.value.next ;
  while( node != NULL ){
    if( node->left.type != TYPE_CONSLIST_STRING ){
      return NULL ;
    } else {
      /* まず定義されている変数リストを探索する。*/
      varnode = search_localVariable
	( node->left.value.string, localVariableListTop ) ;
      if( varnode == NULL ){
	varnode = search_globalVariable( node->left.value.string ) ;
      }
      if( varnode == NULL ){
	if( ( varnode = create_newVariable() ) == NULL )
	  return NULL ;
	varnode->name = node->left.value.string ;
	node->left.value.string = NULL ;
      }
    }
    if( node->right.type == TYPE_CONSLIST_STRING ){
      entity = nilEntity() ;
      link_variable_to_entity( varnode, entity ) ;
      return entity ;
    }
    node = node->right.value.next ;
    entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    link_variable_to_entity( varnode, entity ) ;
    if( node->right.type != TYPE_CONSLIST_STRING ){ 
      node = node->right.value.next ;
    } else {
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
  }
  return entity ;
}

/*
 * (and ...) を実現する関数。
 *----
 * 細かい挙動までは確認できてないよお...。
 */
static struct skkinputlisp_entity *skkinputlisp_and
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  } else if( top->right.type == TYPE_CONSLIST_STRING ||
	     top->right.value.next == NULL ){
    return tEntity() ;
  }
  node = top->right.value.next ;
  while( node != NULL ){
    if( entity != NULL )
      free_unreferred_entity( entity ) ;

    entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ){
#if defined(DEBUG)
      fprintf
	( stdout,
	  "Wrong type argument: listp, %s\n",
	  node->right.value.string ) ;
#endif      
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    /* nil なら停止する。*/
    if( isNilEntity( entity ) ){
      return entity ;
    }
    node = node->right.value.next ;
  }
  return entity ;
}

/*
 * (or) を実現する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_or
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  } else if( top->right.type == TYPE_CONSLIST_STRING || 
	     top->right.value.next == NULL ){
    return nilEntity() ;
  }
  node = top->right.value.next ;
  while( node != NULL ){
    entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ){
#if defined(DEBUG)
      fprintf
	( stdout,
	  "Wrong type argument: listp, %s\n",
	  node->right.value.string ) ;
#endif      
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    /* nil なら停止する。*/
    if( !isNilEntity( entity ) ){
      return entity ;
    }
    free_unreferred_entity( entity ) ;
    node = node->right.value.next ;
  }
  return nilEntity() ;
}

/*
 * cond を実現する関数。
 * (cond ( ... ) ... ( ... )) という形になっていて、順々にリストを評価
 * する。
 */
static struct skkinputlisp_entity *skkinputlisp_cond
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node, *lnode ;

  if( top->right.type != TYPE_CONSLIST_CONSPAIR ){
#if defined(DEBUG)
    fprintf
      ( stdout,
	"Wrong type argument: listp, %s\n",
	top->right.value.string ) ;
#endif      
    return NULL ;
  }
#if 0
  else if( top->right.value.next == NULL ){
    /*
     * (cond . nil) は nil を返す。
     */ 
    return nilEntity() ;
  }
#endif
  node = top->right.value.next ;
  while( node != NULL ){
    /* 引数であるリストを順に評価していく。*/
    if( !isConslistNodeListP( &node->left ) ){
#if defined(DEBUG)
      fprintf
	( stdout,
	  "Wrong type argument: listp, %s\n",
	  node->left.value.string ) ;
#endif      
      return NULL ;
    }
    if( node->left.type == TYPE_CONSLIST_CONSPAIR ){
      lnode = node->left.value.next ;
      /* 引数を順に評価していく。*/
      entity = skkinputlisp_eval_car
	( lnode, localVariableListTop ) ;
      /* 評価にとことん失敗しましたか？ */
      if( entity == NULL )
	return NULL ;
      /* 評価に値しますか？ */
      if( !isNilEntity( entity ) ){
	if( !isConslistNodeListP( &lnode->right ) ){
#if defined(DEBUG)
	  fprintf
	    ( stdout,
	      "Wrong type argument: listp, %s\n",
	      lnode->right.value.string ) ;
#endif
	  free_unreferred_entity( entity ) ;
	  return NULL ;
	}
	/* cond の引数であるリストの中を順々に評価していく。*/
	while( lnode->right.value.next != NULL ){
	  entity = skkinputlisp_eval_car
	    ( lnode->right.value.next, localVariableListTop ) ;
	  lnode = lnode->right.value.next ;
	}
	/* 一番最後の結果が返される。*/
	return entity ;
      }
      free_unreferred_entity( entity ) ;
    } else {
      /* この場合にはどうせ nil なので、評価するだけ無駄である。*/
    }
    /* cond の次の引数を評価する。*/
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ){
#if defined(DEBUG)
      fprintf
	( stdout,
	  "Wrong type argument: listp, %s\n",
	  node->right.value.string ) ;
#endif      
      return NULL ;
    }
    node = node->right.value.next ;
  }
  return nilEntity() ;
}

/*
 * if を実現する関数。
 * (if a b c d) という形になっている。
 */
static struct skkinputlisp_entity *skkinputlisp_if
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity = NULL ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) )
    return NULL ;
  /* 引数の数をチェックする。*/
  argc = count_argument_number( top->right.value.next ) ;
  if( argc < 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Wrong number of arguments: #<subr if>, %d\n", argc ) ;
#endif    
    return NULL ;
  }
  node = top->right.value.next ;
  /* 条件を評価する。*/
  entity = skkinputlisp_eval_car
    ( node, localVariableListTop ) ;
  /* 評価にとことん失敗しましたか？ */
  if( entity == NULL )
    return NULL ;
  node = node->right.value.next ;
  /* さて？ どうですか？ */
  if( !isNilEntity( entity ) ){
    return skkinputlisp_eval_car( node, localVariableListTop ) ;
  } else {
    if( node->right.type == TYPE_CONSLIST_STRING || 
	node->right.value.next == NULL ){
      return nilEntity() ;
    } else {
      node = node->right.value.next ;
      return skkinputlisp_eval_car( node, localVariableListTop ) ;
    }
  }
  return nilEntity() ;
}

/*
 * 良く分からない関数：
 *      (f2c) (j-stay)
 * 実装するのがしんどそうな関数：
 *      (j-input-by-code-or-menu) (j-clock)
 * 容易に実装可能だと思われる関数：
 *      (skk-version) (j-date-and-time) (current-time-string)
 *      (j-date) (substring) (make-string)  (concat)
 */

static struct skkinputlisp_entity *skkinputlisp_concat
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  struct myChar *string ;
  int length, slen ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  } else if( top->right.type == TYPE_CONSLIST_STRING || 
	     top->right.value.next == NULL ){
    return emptyStringEntity() ;
  }
  length = 0 ;
  string = NULL ;
  node = top->right.value.next ;
  while( node != NULL ){
    /* 引数を順に評価していく。*/
    if( ( entity = skkinputlisp_eval_car
	  ( node, localVariableListTop ) ) == NULL ){
      goto myconcat_error ;
    }
    if( entity->type != ENTITY_STRING ){
#if defined(DEBUG)
      fprintf
	( stdout,
	  "Wrong type argument: sequencep, " ) ;
      print_entity( entity ) ;
      fprintf( stdout, "\n" ) ;
#endif
      goto myconcat_error ;
    }
    /* 仮に文字列が存在したならば…。*/
    if( entity->data.string != NULL ){
      slen = myCharStrlen( entity->data.string ) ;
      if( string == NULL ){
	if( ( string = 
	      malloc( sizeof( struct myChar ) * ( slen + 1 ) ) ) == NULL )
	  goto myconcat_error ;
	length = slen ;
	MYCHAR_SET_END_OF_STRING( *string ) ;
      } else {
	struct myChar *prev_string = string ;
	string = malloc
	  ( sizeof( struct myChar ) * ( slen + length + 1 ) ) ;
	if( string == NULL ){
	  free( prev_string ) ;
	  goto myconcat_error ;
	}
	myCharStrcpy( string, prev_string ) ;
	free( prev_string ) ;
	length += slen ;
      }
      myCharStrcat( string, entity->data.string ) ;
      MYCHAR_SET_END_OF_STRING( string[ length ] ) ;
      free_unreferred_entity( entity ) ;
    }
    /* cond の次の引数を評価する。*/
    if( node->right.type != TYPE_CONSLIST_CONSPAIR ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: listp, " ) ;
      myCharFputstring( node->right.value.string ) ;
      fputc( '\n', stdout ) ;
      fflush( stdout ) ;
#endif      
      goto myconcat_error ;
    }
    node = node->right.value.next ;
  }
  if( ( entity = create_newEntity() ) == NULL ){
    goto myconcat_error ;
  }
  entity->type = ENTITY_STRING ;
  entity->data.string = string ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;

myconcat_error:
  if( string != NULL )
    free( string ) ;
  free_unreferred_entity( entity ) ;
  return NULL ;
}

static struct skkinputlisp_entity *skkinputlisp_make_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  struct myChar *ptr ;
  int argc, len, chara ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  argc = count_argument_number( top->right.value.next ) ;
  if( argc != 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr make-string>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  node = top->right.value.next ;
  /* 引数を順に評価していく。*/
  if( ( entity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    return NULL ;
  }
  if( entity->type != ENTITY_INTEGER ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong type argument: wholenump, " ) ;
    print_entity( entity ) ;
    fprintf( stdout, "\n" ) ;
#endif      
    goto mymakestring_error ;
  }
  len = entity->data.integer ;
  free_unreferred_entity( entity ) ;

  node = node->right.value.next ;
  /* 引数を順に評価していく。*/
  if( ( entity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    return NULL ;
  }
  if( entity->type != ENTITY_INTEGER ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong type argument: integerp, " ) ;
    print_entity( entity ) ;
    fprintf( stdout, "\n" ) ;
#endif      
    goto mymakestring_error ;
  }
  chara = entity->data.integer ;
  free_unreferred_entity( entity ) ;

  if( ( entity = create_newEntity() ) == NULL ){
    goto mymakestring_error ;
  }
  entity->type = ENTITY_STRING ;
  entity->data.string = malloc
    ( ( len + 1 ) * sizeof( unsigned char ) ) ;
  if( entity->data.string == NULL )
    goto mymakestring_error ;
  ptr = entity->data.string ;
  while( len > 0 ){
    MYCHAR_SET_CHARA( *ptr, chara ) ;
    ptr ++ ;
    len -- ;
  }
  MYCHAR_SET_END_OF_STRING( *ptr ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;

mymakestring_error:
  free_unreferred_entity( entity ) ;
  return NULL ;
}

static struct skkinputlisp_entity *skkinputlisp_substring
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  int argc, len, startpoint, endpoint ;

  entity = tmpEntity = NULL ;
  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  argc = count_argument_number( top->right.value.next ) ;
  if( argc != 2 && argc != 3 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr substring>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  node = top->right.value.next ;
  /* 引数を順に評価していく。*/
  if( ( entity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    return NULL ;
  }
  if( entity->type != ENTITY_STRING ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong type argument: stringp, " ) ;
    print_entity( entity ) ;
    fprintf( stdout, "\n" ) ;
#endif      
    goto mysubstring_error ;
  }
  if( entity->data.string != NULL ){
    len = myCharStrlen( entity->data.string ) ;
  } else {
    len = 0 ;
  }
  node = node->right.value.next ;
  /* 引数を順に評価していく。*/
  if( ( tmpEntity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    return NULL ;
  }
  if( tmpEntity->type != ENTITY_INTEGER ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong type argument: integerp, " ) ;
    print_entity( tmpEntity ) ;
    fprintf( stdout, "\n" ) ;
#endif      
    goto mysubstring_error ;
  }
  startpoint = tmpEntity->data.integer ;
  if( startpoint > len || startpoint < 0 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Args out of range: \"%s\", %d\n",
	entity->data.string, startpoint ) ;
#endif      
    goto mysubstring_error ;
  }
  free_unreferred_entity( tmpEntity ) ;
  if( argc == 3 ){
    node = node->right.value.next ;
    /* 引数を順に評価していく。*/
    if( ( tmpEntity = skkinputlisp_eval_car
	  ( node, localVariableListTop ) ) == NULL ){
      return NULL ;
    }
    if( tmpEntity->type != ENTITY_INTEGER ){
#if defined(DEBUG)
      fprintf
	( stdout, 
	  "Wrong type argument: integerp, " ) ;
      print_entity( tmpEntity ) ;
      fprintf( stdout, "\n" ) ;
#endif      
      goto mysubstring_error ;
    }
    endpoint = tmpEntity->data.integer ;
    if( len < endpoint || startpoint > endpoint ){
#if defined(DEBUG)
      fprintf
	( stdout, 
	  "Args out of range: \"%s\", %d, %d\n",
	  entity->data.string, startpoint, tmpEntity->data.integer ) ;
#endif      
      goto mysubstring_error ;
    }
  } else {
    endpoint = len ;
  }
  if( ( tmpEntity = create_newEntity() ) == NULL ){
    goto mysubstring_error ;
  }
  tmpEntity->type = ENTITY_STRING ;
  tmpEntity->data.string = malloc
    ( ( len + 1 ) * sizeof( struct myChar ) ) ;
  if( tmpEntity->data.string == NULL )
    goto mysubstring_error ;
  myCharStrncpy
    ( tmpEntity->data.string, entity->data.string + startpoint,
      endpoint - startpoint ) ;
  MYCHAR_SET_END_OF_STRING
    ( tmpEntity->data.string[ endpoint - startpoint ] ) ;
  free_unreferred_entity( entity ) ;

  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( tmpEntity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( tmpEntity ) ;
    entity = tmpEntity ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( tmpEntity ) ;
  }
  return ( entity ) ;

mysubstring_error:
  free_unreferred_entity( tmpEntity ) ;
  free_unreferred_entity( entity ) ;
  return NULL ;
}

/*
 * (current-time-string) を実行する関数。
 *----
 * current-time-string は emacs-lisp に存在する関数であり、引数を一つ
 * とることを許されている。その引数は必ず (a . b) の形の conspair に
 * なっていなければならない。1970/01/01 09:00:00 からの経過秒数を 
 * (a * 65536 + b) の形で指定しているのである。省略すると、現在までの
 * 経過秒数を与えたことになる。
 */
static struct skkinputlisp_entity *skkinputlisp_current_time_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  unsigned char *string ;
  int argc, len ;
  time_t secs ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  entity = NULL ;
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  if( argc > 1 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr current-time-string>, %d\n",
	argc ) ;
#endif      
    return NULL ;
  }
  if( argc == 0 ){
    /* 1970/01/01 09:00:00 からの経過時間を求める。*/
    secs = time( NULL ) ;
  } else {
    /* 引数を順に評価していく。*/
    if( ( entity = skkinputlisp_eval_car
	  ( node, localVariableListTop ) ) == NULL ){
      return NULL ;
    }
    if( entity->type != ENTITY_CONS ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: listp, " ) ;
      print_entity( entity ) ;
      fprintf( stdout, "\n" ) ;
#endif      
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    if( entity->data.conspair.left == NULL ||
	entity->data.conspair.left->type != ENTITY_INTEGER ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: integerp, " ) ;
      print_entity( entity->data.conspair.left ) ;
      fprintf( stdout, "\n" ) ;
#endif      
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    if( entity->data.conspair.right == NULL ||
	entity->data.conspair.right->type != ENTITY_INTEGER ){
#if defined(DEBUG)
      fprintf
	( stdout, "Wrong type argument: integerp, " ) ;
      print_entity( entity->data.conspair.right ) ;
      fprintf( stdout, "\n" ) ;
#endif      
      free_unreferred_entity( entity ) ;
      return NULL ;
    }
    secs = entity->data.conspair.left->data.integer * 0x10000 +
      entity->data.conspair.right->data.integer ;
  }
  free_unreferred_entity( entity ) ;
  if( ( entity = create_newEntity() ) == NULL )
    return NULL ;
  entity->type = ENTITY_STRING ;
  string = ctime( &secs ) ;
  len    = strlen( string ) ;
  entity->data.string =
    malloc( sizeof( struct myChar ) * ( len + 1 ) ) ;
  if( entity->data.string == NULL ){
    free_unreferred_entity( entity ) ;
    return NULL ;
  }
  myCharCharStrcpy( entity->data.string, string ) ;
  if( IS_ASCII_EQUAL( entity->data.string[ len - 1 ], '\n' ) )
    MYCHAR_SET_END_OF_STRING( entity->data.string[ len - 1 ] ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;
}

#if defined(MYEVAL_ONLY)
int j_date_ad( struct myChar *buffer, int bufsize, int date_ad, int num_style )
{
  return False ;
}
#endif

/*
 * skk に与えられている関数である、j-date を実行する関数。
 *----
 * j-date には二つ引数が許されており、
 *     最初の引数は、年号か西暦か。
 *     次の引数は、  数値を漢字で表示するかという数値の表示方法。
 */
static struct skkinputlisp_entity *skkinputlisp_j_date
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *entities[ 2 ], *tmpEntity ;
  struct conslist *node ;
  int argc, i, local_date_ad, local_number_style, len ;
  struct myChar buffer[ TEXTBUFSIZE ] ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  entity = NULL ;
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  if( argc > 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr j-date>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  for( i = 0 ; i < argc && node != NULL ; i ++ ){
    /* 引数を順に評価していく。*/
    if( ( entity = skkinputlisp_eval_car
	  ( node, localVariableListTop ) ) == NULL ){
      return NULL ;
    }
    entities[ i ] = entity ;
    node = node->right.value.next ;
  }
  if( argc > 0 ){
    if( !isNilEntity( entities[ 0 ] ) ){
      local_date_ad = True ;
    } else {
      local_date_ad = False ;
    }
  } else {
    local_date_ad = -1 ;
  }
  if( argc == 2 ){
    if( entities[ 1 ]->type != ENTITY_INTEGER ){
      local_number_style = 0 ;
    } else {
      local_number_style = entities[ 1 ]->data.integer ;
    }
  } else {
    local_number_style = -1 ;
  }
  for( i = 0 ; i < argc ; i ++ )
    free_unreferred_entity( entities[ i ] ) ;
  if( !j_date_ad( buffer, TEXTMAXLEN, local_date_ad, local_number_style ) )
    return NULL ;
  if( ( entity = create_newEntity() ) == NULL )
    return NULL ;
  entity->type = ENTITY_STRING ;
  len = myCharStrlen( buffer ) ;
  entity->data.string =
    malloc( sizeof( struct myChar ) * ( len + 1 ) ) ;
  if( entity->data.string == NULL ){
    free_unreferred_entity( entity ) ;
    return NULL ;
  }
  myCharStrcpy( entity->data.string, buffer ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;
}

/*
 * (skk-version)
 */
static struct skkinputlisp_entity *skkinputlisp_skk_version
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  int argc, len ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  entity = NULL ;
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  if( argc > 1 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr skk-version>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  if( ( entity = create_newEntity() ) == NULL )
    return NULL ;
  entity->type = ENTITY_STRING ;
  len = strlen( skkinput_version ) ;
  entity->data.string = 
    malloc( sizeof( struct myChar ) * ( len + 1 ) ) ;
  if( entity->data.string == NULL ){
    free_unreferred_entity( entity ) ;
    return NULL ;
  }
  myCharCharStrcpy( entity->data.string, skkinput_version ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;
}

/*
 * (aref 配列 要素番号) を実現するのに利用される関数。
 */
static struct skkinputlisp_entity *skkinputlisp_aref
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *ar_entity, *i_entity ;
  struct skkinputlisp_entity *entity, *tmpEntity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  entity = NULL ;
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  if( argc != 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr aref>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  /* 引数を順に評価していく。*/
  if( ( ar_entity = skkinputlisp_evalCarAndCheckType
	( node, localVariableListTop, ENTITY_ARRAY ) ) == NULL ){
    return NULL ;
  }
  node = node->right.value.next ;
  /* 引数を順に評価していく。*/
  if( ( i_entity = skkinputlisp_evalCarAndCheckType
	( node, localVariableListTop, ENTITY_INTEGER ) ) == NULL ){
    return NULL ;
  }
  if( ar_entity->data.array.length <= i_entity->data.integer ||
      i_entity->data.integer < 0 ){
#if defined(DEBUG)
    fprintf( stdout, "Args out of range: " ) ;
    print_entity( ar_entity ) ;
    fprintf( stdout, " " ) ;
    print_entity( i_entity ) ;
    fprintf( stdout, "\n" ) ;
#endif    
    free_unreferred_entity( ar_entity ) ;
    free_unreferred_entity( i_entity ) ;
    return NULL ;
  }
  entity = ar_entity->data.array.array[ i_entity->data.integer ] ;
  free_unreferred_entity( ar_entity ) ;
  free_unreferred_entity( i_entity ) ;
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( tmpEntity = search_entity( entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( entity ) ;
    entity = tmpEntity ;
  }
  return ( entity ) ;
}

/*
 * (aset 配列 要素番号 新しい要素) を実現するのに利用される関数。
 */
static struct skkinputlisp_entity *skkinputlisp_aset
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *ar_entity, *i_entity ;
  struct skkinputlisp_entity *s_entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  if( ( argc = count_argument_number( node ) ) != 3 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr aset>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  /* 引数を順に評価していく。(最初の引数は評価した結果は必ず配列でなけ
     ればならない。*/
  if( ( ar_entity = skkinputlisp_evalCarAndCheckType
	( node, localVariableListTop, ENTITY_ARRAY ) ) == NULL ){
    return NULL ;
  }
  /* 引数を順に評価していく。(第２引数は評価した結果は必ず整数でなけれ
     ばならない。*/
  node = node->right.value.next ;
  if( ( i_entity = skkinputlisp_evalCarAndCheckType
	( node, localVariableListTop, ENTITY_INTEGER ) ) == NULL ){
    return NULL ;
  }
  /* ここで引数に指定された値が正しいものであるかどうかをちょこっと判
     断します。*/
  if( ar_entity->data.array.length <= i_entity->data.integer ||
      i_entity->data.integer < 0 ){
#if defined(DEBUG)
    fprintf( stdout, "Args out of range: " ) ;
    print_entity( ar_entity ) ;
    fprintf( stdout, " " ) ;
    print_entity( i_entity ) ;
    fprintf( stdout, "\n" ) ;
#endif    
    free_unreferred_entity( ar_entity ) ;
    free_unreferred_entity( i_entity ) ;
    return NULL ;
  }
  /* 引数を順に評価していく。(第３引数は何でもよいの？) */
  node = node->right.value.next ;
  if( ( s_entity = skkinputlisp_eval_car
	( node, localVariableListTop ) ) == NULL ){
    /* この状態に来る要因としては、symbol's value as ほげほげ がある。*/
    free_unreferred_entity( ar_entity ) ;
    free_unreferred_entity( i_entity ) ;
    return NULL ;
  }
  /* もともと指されていた実体を破棄する。*/
  free_entity
    ( ar_entity->data.array.array[ i_entity->data.integer ] ) ;
  /* 新しく指されることになる実体のカウンタを増やす。*/
  increment_entity_count( s_entity ) ;
  ar_entity->data.array.array[ i_entity->data.integer ] = s_entity ;
  /* もし、ちっとも全然少しもこれっぽっちも指されることが無いのなら消
     す。*/
  free_unreferred_entity( ar_entity ) ;
  free_unreferred_entity( i_entity ) ;
  return ( s_entity ) ;
}

/*
 * (defun) を実行する関数。
 *
 * (defun シンボル (引数 …) 命令列(アトムの列？) … )
 */
static struct skkinputlisp_entity *skkinputlisp_defun
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *s_entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  if( ( argc = count_argument_number( node ) ) < 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr defun>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  /* 引数の型チェック。第１引数はシンボルでなければならない。*/
  if( node->left.type != TYPE_CONSLIST_STRING )
    return NULL ;
  s_entity = stringIsAtom
    ( node->left.value.string, localVariableListTop ) ;
  if( s_entity == NULL ){
#if defined(DEBUG)
    fprintf( stdout, "Wrong type argument: symbolp, " ) ;
    print_entity( s_entity ) ;
    fprintf( stdout, "\n" ) ;
#endif      
    return NULL ;
  }
  /* 引数リストをすげかえて登録する。関数名は lambda に差し替える。*/
  node = top->right.value.next ;
  if( node->left.value.string != NULL ){
    free( node->left.value.string ) ;
  }
  /* strlcn( "lambda" ) == 6 */
  node->left.value.string = malloc( sizeof( struct myChar ) * 7 ) ;
  if( node->left.value.string == NULL ){
    free_unreferred_entity( s_entity ) ;
    return NULL ;
  }
  myCharCharStrcpy( node->left.value.string, "lambda" ) ;
  if( !skkinputlisp_registerUserDefinedFunction
      ( s_entity->data.string, node ) ){
    free_unreferred_entity( s_entity ) ;
    return NULL ;
  }
  top->right.value.next = NULL ;
  return s_entity ;
}

/*
 * (lambda) を実行する関数。
 *
 * (lambda (引数 …) 命令列(アトムの列？) … )
 * この引数の置き換えが問題になると思うのだが…うーん。そういうのは無
 * 視する？
 */
static struct skkinputlisp_entity *skkinputlisp_lambda
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  /* 続く引数は list でないといけない。*/
  if( !skkinputlisp_listpCheck( top ) )
    return NULL ;
  /* lambda はダミー関数なので、何もしない。*/
  return conslist2conspair( top, localVariableListTop ) ;
}

/*
 * 局所変数を一つ用意する関数。
 */
static struct skkinputlisp_variable *alloc_localVariable
( struct myChar *name, struct skkinputlisp_entity *entity )
{
  struct skkinputlisp_variable *vnode ;
  if( name == NULL || entity == NULL )
    return NULL ;
  /* メモリの確保。*/
  vnode = malloc( sizeof( struct skkinputlisp_variable ) ) ;
  if( vnode == NULL )
    return NULL ;
  vnode->name = malloc
    ( sizeof( struct myChar ) * ( myCharStrlen( name ) + 1 ) ) ;
  if( vnode->name == NULL ){
    free( vnode ) ;
    return NULL ;
  }
  myCharStrcpy( vnode->name, name ) ;
  vnode->value = NULL ;
  /* 実体をつなぐ。*/
  link_variable_to_entity( vnode, entity ) ;
  return vnode ;
}

/*
 * 局所変数を破棄するのに用いられる関数。
 */
static void destroy_localVariable
( struct skkinputlisp_variable *variableListTop )
{
  struct skkinputlisp_variable *varnode, *nextVarnode ;
  varnode = variableListTop ;
  while( varnode != NULL ){
    nextVarnode = varnode->next ;
    /* 変数名を解放する。*/
    if( varnode->name != NULL )
      free( varnode->name ) ;
    /* 実体を解放する。*/
    free_entity( varnode->value ) ;
    varnode = nextVarnode ;
  }
  return ;
}

/*
 * 注意！ これは let には使えない。let は左で代入された値が右に影響す
 * るが、これはそういうことは全然ないので。
 */
static struct skkinputlisp_variable *create_localVariableForLambda
( struct conslist *varNode, struct conslist *valueNode,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_variable *newListTop, *vnode ;
  struct skkinputlisp_entity *entity ;

  newListTop = NULL ;
  while( varNode != NULL ){
    if( varNode->left.type != TYPE_CONSLIST_STRING )
      goto create_localv_error ;
    entity = skkinputlisp_eval_car( valueNode, localVariableListTop ) ;
    if( entity == NULL )
      goto create_localv_error ;
    vnode = alloc_localVariable
      ( varNode->left.value.string, entity ) ;
    if( vnode == NULL ){
      free_unreferred_entity( entity ) ;
      goto create_localv_error ;
    } else {
      vnode->next = newListTop ;
      newListTop = vnode ;
    }
    varNode = varNode->right.value.next ;
    valueNode = valueNode->right.value.next ;
  }
  return newListTop ;

create_localv_error:
  destroy_localVariable( newListTop ) ;
  return NULL ;
}

/*
 * (lambda) 式を実行解釈する関数。
 *-----
 * 内容…(しくしく、結構面倒だね)
 * (car (car top)) == "lambda"
 * (car (cdr (car top))) == "(引数のリスト)"
 * (cdr (cdr (car top))) == "(解釈実行／評価される命令の列)"
 * (cdr top) == "(引数のリストに入るべき値)"
 * まず、(cdr top) を (car (cdr (car top))) を見て、(cdr (cdr (car
 * top))) の中に叩き込まなければならない。その後は、順に 
 * (cdr (cdr (car top))) を eval していく。
 */
static struct skkinputlisp_entity *myevalLambdaForm
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  int argcl, argca, argc1 ;
  struct conslist *node, *vNode ;
  struct skkinputlisp_variable *newLocalVariableListTop ;
  struct skkinputlisp_variable *pVarListNode ;
  struct skkinputlisp_entity *entity ;

  /* (lambda ... ) の長さを勘定する。*/
  node = top->left.value.next ;
  argcl = count_argument_number( node->right.value.next ) ;
  argc1 = 0 ;
  /* (lambda 最初の引数 ... ) と最初の引数があれば、それは lambda 関数
     への引数のリストを表現している。*/
  vNode = NULL ;
  if( argcl > 0 ){
    node = node->right.value.next ;
    if( !isConslistNodeListP( &node->left ) ){
#if defined(DEBUG)
      fprintf( stdout, "Wrong type argument: listp, 1\n" ) ;
#endif
      return NULL ;
    } else if( node->left.type == TYPE_CONSLIST_CONSPAIR ){
      vNode = node->left.value.next ;
      /* 何個変数を引数に持っているのかを勘定しておく。*/
      argc1 = count_argument_number( node->left.value.next ) ;
    }
  }
  /* lambda 式に渡される引数の数を勘定する。*/
  if( !isConslistNodeListP( &top->right ) )
    return NULL ;
  if( top->right.type == TYPE_CONSLIST_CONSPAIR ){
    argca = count_argument_number( top->right.value.next ) ;
  } else {
    argca = 0 ;
  }
  /* 引数の数を比較する。*/
  if( argc1 != argca ){
#if defined(DEBUG)
    fprintf( stdout, "Wrong number of arguments: " ) ;
    print_conslist( top->left.value.next ) ;
    fprintf( stdout, ", %d\n", argca ) ;
#endif
    return NULL ;
  }
  if( argcl == 0 ){
    return nilEntity() ;
  }
  /* 局所変数を用意する。その名前は argc1 にあるもの、その実体(内容)は 
     argca にあるものを利用する。*/
  pVarListNode = NULL ;
  if( vNode != NULL ){
    struct skkinputlisp_variable *tmpnode ;
    newLocalVariableListTop = create_localVariableForLambda
      ( vNode, top->right.value.next, localVariableListTop ) ;
    /* 局所変数の用意に失敗した場合の処理。*/
    if( newLocalVariableListTop == NULL ){
#if defined(DEBUG)
      fprintf( stdout, "(create_local_variable) returns NULL.\n" ) ;
#endif
      return NULL ;
    }
    if( ( tmpnode = newLocalVariableListTop ) != NULL ){
      while( tmpnode->next != NULL )
	tmpnode = tmpnode->next ;
      pVarListNode = tmpnode ;
      tmpnode->next = localVariableListTop ;
    }
  } else {
    newLocalVariableListTop = localVariableListTop ;
  }
  /* ここで順々に評価するってことをやる。*/
  node = top->left.value.next->right.value.next->right.value.next ;
  entity = NULL ;
  while( node != NULL ){
    if( entity != NULL )
      free_unreferred_entity( entity ) ;
    entity = skkinputlisp_eval_car( node, newLocalVariableListTop ) ;
    /* エラーが出たら、そこで停止する。*/
    if( entity == NULL )
      break ;
    node = node->right.value.next ;
  }

  /* 局所変数を破棄する。*/
  if( pVarListNode != NULL ){
    pVarListNode->next = NULL ;
    destroy_localVariable( newLocalVariableListTop ) ;
  }
  return entity ;
}

/*
 * (* 数値 … 数値) を実行する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_multiply
( struct conslist *top, 
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *r_entity, *entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_INTEGER ;
  r_entity->data.integer = 1 ;
  node = top->right.value.next ;
  /* 引数の数を数えておく。*/
  argc = count_argument_number( node ) ;
  while( argc > 0 && node != NULL ){
    entity = skkinputlisp_evalCarAndCheckType
      ( node, localVariableListTop, ENTITY_INTEGER ) ;
    if( entity == NULL ){
      free_unreferred_entity( r_entity ) ;
      return NULL ;
    }
    /* 乗算を行う。*/
    r_entity->data.integer = r_entity->data.integer *
      entity->data.integer ;
    free_unreferred_entity( entity ) ;
    argc -- ;
    node = node->right.value.next ;
  }
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}

/*
 * (+ 数値 … 数値) を実行する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_plus
( struct conslist *top, 
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *r_entity, *entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_INTEGER ;
  r_entity->data.integer = 0 ;
  node = top->right.value.next ;
  /* 引数の数を数えておく。*/
  argc = count_argument_number( node ) ;
  while( argc > 0 && node != NULL ){
    entity = skkinputlisp_evalCarAndCheckType
      ( node, localVariableListTop, ENTITY_INTEGER ) ;
    if( entity == NULL ){
      free_unreferred_entity( r_entity ) ;
      return NULL ;
    }
    /* 乗算を行う。*/
    r_entity->data.integer = r_entity->data.integer +
      entity->data.integer ;
    free_unreferred_entity( entity ) ;
    argc -- ;
    node = node->right.value.next ;
  }
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}

/*
 * (/ 数値 … 数値) を実行する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_divide
( struct conslist *top, 
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *r_entity, *entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  /* 引数の数を数えておく。*/
  argc = count_argument_number( node ) ;
  if( argc < 2 ){
#if defined(DEBUG)
    fprintf
      ( stdout, "Wrong number of arguments: #<subr />, %d\n", argc ) ;
#endif
    return NULL ;
  }
  /* 非除数を求める。*/
  entity = skkinputlisp_evalCarAndCheckType
    ( node, localVariableListTop, ENTITY_INTEGER ) ;
  if( entity == NULL )
    return NULL ;
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_INTEGER ;
  r_entity->data.integer = entity->data.integer ;
  free_unreferred_entity( entity ) ;
  node = node->right.value.next ;
  argc -- ;
  /* 以下、除数を求めて、非除数を割っていく。*/
  while( argc > 0 && node != NULL ){
    entity = skkinputlisp_evalCarAndCheckType
      ( node, localVariableListTop, ENTITY_INTEGER ) ;
    if( entity == NULL ){
      free_unreferred_entity( r_entity ) ;
      return NULL ;
    }
    /* 除算を行う。*/
    r_entity->data.integer = r_entity->data.integer /
      entity->data.integer ;
    free_unreferred_entity( entity ) ;
    argc -- ;
    node = node->right.value.next ;
  }
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}


/*
 * (- 数値 … 数値) を実行する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_minus
( struct conslist *top, 
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *r_entity, *entity ;
  struct conslist *node ;
  int argc, value ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  /* 返す値を用意しておく。*/
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_INTEGER ;
  /* 引数の数を数えておく。*/
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  if( argc <= 0 ){
    r_entity->data.integer = 0 ;
  } else {
    entity = skkinputlisp_evalCarAndCheckType
      ( node, localVariableListTop, ENTITY_INTEGER ) ;
    if( entity == NULL ){
      free_unreferred_entity( r_entity ) ;
      return NULL ;
    }
    value = entity->data.integer ;
    free_unreferred_entity( entity ) ;
    if( argc == 1 ){
      /* 引数が一つだけならば、その数値の正負を入れ替える。*/
      r_entity->data.integer = value * (-1) ;
    } else {
      /* 引数が複数あれば、最初の数値から順に減算を行う。*/
      r_entity->data.integer = value ;

      node = node->right.value.next ;
      argc -- ;
      while( argc > 0 && node != NULL ){
	entity = skkinputlisp_evalCarAndCheckType
	  ( node, localVariableListTop, ENTITY_INTEGER ) ;
	if( entity == NULL ){
	  free_unreferred_entity( r_entity ) ;
	  return NULL ;
	}
	/* 減算を行う。*/
	r_entity->data.integer = r_entity->data.integer -
	  entity->data.integer ;
	free_unreferred_entity( entity ) ;
	argc -- ;
	node = node->right.value.next ;
      }
    }
  }
  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}

/*
 * 文字列を数値に変換する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_string_to_int
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *r_entity ;
  struct conslist *node ;
  int argc, value ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  if( ( argc = count_argument_number( node ) ) != 1 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr string-to-int>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  entity = skkinputlisp_evalCarAndCheckType
    ( node, localVariableListTop, ENTITY_STRING ) ;
  if( entity == NULL )
    return NULL ;
  value = myCharAtoi( entity->data.string ) ;
  free_unreferred_entity( entity ) ;
  /* 返す値を用意しておく。*/
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_INTEGER ;
  r_entity->data.integer = value ;

  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}

/*
 * 数値を文字列に変換する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_int_to_string
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *r_entity ;
  struct conslist *node ;
  /* この 64 とかいう数値は MAX_INTEGER を見て修正しないといけないが…
     うーん。面倒かなあ？ 当分は 64桁あれば大丈夫だと思うけどね。*/
  unsigned char buffer[ 64 ] ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  if( ( argc = count_argument_number( node ) ) != 1 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr int-to-string>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  entity = skkinputlisp_evalCarAndCheckType
    ( node, localVariableListTop, ENTITY_INTEGER ) ;
  if( entity == NULL )
    return NULL ;
  sprintf( buffer, "%d", entity->data.integer ) ;
  free_unreferred_entity( entity ) ;
  /* 返す値を用意しておく。*/
  if( ( r_entity = create_newEntity() ) == NULL )
    return NULL ;
  r_entity->type = ENTITY_STRING ;
  r_entity->data.string = malloc
    ( sizeof( struct myChar ) * ( strlen( buffer ) + 1 ) ) ;
  if( r_entity->data.string == NULL ){
    free_unreferred_entity( r_entity ) ;
    return NULL ;
  }
  myCharCharStrcpy( r_entity->data.string, buffer ) ;

  /* 仮の実体に等しい実体が存在するかを調べる。*/
  if( ( entity = search_entity( r_entity ) ) == NULL ){
    /* 実体の列につないでおく。*/
    link_newEntity( r_entity ) ;
    /* 自分自身の参照カウンタは増やさないこと。*/
  } else {
    free_unreferred_entity( r_entity ) ;
    r_entity = entity ;
  }
  return r_entity ;
}

static struct skkinputlisp_entity *skkinputlisp_progn
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity ;
  struct conslist *node ;
  int argc ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  argc = count_argument_number( node ) ;
  entity = nilEntity() ;
  while( node != NULL && argc > 0 ){
    if( entity != NULL )
      free_unreferred_entity( entity ) ;
    entity = skkinputlisp_eval_car( node, localVariableListTop ) ;
    if( entity == NULL )
      return NULL ;
    node = node->right.value.next ;
    argc -- ;
  } 
  return entity ;
}

/*
 * 滅茶苦茶な関数…。この関数は load-file 以外では絶対に使わないこと！！
 * こんな malloc しまくり関数が存在するとあとがひどそう...。
 * load-file を巨大なファイルに対してかけると腐るわけですわ。
 */
static struct myChar *add_myCharString_myCharString
( struct myChar *oldstring, struct myChar *string )
{
  int length ;
  struct myChar *ret ;
  
  if( oldstring != NULL ){
    length = myCharStrlen( oldstring ) + 1 ;
  } else {
    length = 1 ;
  } 
  length += myCharStrlen( string ) ;
  if( ( ret = malloc( sizeof( struct myChar ) * length ) ) == NULL )
    return NULL ;
  if( oldstring != NULL ){
    myCharStrcpy( ret, oldstring ) ;
  } else {
    MYCHAR_SET_END_OF_STRING( *ret ) ;
  }
  myCharStrcat( ret, string ) ;
  return ret ;
}

/*
 * 滅茶苦茶な関数…。この関数は load-file 以外では絶対に使わないこと！！
 * こんな malloc しまくり関数が存在するとあとがひどそう...。
 * load-file を巨大なファイルに対してかけると腐るわけですわ。
 */
static struct myChar *add_myCharString_string
( struct myChar *oldstring, unsigned char *string )
{
  int length ;
  struct myChar *ret ;
  
  if( oldstring != NULL ){
    length = myCharStrlen( oldstring ) + 1 ;
  } else {
    length = 1 ;
  } 
  length += strlen( string ) ;
  if( ( ret = malloc( sizeof( struct myChar ) * length ) ) == NULL )
    return NULL ;
  if( oldstring != NULL ){
    myCharStrcpy( ret, oldstring ) ;
  } else {
    MYCHAR_SET_END_OF_STRING( *ret ) ;
  }
  myCharCharStrcat( ret, string ) ;
  return ret ;
}

static struct myChar *skkinputlisp_load_file_sub
( unsigned char *path, int jcode )
{
  FILE *fp ;
  struct myChar *command_string, *newstring ;
  struct myChar *oneline ;

  command_string = NULL ;
  if( ( fp = fopen( path, "r" ) ) == NULL )
    return False ;
  
  command_string = add_myCharString_string
    ( NULL, "(progn " ) ;
  while( !feof( fp ) ){
    if( ( oneline = mychar_readOneLine( fp, jcode ) ) == NULL )
      break ;
    delete_comment_string( oneline ) ;
    if( IS_END_OF_STRING( *oneline ) ){
      free( oneline ) ;
      continue ;
    }
    if( ( newstring = add_myCharString_myCharString
	  ( command_string, oneline ) ) == NULL ){
      free( oneline ) ;
      free( command_string ) ;
      fclose( fp ) ;
      return NULL ;
    }
    free( oneline ) ;
    free( command_string ) ;
    command_string = newstring ;
  }
  newstring = add_myCharString_string
    ( command_string, ")" ) ;
  free( command_string ) ;
  fclose( fp ) ;
  return newstring ;
}

/*
 * (load-file "ファイル名") を実行する関数。
 */
static struct skkinputlisp_entity *skkinputlisp_load_file
( struct conslist *top,
  struct skkinputlisp_variable *localVariableListTop )
{
  struct skkinputlisp_entity *entity, *tmpentity ;
  struct conslist *node ;
  unsigned char *path, *asciiString ;
  struct myChar *command_string, *realcommand ;
  int argc, jcode ;

  if( !skkinputlisp_sequencepCheck( top ) ){
    return NULL ;
  }
  node = top->right.value.next ;
  if( ( argc = count_argument_number( node ) ) != 1 ){
#if defined(DEBUG)
    fprintf
      ( stdout, 
	"Wrong number of arguments: #<subr load-file>, %d\n", argc ) ;
#endif      
    return NULL ;
  }
  /* 引数の型チェック。*/
  if( ( entity = skkinputlisp_evalCarAndCheckType
	( node, localVariableListTop, ENTITY_STRING ) ) == NULL ){
    return NULL ;
  }
  /* もう勝手に expand-file-name してしまう...いいのかなあ？ */
  asciiString = myCharStringToAsciiString( entity->data.string ) ;
  if( asciiString == NULL )
    return NULL ;
  path = expand_file_name( asciiString ) ;
  free( asciiString ) ;
  free_unreferred_entity( entity ) ;
  /* 読み込むファイルの漢字コードを判別する。*/
  jcode = check_skkinput_jisyo_code( path ) ;
  command_string = skkinputlisp_load_file_sub( path, jcode ) ;
  free( path ) ;
  if( command_string == NULL ){
    return NULL ;
  }
  if( ( realcommand = convert_quote( command_string ) ) == NULL ){
    free( command_string ) ;
    return NULL ;
  }
  tmpentity = string2entity( realcommand, localVariableListTop ) ;
  free( command_string ) ;
  free( realcommand ) ;
  if( tmpentity == NULL )
    return NULL ;
  free_unreferred_entity( tmpentity ) ;
  return tEntity() ;
}

/*
 * skkinput が辞書の候補が (...) だった時に呼出す関数。
 */
int skkinputlisp_eval
( struct myChar *commandstring, struct myChar *buffer )
{
  struct skkinputlisp_entity *entity ;
  struct myChar *realcommand ;
  int length ;

  if( ( realcommand = convert_quote( commandstring ) ) == NULL )
    return False ;
  entity = string2entity( realcommand, NULL ) ;
  free( realcommand ) ;
  if( entity == NULL ){
    skkinputlisp_garbagecollector() ;
    return False ;
  }
  /* 文字列でなければならない。*/
  if( entity->type != ENTITY_STRING ){
    skkinputlisp_garbagecollector() ;
    return False ;
  }
  if( entity->data.string == NULL ){
    MYCHAR_SET_END_OF_STRING( buffer[ 0 ] ) ;
  } else {
    if( ( length = myCharStrlen( entity->data.string ) ) > TEXTMAXLEN )
      length = TEXTMAXLEN ;
    myCharStrncpy( buffer, entity->data.string, length ) ;
    MYCHAR_SET_END_OF_STRING( buffer[ length ] ) ;
  }
  skkinputlisp_garbagecollector() ;
  return True ;
}

/*
 * 返り値が文字列でなくても問題にしない文字列実行関数。
 */
int skkinputlisp_weak_eval
( struct myChar *commandstring )
{
  struct skkinputlisp_entity *entity ;
  struct myChar *realcommand ;
  int ret ;

  if( ( realcommand = convert_quote( commandstring ) ) == NULL )
    return False ;
  entity = string2entity( realcommand, NULL ) ;
  free( realcommand ) ;
  ret = ( entity == NULL )? False : True ;
  skkinputlisp_garbagecollector() ;
  return ret ;
}

/*
 * j-num-list に数値変換の時の値を入れる関数。
 *----
 * j-num-list に特化してしまっています…。そういう関数が必要かと思いま
 * して…。
 */
int skkinput_create_j_num_list
( struct myChar *string )
{
  struct skkinputlisp_entity *entity ;
  struct myChar *liststr ;
  struct myChar *ptr ;
  int counter, length ;

  length = counter = 0 ;
  for( ptr = string ; !IS_END_OF_STRING( *ptr ) ; ptr ++ ){
    if( IS_ASCII_EQUAL( *ptr, '/' ) )
      counter ++ ;
    length ++ ;
  }
  if( counter <= 0 || length <= 0 )
    return True ;
  liststr = malloc
    ( sizeof( struct myChar ) * ( length + counter * 2 + 30 ) ) ;
  if( liststr == NULL )
    return False ;
  
  myCharCharStrcpy( liststr, "(setq j-num-list (quote (" ) ;
  ptr = liststr + 25 ;
  while( !IS_END_OF_STRING( *string ) ){
    MYCHAR_SET_CHARA( *ptr, 0x22 ) ;
    ptr ++ ;
    while( !IS_END_OF_STRING( *string ) &&
	   !IS_ASCII_EQUAL( *string, '/' ) ){
      *ptr ++ = *string ++ ;
    }
    if( IS_ASCII_EQUAL( *string, '/' ) )
      string ++ ;
    MYCHAR_SET_CHARA( *ptr, 0x22 ) ;
    ptr ++ ;
    MYCHAR_SET_CHARA( *ptr, ' ' ) ;
    ptr ++ ;
  }
  MYCHAR_SET_CHARA( *ptr, ')' ) ;
  ptr ++ ;
  MYCHAR_SET_CHARA( *ptr, ')' ) ;
  ptr ++ ;
  MYCHAR_SET_CHARA( *ptr, ')' ) ;
  ptr ++ ;
  MYCHAR_SET_END_OF_STRING( *ptr ) ;

#if defined(DEBUG)
  fprintf( stderr, "(j-num-list): " ) ;
  myCharFputstring( stderr, liststr ) ;
  fputc( '\n', stderr ) ;
  fflush( stderr ) ;
#endif
  if( ( entity = string2entity( liststr, NULL ) ) == NULL ){
#if defined(DEBUG)
    fprintf( stderr, "(j-num-list error): %s\n", liststr ) ;
#endif
    free( liststr ) ;
    skkinputlisp_garbagecollector() ;
    return False ;
  }
  free( liststr ) ;
  skkinputlisp_garbagecollector() ;
  return True ;
}

#if defined(MYEVAL_ONLY)
/*
 * ファイルから一行文字列を読み込み、JIS と思うのなら EUC に変換して文
 * 字列に入れる関数。
 */
int euc_fgets
( unsigned char *buffer, int len, FILE *fp, int echara,
  int coding_system, int ecflag )
{
  int c, status = 0, kflag = False ;

  while( len > 0 ){
    if( ( c = fgetc( fp ) ) == EOF )
      break ;
    if( coding_system ){
      /* JIS の場合には機能文字を調べる。*/
      switch( c ){
	/* 機能文字の開始コード。*/
      case 0x1b :
	status = c ;
	continue ;
	/* これらの文字は 0x1b に続く場合には機能文字である。*/
      case 0x24 :
      case 0x28 :
	if( status == 0x1b ){
	  status = c ;
	  continue ;
	} 
	break ;
	/* この文字は 0x1b,0x24/0x28 に続く場合には機能文字である。*/
      case 0x42 :
	if( status == 0x28 ){
	  kflag = False ;
	  status = 0 ;
	  continue ;
	} else if( status == 0x24 ){
	  kflag = True ;
	  status = 0 ;
	  continue ;
	}
	break ;
	/* それ以外の文字…。*/
      default :
	break ;
      }
      /* 漢字フラグが立っていたら、8bit目をたてる。*/
      if( kflag )
	c |= 0x80 ;
    }
    /* 改行コードを見てしまった場合には終了する。*/
    if( c == echara ){
      /* このフラグがたっていたら、END 文字が入ってしまう。*/
      if( ecflag ){
	*buffer ++ = echara ;
	len -- ;
      }
      break ;
    }
    /* 今回読み込んだ文字をしまう。*/
    *buffer ++ = c ;
    len -- ;
  }
  /* その余裕があれば、終端する。*/
  if( len > 0 )
    *buffer ++ = '\0' ;
  /* 読み残した文字数を返す。*/
  return len ;
}

/*
 * emacs-lisp にある expand-file-name に相当する関数。
 *-----
 * 一番最初に "~" があった場合に home directory に展開する機能を所持し
 * ている。ただし、wild-card なんとかには対応していない。
 * この関数を呼んだ結果は skk-local-jisyo-path に入ることになる。
 * skk-local-jisyo-path が NULL でなかったら、この関数を呼ばない方が良
 * いと思うが呼ぶ側では多分それをチェックできないので、ここでチェック
 * する。
 */
unsigned char *expand_file_name( unsigned char *path )
{
  unsigned char *ptr ;
  unsigned char *home ;
  int len = strlen( path ) ;

  /* "~" という home directory を表現する記号が入っていた場合の処理。*/
  if( *path == '~' ){
    /* HOME Directory が何処かを得る。*/
    home = getenv( "HOME" ) ;
    /* Home directory + 残りのパスの長さを malloc する。*/
    ptr = malloc( strlen( home ) + len + 1 ) ;
    if( ptr == NULL ){
      /* malloc 失敗…これは致命的なエラーなので継続動作はしない。*/
      fprintf( stderr, "Memory fault.\n" ) ;
      exit( 1 ) ;
    }
    /* "~" を展開して、書き直す。*/
    strcpy( ptr, home ) ;
    strcat( ptr, path + 1 ) ;
  } else {
    /* その必要が無い場合。*/
    ptr = ( unsigned char *)malloc( len + 1 ) ;
    strcpy( ptr, path ) ;
  }
  return ptr ;
}

/*
 * ファイルを眺めて、ESC が入っていれば JIS、8bit 目が立っているコード
 * が入っていたら EUC とか勝手に判断するかなり適当な関数。
 *----
 * skkinput-jisyo に変な漢字コードを入れないように…。
 */
int check_skkinput_jisyo_code( unsigned char *path )
{
  FILE *fp ;
  int c, ret ;

  /* 辞書ファイルが存在しない場合には、こちらで勝手にcoding systemを *
   * 選択する。*/
  if( ( fp = fopen( path, "rb" ) ) == NULL ){
    return CODING_SYSTEM_IS_EUC ;
  }
  ret = CODING_SYSTEM_IS_EUC ;
  while( ( c = fgetc( fp ) ) != EOF ){
    /* エスケープ文字を見付けた場合の処理。*/
    if( c == 0x1b )
      ret = CODING_SYSTEM_IS_JIS ;
    /* 8bit 目が立っていた場合の処理。*/
    if( c & 0x80 )
      break ;
  }
  fclose( fp ) ;
  return ret ;
}

/*
 * テストな人のメインです。
 */
int main( int argc, char *argv[] )
{
  struct skkinputlisp_entity *hoge ;
  struct myChar *string ;
  struct myChar myChar_buffer[1024];
  unsigned char buffer[ 1024 ] ;
  int i, j;
  int len ;

  /* メインループ。*/
  while( 1 ){
    printf( "> " ) ;
    if( fgets( buffer, 1024, stdin ) == NULL )
      break ;
    len = strlen( buffer ) ;
    if( buffer[ len - 1 ] != '\n' || buffer[ 0 ] == '\n' ){
      /* 長過ぎる行は却下する。*/
      continue ;
    } else {
      buffer[ len - 1 ] = '\0' ;
    }
    memset(myChar_buffer, 0, sizeof myChar_buffer);
    for (i = j= 0; i < len; i++, j++) {
	if (buffer[i] < 0x80) {
	    myChar_buffer[j].charset = CHARSET_ASCII;
	    myChar_buffer[j].chara = buffer[i];
	} else {
	    myChar_buffer[j].charset = CHARSET_JISX0208_1983;
	    myChar_buffer[j].chara = buffer[i] << 8 + buffer[i+1];
	    i++;
	}
    }
    myChar_buffer[j].charset = CHARSET_ASCII;
    myChar_buffer[j].chara = 0;

    string = convert_quote( myChar_buffer ) ;
    if( string != NULL ){
      hoge = string2entity( string, NULL ) ;
      if( hoge != NULL ){
	print_entity( hoge ) ;
	printf( "\n" ) ;
	/* ここでゴミ収集を行う。重いかも（笑）*/
	skkinputlisp_garbagecollector() ;
      }
      free( string ) ;
    }
  }
  return 0 ;
}

#endif
