/*
 * $Id: rk_read.c,v 2.5.2.1 2000/08/04 05:37:29 kaneda Exp $
 */
/*
WNN6 CLIENT LIBRARY--SOFTWARE LICENSE TERMS AND CONDITIONS


Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993

Preamble

These Wnn6 Client Library--Software License Terms and Conditions
 (the "License Agreement") shall state the conditions under which you are
 permitted to copy, distribute or modify the software which can be used
 to create Wnn6 Client Library (the "Wnn6 Client Library").  The License
 Agreement can be freely copied and distributed verbatim, however, you
 shall NOT add, delete or change anything on the License Agreement.

OMRON Corporation and OMRON Software Co., Ltd. (collectively referred to
 as "OMRON") jointly developed the Wnn6 Software (development code name
 is FI-Wnn), based on the Wnn Software.  Starting from November, 1st, 1998,
 OMRON publishes the source code of the Wnn6 Client Library, and OMRON
 permits anyone to copy, distribute or change the Wnn6 Client Library under
 the License Agreement.

Wnn6 Client Library is based on the original version of Wnn developed by
 Kyoto University Research Institute for Mathematical Sciences (KURIMS),
 OMRON Corporation and ASTEC Inc.

Article 1.  Definition.

"Source Code" means the embodiment of the computer code, readable and
 understandable by a programmer of ordinary skills.  It includes related
 source code level system documentation, comments and procedural code.

"Object File" means a file, in substantially binary form, which is directly
 executable by a computer after linking applicable files.

"Library" means a file, composed of several Object Files, which is directly
 executable by a computer after linking applicable files.

"Software" means a set of Source Code including information on its use.

"Wnn6 Client Library" the computer program, originally supplied by OMRON,
 which can be used to create Wnn6 Client Library.

"Executable Module" means a file, created after linking Object Files or
 Library, which is directly executable by a computer.

"User" means anyone who uses the Wnn6 Client Library under the License
 Agreement.

Article 2.  Copyright

2.1  OMRON Corporation and OMRON Software Co., Ltd. jointly own the Wnn6
 Client Library, including, without limitation, its copyright.

2.2  Following words followed by the above copyright notices appear
 in all supporting documentation of software based on Wnn6 Client Library:

  This software is based on the original version of Wnn6 Client Library
  developed by OMRON Corporation and OMRON Software Co., Ltd. and also based on
  the original version of Wnn developed by Kyoto University Research Institute
  for Mathematical Sciences (KURIMS), OMRON Corporation and ASTEC Inc.

Article 3.  Grant

3.1  A User is permitted to make and distribute verbatim copies of
 the Wnn6 Client Library, including verbatim of copies of the License
 Agreement, under the License Agreement.

3.2  A User is permitted to modify the Wnn6 Client Library to create
 Software ("Modified Software") under the License Agreement.  A User
 is also permitted to make or distribute copies of Modified Software,
 including verbatim copies of the License Agreement with the following
 information.  Upon modifying the Wnn6 Client Library, a User MUST insert
 comments--stating the name of the User, the reason for the modifications,
 the date of the modifications, additional terms and conditions on the
 part of the modifications if there is any, and potential risks of using
 the Modified Software if they are known--right after the end of the
 License Agreement (or the last comment, if comments are inserted already).

3.3  A User is permitted to create Library or Executable Modules by
 modifying the Wnn6 Client Library in whole or in part under the License
 Agreement.  A User is also permitted to make or distribute copies of
 Library or Executable Modules with verbatim copies of the License
 Agreement under the License Agreement.  Upon modifying the Wnn6 Client
 Library for creating Library or Executable Modules, except for porting
 a computer, a User MUST add a text file to a package of the Wnn6 Client
 Library, providing information on the name of the User, the reason for
 the modifications, the date of the modifications, additional terms and
 conditions on the part of the modifications if there is any, and potential
 risks associated with using the modified Wnn6 Client Library, Library or
 Executable Modules if they are known.

3.4  A User is permitted to incorporate the Wnn6 Client Library in whole
 or in part into another Software, although its license terms and
 conditions may be different from the License Agreement, if such
 incorporation or use associated with the incorporation does NOT violate
 the License Agreement.

Article 4. Warranty

THE WNN6 CLIENT LIBRARY IS PROVIDED BY OMRON ON AN "AS IS" BAISIS.
  OMRON EXPRESSLY DISLCIAMS ANY AND ALL WRRANTIES, EXPRESS OR IMPLIED,
 INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, IN CONNECTION WITH THE WNN6 CLIENT LIBRARY
 OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT LIBRARY.  IN NO EVENT
 SHALL OMRON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, PUNITIVE
 OR CONSEQUENTIAL DAMAGES OF ANY KIND WHATSOEVER IN CONNECTION WITH THE
 WNN6 CLIENT LIBRARY OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT
LIBRARY.

***************************************************************************
Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993
***************************************************************************

Comments on Modifications:
*/
/***********************************************************************
			rk_read.c
						88. 6.11  改 正
						93.10.19

	rk_main.c の部品。変換対応表の読み込みを担当。
***********************************************************************/
/*	Version 3.0
 */
#include "rk_multi.h"
#include <sys/types.h>
#include <sys/stat.h>

letter	onescan();
char	*ename();

extern	letter	*ltrgrow(), *ltrend(), letterpick(), *ltr1cut();
extern	char	*chrcat(), *strend();

static int termsscan(), evalandcpy(), eval1cpy(), partscan(),
  atermscan(), serfun(), hensrc_tourk(), blankpass(),
  modsrcL(), chkL_get_int();
static void ERRLIN(), ERHOPN(),
  ltr1tostr(), ERRHYO(), vchk(), rangeset(), de_bcksla(), 
  listscan(), singleqscan(), doubleqscan();
static void readhyo();
static int evlis();
letter	*rangekettei();
extern void BUGreport(), choosehyo(), readmode();
extern int ltrcmp(), ltrstrcmp(), readfnm(), fixednamep();

#define IHENSU (1 << 24) /* 内部表現の上位１バイトで、変数を表す */
#define IKANSU (2 << 24) /*	      〃	      関数を表す */
#define IMODNM (3 << 24) /*	      〃	      モード名を表す */

#define ENDOF_NestFileArea ((FILE *)~0)
	 /** includeファイルのディスクリプタ格納エリアのエンドマーク*/


 /**	一行読み込み。一字も読み込まないうちにEOFにつきあたったら0を返す。
	但しincludeを考慮している。対応表には空白文字以外のコントロール文字は
	生では混じらないものとし、混じっていたらチェックする。*/
int
readln(buf, cur_rk)
uns_chr *buf;
ARGS *cur_rk;
{
	register uns_chr *p;
	register int	c;

	if(NULL == *base){
		*buf = '\0';
		return(0);
	}

	p = buf;
	while(1){
		while(EOF == (c = getc(*base))){
			fclose(*base);
			if(NULL == *--base){
				c = EOF;
				break;
			}
		}
		if(c == EOF || c == '\n') break;

		if(is_cntrl(c) && !isspace(c)){
			sprintf(hcurread, "\\%03o", c);
			ERRLIN(21, cur_rk);
		}
		*p++ = c;
	}
	*p = '\0';
	return(p != buf || c != EOF);
}

letter	*memptr, *ltrbufptr, *hensumei, *hen_iki, *term, **henptr;
letter	*dummy;
struct	dat	*datptr;
struct	hensuset
{
	unsigned	regdflg : 1;	/* 既登録の変数を表す */
	unsigned	curlinflg : 1;	/* 現在行に既出の変数を表す */
	unsigned	constflg : 1; /* 定数として定義されたことを表す */
	letter		*name;
	letter		*range;
} *hentourkptr, *henorg;

 /** 与えられたファイルがディレクトリなら非0を返す */
int
isdir(fnm)
char	*fnm;
{
	struct	stat	statbuf;
/*
	return(stat(fnm, &statbuf) == 0 && (statbuf.st_mode & S_IFDIR));
*/
	return(stat(fnm, &statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR));
}

 /**	nameで与えられた名の変換対応表をオープンする。固定名と見なされない
	名前（fixednamep()参照）に対しては、サーチパスを見る。その場合、
	オープンに成功したら、パス名を *dirnamptrに入れて返る。その他の場合は
	*dirnamptrに空文字列が入る。*errcodには次のエラーコードが入る。
	与えられたファイルがディレクトリの時1（サーチパスを探した時は3）、
	ファイルをオープンできない時2（同4）。*/
FILE *
trytoopen(name, dirnamptr, errptr, cur_rk)
char	*name, **dirnamptr;
int	*errptr;
ARGS *cur_rk;
{
	char	**src, taio_fnm[REALFN];
	FILE	*opened;

	*dirnamptr = nulstr;
	*errptr = 0;

	if(fixednamep(name)){
		if(isdir(name)){
			*errptr = 1;
			return(NULL);
		}
		if(NULL == (opened = fopen(name, "r"))){
			*errptr = 2;
			return(NULL);
		}
		if(flags & RK_VERBOS){
			fprintf(stderr, "romkan: using Taio-hyo %s ...\r\n",
				name);
		}
		return(opened);
	} else {
		for(src = pathmeiorg; *src != NULL; src++){
			strcpy(taio_fnm, (*dirnamptr = *src));
			strcat(taio_fnm, name);

			if(isdir(taio_fnm)){
				*errptr = 3;
				return(NULL);
			}
			if(NULL == (opened = fopen(taio_fnm, "r"))) continue;

			 /* Now Taio-hyo found */
			if(flags & RK_VERBOS)
				fprintf(stderr,
					"romkan: using Taio-hyo %s ...\r\n",
					taio_fnm);
			return(opened);
		}
		if(flags & RK_VERBOS){ /* Taio-hyo not found */
			char	*p, *q;

			fprintf(stderr, "no %s in", name);
			for(src = pathmeiorg; *src != NULL; src++){
				fputc(' ', stderr);
				q = *src;
				if(*q == KUGIRI && *(q + 1) == '\0') q++;
				 else q = strend(q);
				for(p = *src; p < q; p++)
					fputc(*p, stderr);
			}
			fprintf(stderr, ".\n");
		}
		*dirnamptr = nulstr;
		*errptr = 4;
		return(NULL);
	}
}

 /** 表全部の読み込み */
void
readdata(memory, data, hensudefhyo, modf, cur_rk)
letter	*memory;	/* 対応表の内部表現を入れる配列の先頭番地を渡される */
struct	dat	*data;	/* 対応表の行ごとのデータを入れる配列の番地 */
letter	**hensudefhyo;	/* 変数定義のデータを入れる配列の番地 */
char	*modf;		/* モード定義表の名又はそのパス名が入っている */
ARGS *cur_rk;
{
	int	i, j;
	char	*hyomeibgn[HYOMAX];
	 /* 表の名へのポインタを入れる配列 */
	char	hyomeimem_[HYOMEI];
	 /* 表の名の実際の文字列を入れる配列 */
	char	*pathmeibgn[PTHMAX];
	 /* サーチパス名へのポインタを入れる配列 */
	char	pathmeimem_[PTHMEI];
	 /* サーチパス名の実際の文字列を入れる配列 */
	char	modfnm[REALFN];
	 /* モード表のファイル名をここへコピる のちにはそのパス名が入る */

	memptr = memory;
	datptr = data;
	henptr = hensudefhyo;
	*(pathmeiptr = pathmeiorg = pathmeibgn) = NULL;
	*(pathmeimem = pathmeimem_) = '\0';
	*(hyomeiptr = hyomeiorg = hyomeibgn) = NULL;
	*(hyomeimem = hyomeimem_) = '\0';
	*(modmeiptr = modmeibgn) = NULL;
	*(modmeimem = modmeimem_) = '\0';
	*(dspnamptr = dspnambgn) = NULL;
	*(dspcod = dspcod_) = '\0';
	*(naibu = naibu_) = '\0';

	strcpy(modfnm, modf);
	     /* modfnmが与えたファイル名。パス名だけ与えられたら、デフォルトの
		モード表名"mode"をつなぐ。KUGIRI＝ディレクトリの区切り文字 */

	if(*modfnm == '\0' || *(strend(modfnm)) == KUGIRI){
		strcat(modfnm, "mode");
	} else if(isdir(modfnm)){
		chrcat(modfnm, KUGIRI);
		strcat(modfnm, "mode");
	}

	curdir = nulstr;
	readmode(curfnm = modfnm, cur_rk);

	for(i = 0; hyomeiorg[i] != NULL; i++){
		int	err;

		for(j = 0; j < FILNST; j++) nestfile[j] = NULL;
		nestfile[FILNST - 1] = ENDOF_NestFileArea;
		base = nestfile + 1;

		*base = trytoopen(curfnm = hyomeiorg[i], &curdir, &err, cur_rk);
		if(err){
			switch(err){
				case 1:
				case 3: ERHOPN(1, cur_rk);
				case 2:
				case 4: ERHOPN(0, cur_rk);
			}
		}
		readhyo(i, cur_rk);
	}

	hyo_n[i] . data = NULL;
	choosehyo(cur_rk);
}

 /** ファイル名からパス名を除いた部分の先頭を返す。*/
char	*ename(s)
char	*s;
{
	char	*p;

	p = strrchr(s, KUGIRI);
	return(p == NULL ? s : p + 1);
}

 /**	ファイル名のチェック。先頭（パス名は除く）が'1'〜'3'でないといけない。
	正当なものなら1〜3（前・本・後処理表の区別を表す）を返し、そうでないと
	0を返す。*/
int
filnamchk(s)
char	*s;
{
	char	c;

	c = *(ename(s)) - '0';
	return((1 <= c && c <= 3) ? c : 0);
}

 /**	linbufに入っているunsigned charの列をletterの列にしてltrbufに入れる。
	エンドマークはEOLTTRになる。flgが非0の時は、先頭の空白文字は飛ばす。*/
void
ustrtoltr(linbuf, ltrbuf, flg, cur_rk)
uns_chr *linbuf;
int	flg;
register letter *ltrbuf;
ARGS *cur_rk;
{
	register letter l;

	if(flg){
		while(l = letterpick(&linbuf, cur_rk), is_eolsp(l)){
			if(l == EOLTTR){
				*ltrbuf = EOLTTR;
				return;
			}
		}
		*ltrbuf++ = l;
	}
	while((*ltrbuf++ = letterpick(&linbuf, cur_rk)) != EOLTTR);
}

 /**	letterの列を文字列にコンバート。二つのポインタが同一番地であっても
	動作を保証すること。*/
void
ltrtostr(ltrbuf, linbuf)
char	*linbuf;
letter	*ltrbuf;
{
	letter	l;

	while((l = *ltrbuf++) != EOLTTR) ltr1tostr(l, &linbuf);
	*linbuf = '\0';
}

 /** letterを文字列にコンバート */
static void
ltr1tostr(l, sptr)
char	**sptr;
letter	l;
{
	int	i;

	for(i = 0; i < 3 && 0 == (l & (0xff000000)); i++) l <<= 8;
	for(; i < 4; i++){
		*(*sptr)++ = (char)(l >> 24);
		l <<= 8;
	}
}

 /** 変数の「現在行既出フラグ」を全てクリア */
void
hen_useflgclr(hensu)
struct	hensuset	*hensu;
{
	for(; hensu -> name != NULL; hensu++)
		hensu -> curlinflg = 0; /* 現在行に未出 */
}

 /** 対応表一つ読み込み */
static void
readhyo(n, cur_rk)
int	n;
ARGS *cur_rk;
{
	uns_chr linbuf[LINSIZ];
	letter	ltrbuf[LINSIZ], *lp;
	letter	termbuf[SIZALL]; /* エラーを考慮して、表のサイズ分取っておく*/
	letter	dummybuf[TRMSIZ], hensumei_[VARLEN], hen_iki_[SIZALL];
	struct	hensuset	hensu[VARMAX];
	int	m, hyosw, rsltyp[3];

	hcurread = (char *)linbuf; /* エラー処理用 */
	ltrbufbgn = ltrbuf;

	*(hensumei = hensumei_) = EOLTTR;
	*(hen_iki = hen_iki_) = EOLTTR;
	(henorg = hentourkptr = hensu) -> name = NULL;
	dummy = dummybuf;

	hyo_n[n] . hensudef = henptr;
	hyo_n[n] . data = datptr;

	hyosw = hyoshu[n];
	while(readln(linbuf, cur_rk)){
		hen_useflgclr(henorg);
		ustrtoltr(linbuf, ltrbuf, 1, cur_rk);
		ltrbufptr = ltrbuf;

		for(m = 0; termsscan(&ltrbufptr, term = termbuf, 1, cur_rk); m++){
			 /* mは、何番目の項目を見ているかを表す */
			if(*term == ';') break; /* 注釈行 */
			if(m == 3) ERRLIN(15, cur_rk);
			if(m != 0 && rsltyp[0] == 4) ERRLIN(12, cur_rk);

			datptr -> code[m] = memptr;
			if((rsltyp[m] = evalandcpy(&term, m, cur_rk)) == 4){
				if(m) ERRLIN(14, cur_rk);
			 /* 宣言は最初の項目にしか来れない。
			    funstr[]のappearフラグでもチェックしているが
			    将来のために一応ここにもチェックを入れておく。*/
			} else {
			 /* 宣言の時には内部表現へのポインタは進めない */
				totail(memptr);
				memptr++;
			}
		}

		if(m != 0 && rsltyp[0] != 4){
			for( /* m=? */ ; m < 3; m++){
				datptr -> code[m] = nil;
				rsltyp[m] = -1; /* doesn't exist */
			}
			datptr++;

 /* rsltyp: 0=文字項 1=文字列連 2=データ連 3=機能項 4=宣言項 -1=存在せず */
			switch(hyosw){
		   /* 前・後処理は、表の内容に制限がある。それを検査 */
				case 1:
					if(!(rsltyp[0] == 0 &&
					     rsltyp[1] == 0 && 
					     rsltyp[2] == -1
					    ))
						ERRLIN(17, cur_rk);
					break;
				case 2:
					if(rsltyp[1] == 3 && rsltyp[2] != -1)
						ERRLIN(19, cur_rk);
					break;
				case 3:
					if(!(rsltyp[0] == 0 &&
					     (rsltyp[1] == 0 ||
					      rsltyp[1] == 1) &&
					     rsltyp[2] == -1
					    ))
						ERRLIN(18, cur_rk);
					break;
				default:
					BUGreport(10);
			}

		}
	}

	(datptr++) -> code[0] = NULL;

		/* 変数登録ここでまとめてする */
	for(lp = hen_iki_; lp < hen_iki; ) *memptr++ = *lp++;
	for(hentourkptr = henorg; hentourkptr -> name != NULL;
	    hentourkptr++){
		if(hentourkptr -> regdflg == 0) ERRHYO(0, cur_rk);
		*henptr++ = memptr - (lp - hentourkptr -> range);
	}
	*henptr++ = NULL;

	/* ここで fclose(*base); は不要。readln内ですんでいる */
}

 /**	変換対応表の項目一つを、解釈して、内部形式のデータエリアにコピーする。
	返す値は、解釈した項目が文字項なら0、それ以外で文字列連なら1、それ以外
	でデータ連なら2、機能項なら3、宣言項なら4。それ以外はエラー。*/
static int
evalandcpy(socp, m, cur_rk)
register letter **socp; /* 項目へのポインタ（へのポインタ）*/
int	m;   /* 対応表の何番目の項目を見ているかを表す。入力コード部を
		見ているときは0、出力コード部なら1、バッファ残り部なら2 */
ARGS *cur_rk;
{
#define TYPMAX	5

	char	exist[TYPMAX], total;
	 /* existは、それぞれタイプ0〜4の項の出現のフラグ（eval1cpy()参照）。
	    totalは全体としての出現フラグ。どちらも、1=未出 2=一回出 その他の
	    時は下2ビット0 */
	int	type;

#define TIME_0(flag) ((flag) == 1)
#define TIME_1(flag) ((flag) == 2)
#define TIME_n(flag) (((flag) & 3) == 0)

	total = 1;
	for(type = 0; type < TYPMAX; type++) exist[type] = 1;

	while(!is_eolsp(**socp)){
		if(!(0 <= (type = eval1cpy(socp, m, 0, cur_rk)) && type < TYPMAX))
			BUGreport(3);
		exist[type] <<= 1;
		total <<= 1;
	}

	if(TIME_0(total))
		BUGreport(13); /* 項目が空ならevalandcpyは実行しない筈 */
	if(!TIME_0(exist[3]) || !TIME_0(exist[4])){
		if(TIME_n(total)) ERRLIN(9, cur_rk);
		return(type); /* 3又は4。typeが値を保持している筈 */
	}
	if(TIME_1(total) && TIME_1(exist[0])) return(0);
	return(!TIME_0(exist[2]) ? 2 : 1);
}

 /**	対応表の項目の中の項一つを解釈し、内部形式のデータエリアにコピーし、
	それのタイプ（文字項=0 文字列項=1 特殊関数項=2 機能項=3 宣言項=4）を
	返す。flgが非0なら、再帰的に呼ばれたことを意味し、その場合、
	現在行に未出の変数を検出したらエラー。また、mが非0のとき（入力コード部
	以外の所を見ている時）も、現在行に未出の変数を検出したらエラー。*/
static int
eval1cpy(socp, m, flg, cur_rk)
letter	**socp; /* flg以外の引数の意味はevalandcpyと同じ */
int	m, flg;
ARGS *cur_rk;
{
	letter	t1buf[TRMSIZ], *t1bufp;

	t1bufp = t1buf;

	*memptr = EOLTTR;
	switch(partscan(socp, t1bufp, cur_rk)){
		case 1: /* 単文字 */
			memptr = ltrgrow(memptr, t1bufp);
			*memptr = EOLTTR;
			return(0);
		case 2: /* 引用文字 */
			t1bufp++;
			*memptr++ = onescan(&t1bufp, dummy, cur_rk);
			*memptr = EOLTTR;
			return(0);
		case 3: /* 引用文字列 */
			t1bufp++;
			while(*t1bufp != '"'){
				*memptr++ = onescan(&t1bufp, dummy, cur_rk);
			}
			*memptr = EOLTTR;
			return(1);
		case 0: /* リスト */
			return(evlis(m, &t1bufp, flg, cur_rk));
			 /* evlis内で *memptr = EOLTTR; をしている。*/
		default:
			BUGreport(4);
			return(-1);
			 /*NOTREACHED*/
	}
	/*NOTREACHED*/
}

#define bitchk(x, n) ((x) & (1 << (n)))

#define get_ltr(lp) (*(lp)++)
#define unget_ltr(l, lp) (*--(lp) = (l))

 /** globalなポインタから指されているletter列から一文字取ってくる。*/
letter
get1ltr(cur_rk)
ARGS *cur_rk;
{
	return(get_ltr(lptr));
}

letter
unget1ltr(l, cur_rk)
letter	l;
ARGS *cur_rk;
{
	return(unget_ltr(l, lptr));
}

int
int_get1ltr(cur_rk)
ARGS *cur_rk;
{
    return((int)(get1ltr(cur_rk)));
}

int
int_unget1ltr(c, cur_rk)
letter c;
ARGS *cur_rk;
{
    return((int)(unget1ltr((letter) c, cur_rk)));
}
 /** 汚いことこの上なし！なぜ関数の型のcastができないの？
    「(int ()) get1ltr」と書きたい！ */

 /**	includeファイル名のletter列をstringに取り出す作業を、letter列の終わり
	まで続ける。flg & 01が非0なら、'/'でも終了。*/
letter
getfrom_dblq(socp, destp, flg, cur_rk)
letter	**socp;
char	**destp;
int	flg;
ARGS *cur_rk;
{
	letter	l;

	while(**socp != EOLTTR && !(flg & 01 && **socp == KUGIRI)){
		if (**socp == '\\') *(*destp)++ = '\\';
		l = onescan(socp, dummy, cur_rk);
		ltr1tostr(l, destp);
	}
	*(*destp)++ = '\0';
	return(**socp);
}

int
getfrom_lptr(sptr, flg, cur_rk)
char	**sptr;
int	flg;
ARGS *cur_rk;
{
	return((int)getfrom_dblq(&lptr, sptr, flg, cur_rk));
}

 /**	リストを解釈して内部表現にする。返値は、そのリストのタイプを表す数。
	文字変数項又は文字関数項:0 文字列関数項:1 特殊関数項:2
	機能項:3 宣言項:4 */
static int
evlis(m, socp, flg, cur_rk)
letter	**socp; /* 引数の意味はeval1cpyを参照 */
int	m, flg;
ARGS *cur_rk;
{
	int	fnnum, hennum, i;
	letter	t1buf[TRMSIZ];

	(*socp)++; /* '('をスキップ */
	atermscan(socp, t1buf, 3, cur_rk);

	fnnum = serfun(t1buf);
	if(fnnum != -1 && !bitchk(func[fnnum] . appear, m)) ERRLIN(14, cur_rk);
	 /* mの値によって、現れてはいけない所への出現かどうか見ている。*/

	switch(fnnum){ /* defaultの所以外は func[fnnum].argnumを使ってない */
		case -1: /* 変数 */
			vchk(t1buf, cur_rk);
			atermscan(socp, dummy, 2, cur_rk); /* あればERR */
			hennum = hensrc_tourk(t1buf, ((m==0 && !flg)? 0 : 1), cur_rk);
			*memptr++ = (henorg[hennum] . constflg ? 
				     *(henorg[hennum].range) : hennum|IHENSU);
			break;

		case 0: /* fn No.0 defvar */
			atermscan(socp, t1buf, 3, cur_rk);
			if(*t1buf == '('){
				letter	*soc2, t1buf2[TRMSIZ], t1buf3[TRMSIZ];
				letter	*common_hen;

				atermscan(socp, t1buf3, 3, cur_rk);

				soc2 = t1buf + 1; /* skip '(' */

				atermscan(&soc2, t1buf2, 3, cur_rk);
				vchk(t1buf2, cur_rk);
				if(-1 != serfun(t1buf2)) ERRLIN(11, cur_rk);
				hennum = hensrc_tourk(t1buf2, 2, cur_rk);
				common_hen = rangekettei(hennum, t1buf3, cur_rk);

				while(atermscan(&soc2, t1buf2, 0, cur_rk)){
					vchk(t1buf2, cur_rk);
					if(-1 != serfun(t1buf2)) ERRLIN(11, cur_rk);
					hennum = hensrc_tourk(t1buf2, 2, cur_rk);
					rangeset(hennum, common_hen, cur_rk);
				}
			} else {
				vchk(t1buf, cur_rk);
				if(-1 != serfun(t1buf)) ERRLIN(11, cur_rk);
				hennum = hensrc_tourk(t1buf, 2, cur_rk);
			  /* defvar・defconstの変数名の重複を避けるため */
				atermscan(socp, t1buf, 3, cur_rk);
				rangekettei(hennum, t1buf, cur_rk);
			}
			atermscan(socp, dummy, 2, cur_rk);
			break;
		case 36: /* fn No.36 defconst */
			atermscan(socp, t1buf, 3, cur_rk);
			vchk(t1buf, cur_rk);
			if(-1 != serfun(t1buf)) ERRLIN(11, cur_rk);

			hennum = hensrc_tourk(t1buf, 6, cur_rk);
			  /* defvar・defconstの変数名重複を避けるため */

			rangeset(hennum, hen_iki, cur_rk);

			blankpass(socp, 1, cur_rk);
			if(*(*socp)++ != '\'') ERRLIN(8, cur_rk);
			*hen_iki++ = onescan(socp, dummy, cur_rk);
			(*socp)++; /*「'」が閉じていることの検査は済んでいる*/
			*hen_iki++ = EOLTTR; /* needed? */
			*hen_iki = EOLTTR;

			atermscan(socp, dummy, 2, cur_rk);
			break;

		case 1: /* fn No.1 include */
			{
				char	fnmtmparea[REALFN], *s, *dirnamptr;
				int	dummyc = 0, err;

				blankpass(socp, 1, cur_rk);
				if(3 != partscan(socp, t1buf, cur_rk)) ERRLIN(22, cur_rk);
				atermscan(socp, dummy, 2, cur_rk);
				 /* 余分にあればERR */

				ltr1cut(lptr = t1buf + 1);
				*(s = fnmtmparea) = '\0';
				err = readfnm(int_get1ltr, int_unget1ltr,
					      getfrom_lptr, &s, &dummyc, cur_rk);

				if(err){
					hcurread = s;
					switch(err){
						case 1:
						case 3: ERRLIN(25, cur_rk);
						case 2: ERRLIN(26, cur_rk);
						case 4: ERRLIN(27, cur_rk);
					}
				}
				de_bcksla(fnmtmparea, fnmtmparea);

				if(*++base == ENDOF_NestFileArea){
					base--;
					ERRLIN(23, cur_rk);
				}
				*base= trytoopen(fnmtmparea, &dirnamptr,&err, cur_rk);
				if(err){
					switch(err){
						case 1:
						case 3:
						case 2:
						case 4: base--;
							ERRLIN(24, cur_rk);
					}
				}
			}
			break;

		 /* モード名一つを引数に取るもの */
		case 4: /* fn No.4〜6 off,on,switch */
		case 5:
		case 6:
		case 20: /* fn No.20,21 if,unless */
		case 21:
			*memptr++ = fnnum | IKANSU;
			atermscan(socp, t1buf, 3, cur_rk);
			*memptr++ = modsrcL(t1buf, cur_rk) | IMODNM;
			atermscan(socp, t1buf, 2, cur_rk);
			break;

		 /* モード名と文字 一つずつを引数に取るもの */
		case 37: /* fn No.37〜43 setmodeなど */
		case 38:
		case 39:
		case 40:
		case 41:
		case 42:
		case 43:
			{
				int	err, n;
				modetyp	stat;

				*memptr++ = fnnum | IKANSU;
				atermscan(socp, t1buf, 3, cur_rk);
				*memptr++ = (n = modsrcL(t1buf, cur_rk))| IMODNM;
				atermscan(socp, t1buf, 3, cur_rk);
				err = chkL_get_int(t1buf, &stat,
							 modesw[n] . moderng);
				if(err != 0) ERRLIN(29, cur_rk);
				*memptr++ = stat;
				atermscan(socp, t1buf, 2, cur_rk);
				break;
			}

		 /* 普通（引数を取らないものを含む） */
		default: /* toupper,tolower… */
			*memptr++ = fnnum | IKANSU;
			*memptr = EOLTTR;
			for(i = 0; i < func[fnnum] . argnum; i++){
				blankpass(socp, 1, cur_rk);
				if(eval1cpy(socp, m, 1, cur_rk) != 0) ERRLIN(13, cur_rk);
			}
			atermscan(socp, dummy, 2, cur_rk); /* 余分にあればERR */
			break;
	}
	*memptr = EOLTTR;
	return(fnnum == -1 ? 0 : func[fnnum] . fntype);
}

 /** 文字列中の「\」を抜く */
static void
de_bcksla(s, r)
char	*s, *r;
{
	for(; *s; *r++ = *s++) if(*s == '\\') s++;
	*r = '\0';
}

 /**	defvarの第二引数（shikiに入る）を解釈して、その変数の変域を決定する。
	変数列の最後にエンドマークもちゃんと入る。返値は、変域を格納した
	所へのポインタ。*/
letter	*
rangekettei(num, shiki, cur_rk)
letter	*shiki;
int	num; /* 変域を決定しつつある変数の内部番号 */
ARGS *cur_rk;
{
	letter	hyoukabuf[TRMSIZ];

	rangeset(num, hen_iki, cur_rk);
	*hen_iki = EOLTTR;

	if(*shiki++ != '(') ERRLIN(8, cur_rk);
	atermscan(&shiki, hyoukabuf, 1, cur_rk);

	if(!ltrstrcmp(hyoukabuf, "all")){
		*hen_iki++ = VARRNG;
		*hen_iki++ = 0;
		*hen_iki++ = LTRHUG; /* 変域は全文字 */
		*hen_iki++ = EOLTTR;
		*hen_iki = EOLTTR;
		atermscan(&shiki, dummy, 2, cur_rk); /* 余分にあればERR */
	} else 
	if(!ltrstrcmp(hyoukabuf, "between")){
		int	i;

		*hen_iki++ = VARRNG;
		while(blankpass(&shiki, 1, cur_rk), *shiki != ')'){
			for(i = 1; i <= 2; i++){
				switch(*shiki){
					case '\'':
						shiki++;
						*hen_iki++ =
						       onescan(&shiki, dummy, cur_rk);
						shiki++;
						break;
					case ')':
					case '"':
					case '(': ERRLIN(8, cur_rk);
					default:
						*hen_iki++ = *shiki++;
				}
				if(i < 2){
					if(!is_eolsp(*shiki)) ERRLIN(8, cur_rk);
					blankpass(&shiki, 1, cur_rk);
				}
			}
		}
		*hen_iki++ = EOLTTR;
		*hen_iki = EOLTTR;
	} else
	if(!ltrstrcmp(hyoukabuf, "list")){
		while(blankpass(&shiki, 1, cur_rk), *shiki != ')'){
			switch(*shiki){
				case '"':
				case '(': ERRLIN(8, cur_rk);
				case '\'':
					shiki++;
					*hen_iki++ = onescan(&shiki, dummy, cur_rk);
					shiki++; /* 本当に「'」が閉じているか
					 どうかの検査はもう済んでいる。*/
					break;
				default:
					*hen_iki++ = *shiki++;
			}
			if(!is_eolsp(*shiki)) ERRLIN(8, cur_rk);
		}
		*hen_iki++ = EOLTTR;
		*hen_iki = EOLTTR;
	} else {
		ERRLIN(8, cur_rk); /* 将来はこの他の構文も許す予定であった */
	}

	return(henorg[num] . range);
}

 /**	num番目の変数の変域を指すべきポインタの指し先を決定し、その変数を
	既登録状態にする。*/
static void
rangeset(num, range, cur_rk)
letter	*range; /* 変域の入る場所のポインタ */
int	num;
ARGS *cur_rk;
{
	henorg[num] . range = range;
	henorg[num] . regdflg = 1;
}

 /**	nameで指定された名の変数を探し、なければ登録。変数名の最後に
	エンドマークもちゃんと入る。
	flg & 01が非0の時、その名の変数が現在行に未出ならエラー（constとして
	既登録の時を除く）。また flg & 02が非0の時、その名の変数が既定義なら
	エラー（defvarの重複チェック用）。flg & 04が非0ならconstとして登録。*/
static int
hensrc_tourk(name, flg, cur_rk)
letter	*name;
int	flg;
ARGS *cur_rk;
{
	int	i;

	for(i = 0; henorg[i] . name != NULL; i++){
		if(ltrcmp(henorg[i] . name, name)) continue;
		 /* found */
		if(flg & 04) ERRLIN(28, cur_rk);
		if(flg & 02 && henorg[i] . regdflg != 0) ERRLIN(10, cur_rk);
		if(flg & 01 && henorg[i] . curlinflg == 0 &&
				 henorg[i] . constflg == 0)
			ERRLIN(5, cur_rk);
		henorg[i] . curlinflg = 1;
		return(i);
	}
	if(henorg + i != hentourkptr) BUGreport(5);

	 /* ここへ来たということは、初出の変数ということ。当然、flg & 01が
	    非0ならエラー。*/
	if(flg & 01) ERRLIN(5, cur_rk);
	hentourkptr -> name = hensumei;
	hentourkptr -> curlinflg = 1;
	hentourkptr -> regdflg = 0; /* 初出だからrangeのdefは未だの筈 */
	hentourkptr -> constflg = ((flg & 04) != 0);
	(++hentourkptr) -> name = NULL;
	hensumei = ltrgrow(hensumei, name);
	*++hensumei = EOLTTR;

	return(i);
}

 /** 組み込み関数・機能名に対してはその番号を、そうでないものなら-1を返す */
static int
serfun(lp)
register letter *lp; /* 関数・機能名もしくは変数名 */
{
	register int	i;

	for(i = 0; func[i] . fnname != NULL; i++){
		if(! ltrstrcmp(lp, func[i] . fnname)) return(i);
	}
	return(-1);
}

 /** 変数の名前のチェック おかしいとエラー */
static void
vchk(lp, cur_rk)
letter	*lp;
ARGS *cur_rk;
{
	if(is_digit(*lp)) ERRLIN(3, cur_rk);
	for(; *lp != EOLTTR; lp++){
	  /*	if(is_lower(*lp)) *lp = to_upper(*lp);	*/
		if(!is_alnum(*lp) && *lp != '_') ERRLIN(3, cur_rk);
	}
}

 /**	一項目を取り出す。取り出しに成功すると1を返す。flgが非0の時は、')'が
	見つかるとエラー、';'はそれだけで一項目扱い。*/
static int
termsscan(socp, dest, flg, cur_rk)
register letter **socp, *dest;
	 /* socpの指しているポインタが指している所から取り出してdestに入れる。
	    その後、socpが指しているポインタを進める。このファイルの **scan()
	    という関数は全てそうなってる。*/
int	flg;
ARGS *cur_rk;
{
	letter	*bgn;

	bgn = dest;

	if(blankpass(socp, 0, cur_rk) == 0){
		if(flg && **socp == ';'){
			*dest++ = *(*socp)++;
		} else
		while(!is_eolsp(**socp)){
			if(**socp == ')'){
				if(flg) ERRLIN(0, cur_rk);
				break;
			} else {
				partscan(socp, dest, cur_rk);
				totail(dest);
			}
		}
	}

	*dest = EOLTTR;
	return(bgn != dest);
}

 /**	リスト一つか、単純項の一まとまりを取り出す。成功したら1を返す。
	flgが1のとき、')'が見つかるとエラー。
	flgが2のとき、取り出しに成功したらエラー。
	flgが3のとき、取り出しに失敗したらエラー。*/
static int
atermscan(socp, dest, flg, cur_rk)
register letter **socp, *dest;
int	flg;
ARGS *cur_rk;
{
	letter	*bgn;
	int	found;

	bgn = dest;

	if(blankpass(socp, 0, cur_rk) == 0){
		if(**socp == '('){
			listscan(socp, dest, cur_rk);
			totail(dest);
		} else {
			while(!is_eolsp(**socp) && **socp != '('){
				if(**socp == ')'){
					if(flg == 1) ERRLIN(0, cur_rk);
					break;
				} else {
					partscan(socp, dest, cur_rk);
					totail(dest);
				}
			}
		}
	}

	*dest = EOLTTR;

	found = (bgn != dest);
	if((!found && (flg == 3)) || (found && (flg == 2))) ERRLIN(7, cur_rk);
	return(found);
}

 /**	項一つを取り出す。取り出したものがリストなら返値は0、単文字なら1、
	引用文字なら2、引用文字列なら3。*/
static int
partscan(socp, dest, cur_rk)
register letter **socp, *dest;
ARGS *cur_rk;
{
	switch(**socp){
		case '(':
			listscan(socp, dest, cur_rk);
			return(0);
		case '\'':
			singleqscan(socp, dest, cur_rk);
			return(2);
		case '"':
			doubleqscan(socp, dest, cur_rk);
			return(3);
		default:
			*dest++ = *(*socp)++;
			*dest = EOLTTR;
			return(1);
	}
}

 /** シングルクォート表現一つを取り出す。*/
static void
singleqscan(socp, dest, cur_rk)
letter	**socp, *dest;
ARGS *cur_rk;
{
	*dest++ = *(*socp)++;
	onescan(socp, dest, cur_rk);
	totail(dest);
	if((*dest++ = *(*socp)++) != '\'') ERRLIN(1, cur_rk);

	*dest = EOLTTR;
}

 /** ダブルクォート表現一つを取り出す。*/
static void
doubleqscan(socp, dest, cur_rk)
letter	**socp, *dest;
ARGS *cur_rk;
{
	*dest++ = *(*socp)++;
	while(**socp != '"'){
		if(**socp == EOLTTR) ERRLIN(1, cur_rk);
		onescan(socp, dest, cur_rk);
		totail(dest);
	}
	*dest++ = *(*socp)++;

	*dest = EOLTTR;
}

 /**	8・10・16進コード用キャラクタを実際のコードに直す。入力のチェックは
	せず、英文字と数字以外の入力に対しては単に0を返す。*/
int
ltov(l)
letter	l;
{
	if(is_upper(l)) return(l - 'A' + 10);
	if(is_lower(l)) return(l - 'a' + 10);
	if(is_digit(l)) return(l - '0'); else return(0);
}

 /** ltovの逆 */
letter	vtol(l)
letter	l;
{
	if(BASEMX <= l) return('*');
	return(l + (l < 10 ? '0' : 'A' - 10));
}

 /**	シングル・ダブルクォートの中での一文字取り出し。
	「^」によるコントロールコード表現、「\」による8・10・16進表現にも
	対応。「\」表現は、「\［o又はd又はx］数字の並び［;］」である。*/
letter
onescan(socp, dest, cur_rk)
letter	**socp, *dest;
ARGS *cur_rk;
{
	letter	l, realcode;
	int	digflg;

	switch(realcode = *dest++ = *(*socp)++){
		case '^':
			if(!(' ' <= (l = *(*socp)++) && l < '\177'))
			    ERRLIN(2, cur_rk);
			realcode = ((*dest++ = l) == '?' ? '\177' : l & 0x1f);
			break;
		case '\\':
			digflg = 0;
			switch(**socp){
				case 'n':
					*dest++ = *(*socp)++; realcode = '\n';
					break;
				case 't':
					*dest++ = *(*socp)++; realcode = '\t';
					break;
				case 'b':
					*dest++ = *(*socp)++; realcode = '\b';
					break;
				case 'r':
					*dest++ = *(*socp)++; realcode = '\r';
					break;
				case 'f':
					*dest++ = *(*socp)++; realcode = '\f';
					break;
				case 'e':
				case 'E':
					*dest++ = *(*socp)++; realcode=ESCCHR;
					break;
				case 'o':
					*dest++ = *(*socp)++;
					for(realcode = 0; is_octal(**socp);){
						digflg = 1;
						realcode <<= 3;
						realcode += ltov
						       (*dest++ = *(*socp)++);
					}
					if(!digflg) ERRLIN(2, cur_rk);
					if(**socp== ';') *dest++ = *(*socp)++;
					break;
				case 'x':
					*dest++ = *(*socp)++;
					for(realcode = 0; is_xdigit(**socp);){
						digflg = 1;
						realcode <<= 4;
						realcode += ltov
						       (*dest++ = *(*socp)++);
					}
					if(!digflg) ERRLIN(2, cur_rk);
					if(**socp== ';') *dest++ = *(*socp)++;
					break;
				case 'd':
					*dest++ = *(*socp)++;
					for(realcode = 0; is_digit(**socp);){
						digflg = 1;
						realcode *= 10;
						realcode += ltov
						       (*dest++ = *(*socp)++);
					}
					if(!digflg) ERRLIN(2, cur_rk);
					if(**socp== ';') *dest++ = *(*socp)++;
					break;
				default:
					if(is_octal(**socp)){
						for(realcode = 0;
						    is_octal(**socp);){
							realcode <<= 3;
							realcode += ltov(
							*dest++ = *(*socp)++);
						}
						if(**socp == ';')
							*dest++ = *(*socp)++;
					} else {
						realcode= *dest++= *(*socp)++;
					}
			}
			break;
		default: ;
	}

	*dest = EOLTTR;
	return(realcode);
}
	
 /**	letterの列の先頭にある空白をスキップする。
	行末に達したら、flgが0のときは1を返し、そうでないとエラー。*/
static int
blankpass(pptr, flg, cur_rk)
register letter **pptr;
	 /* letterの列のポインタへのポインタ。これが指しているものを進める */
int	flg;
ARGS *cur_rk;
{
	while(is_eolsp(**pptr)){
		if(EOLTTR == **pptr){
			if(flg) ERRLIN(4, cur_rk);
			return(1);
		}
		(*pptr)++;
	}
	return(0);
}

 /** リスト一個取り出し */
static void
listscan(socp, dest, cur_rk)
register letter **socp, *dest;
ARGS *cur_rk;
{
	int	eofreach;

	*dest++ = *(*socp)++; /* = '(' */
	*dest++ = ' ';
	
	while(eofreach = blankpass(socp, 0, cur_rk), **socp != ')'){
		if(eofreach){
			if(! readln((uns_chr *)hcurread, cur_rk)) ERRLIN(20, cur_rk);
			ustrtoltr((uns_chr *)hcurread, (*socp= ltrbufbgn), 1, cur_rk);
			 /* listの中で行が切れている場合、一行追加読み込みを
			    する。uns_chr用のバッファも、letter用のものも、
			    以前の物を先頭から再利用しているので注意。また、
			    エラーが起きた場合、 エラーの位置にかかわらず、
			    現在行として表示されるのは、最後に読まれた行のみ*/
		} else {
			termsscan(socp, dest, 0, cur_rk);
			totail(dest);
			*dest++ = ' ';
		}
	}
	*dest++ = *(*socp)++; /* = ')' */
	*dest = EOLTTR;
}

 /** lpで指定されたモード名を探す。見つからないとエラー */
static int
modsrcL(lp, cur_rk)
letter	*lp;
ARGS *cur_rk;
{
	int	n;

	for(n = 0; modmeibgn[n] != NULL; n++)
		if(!ltrstrcmp(lp, modmeibgn[n])) return(n);

	ERRLIN(16, cur_rk);
	 /*NOTREACHED*/
	return(-1);
}

 /** chk_get_int（rk_modread.c）のletter版 */
static int
chkL_get_int(lp, ip, range)
letter	*lp;
modetyp	*ip;
modetyp range;
{
	int	sgn = 1;
	modetyp	out;

	if(*lp == '-'){
		lp++;
		sgn = -1;
	}
	for(out = 0; *lp != EOLTTR; lp++){
		if(!is_digit(*lp)) return(-1);
#if defined(UX386) || defined(sun386)
		out = out * 10;
#else
		out *= 10;
#endif
		out += ltov(*lp);
	}
	if(range != 0) out %= range;
	if(sgn == -1 && out != 0) out = range - out;
	*ip = out;
	return(0);
}

 /**	この先は、表読み込みでエラった時に警告するルーチン。nはエラーコード。
	またこれらは全て、romkan_initのエラーコードとして、longjmp経由で
	1を返す。*/

void
ERMOPN(n, cur_rk) /* モード定義表がオープンできない */
unsigned int	n;
ARGS *cur_rk;
{
	static	char	*ermes[] = {
 /*  0 */	"Can't open Mode-hyo",
		"Unprintable error"
	};

	if(n >= numberof(ermes)) n = 1;

	fprintf(stderr, "\r\nMode-hyo %s ---\r\n", curfnm);
	fprintf(stderr, "%d: %s.\r\n", n, ermes[n]);
	longjmp(env0, 1);
}

static void
ERHOPN(n, cur_rk) /* 変換対応表がオープンできない */
unsigned int	n;
ARGS *cur_rk;
{
	static	char	*ermes[] = {
 /*  0 */	"Can't open Taio-hyo",
		"Is a directory",
		"Unprintable error"
	};

	if(n >= numberof(ermes)) n = 2;

	fprintf(stderr, "\r\nTaio-hyo %s%s ---\r\n", curdir, curfnm);
	fprintf(stderr, "%d: %s.\r\n", n, ermes[n]);
	longjmp(env0, 1);
}

void
ERRMOD(n, cur_rk) /* モード定義表のエラー */
unsigned int	n;
ARGS *cur_rk;
{
	static	char	*ermes[] = {
 /*  0 */	"Table incomplete",
		"')' mismatch",
		"Unprintable error",
		"Illegal filename",
		"Illegal modename",
 /*  5 */	"Undefined mode",
		"Illegal content(s) of list",
		"Illegal ^,\\o,\\x or \\d expression",
		"Illegal defmode",
		"Unrecognized keyword",
 /* 10 */	"Incomplete string",
		"Search path specified after filename",
		"Argument must be a string",
		"Can't get home directory",
		"Illegal @-keyword",
 /* 15 */	"User doesn't exist",
		"Illegal character",
		"Defmode or set-path placed wrong"
	};

	if(n >= numberof(ermes)) n = 2;

	fprintf(stderr, "\r\nMode-hyo %s%s ---\r\n%s\r\n",
		curdir, curfnm, mcurread);
	fprintf(stderr, "%d: %s.\r\n", n, ermes[n]);
	fclose(modefile);
	longjmp(env0, 1);
}

static void
ERRLIN(n, cur_rk) /* 変換対応表のエラー */
unsigned int	n;
ARGS *cur_rk;
{
	static	char	*ermes[] = {
 /*  0 */	"')' mismatch",
		"Incomplete single-quote or double-quote expression",
		"Illegal ^,\\o,\\x or \\d expression",
		"Illegal variable name",
		"Incomplete line",
 /*  5 */	"Evaluation of unbound variable",
		"Unprintable error",
		"Too many or too few contents of list",
		"Illegal defvar/defconst",
		"Faculity or declaration joined other item(s)",
 /* 10 */	"Duplicate defvar/defconst",
		"Variable/constant name conflicts with Function name",
		"A line contains both declaration and other output item(s)",
		"Argument isn't a letter",
		"Function, faculity or declaration in illegal place",
 /* 15 */	"More than 3 items",
		"Undefined mode",
		"Against the restriction of pre-transform table",
		"Against the restriction of after-transform table",
		"Item comes after faculity",
 /* 20 */	"Incomplete list",
		"Illegal character",
		"Illegal include",
		"Too many levels of 'include' nest",
		"Can't open include file",
 /* 25 */	"Can't get home directory",
		"Illegal @-keyword",
		"User doesn't exist",
		"Constant must be defined before used",
		"Illegal mode status"
	};

	if(n >= numberof(ermes)) n = 6;

	fprintf(stderr, "\r\nTaio-hyo %s%s ---\r\n%s\r\n",
		curdir, curfnm, hcurread);
	fprintf(stderr, "%d: %s.\r\n", n, ermes[n]);

	while(NULL != *base) fclose(*base--);

	longjmp(env0, 1);
}

static void
ERRHYO(n, cur_rk) 
/* ERRLINと同様、対応表のエラーだが、一行だけの誤りでなく
   全体を見ないとわからない誤り。今の所、「未定義変数の出現」のみ。*/
unsigned int	n;
ARGS *cur_rk;
{
	static	char	*ermes[] = {
 /*  0 */	"Undefined variable was found",
		"Unprintable error"
	};

	if(n >= numberof(ermes)) n = 1;

	fprintf(stderr, "\r\nTaio-hyo %s%s ---\r\n", curdir, curfnm);
	fprintf(stderr, "%d: %s.\r\n", n, ermes[n]);

	while(NULL != *base) fclose(*base--);

	longjmp(env0, 1);
}
