Mercurial > freewnn
diff Wnn/romkan/rk_read.c @ 0:bbc77ca4def5
initial import
author | Yoshiki Yazawa <yaz@cc.rim.or.jp> |
---|---|
date | Thu, 13 Dec 2007 04:30:14 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Wnn/romkan/rk_read.c Thu Dec 13 04:30:14 2007 +0900 @@ -0,0 +1,1560 @@ +/* + * $Id: rk_read.c,v 1.6 2005/04/10 15:26:38 aonoto Exp $ + */ + +/* + * FreeWnn is a network-extensible Kana-to-Kanji conversion system. + * This file is part of FreeWnn. + * + * Copyright Kyoto University Research Institute for Mathematical Sciences + * 1987, 1988, 1989, 1990, 1991, 1992 + * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999 + * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992 + * Copyright FreeWnn Project 1999, 2000, 2002 + * + * Maintainer: FreeWnn Project <freewnn@tomo.gr.jp> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*********************************************************************** + rk_read.c + 88. 6.11 改 正 + + rk_main.c の部品。変換対応表の読み込みを担当。 +***********************************************************************/ +/* Version 3.0 */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if STDC_HEADERS +# include <string.h> +#elif HAVE_STRINGS_H +# include <strings.h> +#endif /* STDC_HEADERS */ +#include <sys/stat.h> +#include <sys/types.h> +#include "rk_header.h" +#include "rk_extvars.h" + +letter onescan (), *rangekettei (); +char *ename (); + +extern letter *ltrgrow (), *ltrend (), letterpick (), *ltr1cut (); +extern char *chrcat (), *strend (); + +static int termsscan (), evalandcpy (), eval1cpy (), partscan (), evlis (), atermscan (), serfun (), hensrc_tourk (), blankpass (), modsrcL (), chkL_get_int (); +static void ERRLIN (), ERHOPN (), readhyo (), ltr1tostr (), ERRHYO (), vchk (), rangeset (), de_bcksla (), listscan (), singleqscan (), doubleqscan (); +extern void BUGreport (), choosehyo (), readmode (); +extern int ltrcmp (), ltrstrcmp (), readfnm (), fixednamep (); + +#define IHENSU (1 << 24) /* 内部表現の上位1バイトで、変数を表す */ +#define IKANSU (2 << 24) /* 〃 関数を表す */ +#define IMODNM (3 << 24) /* 〃 モード名を表す */ + +#define ENDOF_NestFileArea ((FILE *)~0) + /** includeファイルのディスクリプタ格納エリアのエンドマーク*/ + + + /** 一行読み込み。一字も読み込まないうちにEOFにつきあたったら0を返す。 + 但しincludeを考慮している。対応表には空白文字以外のコントロール文字は + 生では混じらないものとし、混じっていたらチェックする。*/ +int +readln (buf) + uns_chr *buf; +{ + 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); + } + *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) + char *name, **dirnamptr; + int *errptr; +{ + 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) + letter *memory; /* 対応表の内部表現を入れる配列の先頭番地を渡される */ + struct dat *data; /* 対応表の行ごとのデータを入れる配列の番地 */ + letter **hensudefhyo; /* 変数定義のデータを入れる配列の番地 */ + char *modf; /* モード定義表の名又はそのパス名が入っている */ +{ + 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); + + 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); + if (err) + { + switch (err) + { + case 1: + case 3: + ERHOPN (1); + case 2: + case 4: + ERHOPN (0); + } + } + readhyo (i); + } + + hyo_n[i].data = NULL; + choosehyo (); +} + + /** ファイル名からパス名を除いた部分の先頭を返す。*/ +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) + uns_chr *linbuf; + int flg; + register letter *ltrbuf; +{ + register letter l; + + if (flg) + { + while (l = letterpick (&linbuf), is_eolsp (l)) + { + if (l == EOLTTR) + { + *ltrbuf = EOLTTR; + return; + } + } + *ltrbuf++ = l; + } + while ((*ltrbuf++ = letterpick (&linbuf)) != 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) + int n; +{ + 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)) + { + hen_useflgclr (henorg); + ustrtoltr (linbuf, ltrbuf, 1); + ltrbufptr = ltrbuf; + + for (m = 0; termsscan (<rbufptr, term = termbuf, 1); m++) + { + /* mは、何番目の項目を見ているかを表す */ + if (*term == ';') + break; /* 注釈行 */ + if (m == 3) + ERRLIN (15); + if (m != 0 && rsltyp[0] == 4) + ERRLIN (12); + + datptr->code[m] = memptr; + if ((rsltyp[m] = evalandcpy (&term, m)) == 4) + { + if (m) + ERRLIN (14); + /* 宣言は最初の項目にしか来れない。 + 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); + break; + case 2: + if (rsltyp[1] == 3 && rsltyp[2] != -1) + ERRLIN (19); + break; + case 3: + if (!(rsltyp[0] == 0 && (rsltyp[1] == 0 || rsltyp[1] == 1) && rsltyp[2] == -1)) + ERRLIN (18); + 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); + *henptr++ = memptr - (lp - hentourkptr->range); + } + *henptr++ = NULL; + + /* ここで fclose(*base); は不要。readln内ですんでいる */ +} + + /** 変換対応表の項目一つを、解釈して、内部形式のデータエリアにコピーする。 + 返す値は、解釈した項目が文字項なら0、それ以外で文字列連なら1、それ以外 + でデータ連なら2、機能項なら3、宣言項なら4。それ以外はエラー。*/ +static int +evalandcpy (socp, m) + register letter **socp; /* 項目へのポインタ(へのポインタ) */ + int m; /* 対応表の何番目の項目を見ているかを表す。入力コード部を + 見ているときは0、出力コード部なら1、バッファ残り部なら2 */ +{ +#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)) && 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); + 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) + letter **socp; /* flg以外の引数の意味はevalandcpyと同じ */ + int m, flg; +{ + letter t1buf[TRMSIZ], *t1bufp; + + t1bufp = t1buf; + + *memptr = EOLTTR; + switch (partscan (socp, t1bufp)) + { + case 1: /* 単文字 */ + memptr = ltrgrow (memptr, t1bufp); + *memptr = EOLTTR; + return (0); + case 2: /* 引用文字 */ + t1bufp++; + *memptr++ = onescan (&t1bufp, dummy); + *memptr = EOLTTR; + return (0); + case 3: /* 引用文字列 */ + t1bufp++; + while (*t1bufp != '"') + { + *memptr++ = onescan (&t1bufp, dummy); + } + *memptr = EOLTTR; + return (1); + case 0: /* リスト */ + return (evlis (m, &t1bufp, flg)); + /* 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列から一文字取ってくる。*/ +/* *INDENT-OFF* */ +letter +get1ltr () +/* *INDENT-ON* */ +{ + return (get_ltr (lptr)); +} + +/* *INDENT-OFF* */ +letter +unget1ltr (l) + letter l; +/* *INDENT-ON* */ + +{ + return (unget_ltr (l, lptr)); +} + +int +int_get1ltr () +{ + return ((int) (get1ltr ())); +} + +int +int_unget1ltr (c) + letter c; +{ + return ((int) (unget1ltr ((letter) c))); +} + + /** 汚いことこの上なし!なぜ関数の型のcastができないの? + 「(int ()) get1ltr」と書きたい! */ + + /** includeファイル名のletter列をstringに取り出す作業を、letter列の終わり + まで続ける。flg & 01が非0なら、'/'でも終了。*/ +/* *INDENT-OFF* */ +letter +getfrom_dblq (socp, destp, flg) + letter **socp; + char **destp; + int flg; +/* *INDENT-ON* */ +{ + letter l; + + while (**socp != EOLTTR && !(flg & 01 && **socp == KUGIRI)) + { + if (**socp == '\\') + *(*destp)++ = '\\'; + l = onescan (socp, dummy); + ltr1tostr (l, destp); + } + *(*destp)++ = '\0'; + return (**socp); +} + +int +getfrom_lptr (sptr, flg) + char **sptr; + int flg; +{ + return ((int) getfrom_dblq (&lptr, sptr, flg)); +} + + /** リストを解釈して内部表現にする。返値は、そのリストのタイプを表す数。 + 文字変数項又は文字関数項:0 文字列関数項:1 特殊関数項:2 + 機能項:3 宣言項:4 */ +static int +evlis (m, socp, flg) + letter **socp; /* 引数の意味はeval1cpyを参照 */ + int m, flg; +{ + int fnnum, hennum, i; + letter t1buf[TRMSIZ]; + + (*socp)++; /* '('をスキップ */ + atermscan (socp, t1buf, 3); + + fnnum = serfun (t1buf); + if (fnnum != -1 && !bitchk (func[fnnum].appear, m)) + ERRLIN (14); + /* mの値によって、現れてはいけない所への出現かどうか見ている。 */ + + switch (fnnum) + { /* defaultの所以外は func[fnnum].argnumを使ってない */ + case -1: /* 変数 */ + vchk (t1buf); + atermscan (socp, dummy, 2); /* あればERR */ + hennum = hensrc_tourk (t1buf, ((m == 0 && !flg) ? 0 : 1)); + *memptr++ = (henorg[hennum].constflg ? *(henorg[hennum].range) : hennum | IHENSU); + break; + + case 0: /* fn No.0 defvar */ + atermscan (socp, t1buf, 3); + if (*t1buf == '(') + { + letter *soc2, t1buf2[TRMSIZ], t1buf3[TRMSIZ]; + letter *common_hen; + + atermscan (socp, t1buf3, 3); + + soc2 = t1buf + 1; /* skip '(' */ + + atermscan (&soc2, t1buf2, 3); + vchk (t1buf2); + if (-1 != serfun (t1buf2)) + ERRLIN (11); + hennum = hensrc_tourk (t1buf2, 2); + common_hen = rangekettei (hennum, t1buf3); + + while (atermscan (&soc2, t1buf2, 0)) + { + vchk (t1buf2); + if (-1 != serfun (t1buf2)) + ERRLIN (11); + hennum = hensrc_tourk (t1buf2, 2); + rangeset (hennum, common_hen); + } + } + else + { + vchk (t1buf); + if (-1 != serfun (t1buf)) + ERRLIN (11); + hennum = hensrc_tourk (t1buf, 2); + /* defvar・defconstの変数名の重複を避けるため */ + atermscan (socp, t1buf, 3); + rangekettei (hennum, t1buf); + } + atermscan (socp, dummy, 2); + break; + case 36: /* fn No.36 defconst */ + atermscan (socp, t1buf, 3); + vchk (t1buf); + if (-1 != serfun (t1buf)) + ERRLIN (11); + + hennum = hensrc_tourk (t1buf, 6); + /* defvar・defconstの変数名重複を避けるため */ + + rangeset (hennum, hen_iki); + + blankpass (socp, 1); + if (*(*socp)++ != '\'') + ERRLIN (8); + *hen_iki++ = onescan (socp, dummy); + (*socp)++; /*「'」が閉じていることの検査は済んでいる */ + *hen_iki++ = EOLTTR; /* needed? */ + *hen_iki = EOLTTR; + + atermscan (socp, dummy, 2); + break; + + case 1: /* fn No.1 include */ + { + char fnmtmparea[REALFN], *s, *dirnamptr; + int dummyc = 0, err; + + blankpass (socp, 1); + if (3 != partscan (socp, t1buf)) + ERRLIN (22); + atermscan (socp, dummy, 2); + /* 余分にあればERR */ + + ltr1cut (lptr = t1buf + 1); + *(s = fnmtmparea) = '\0'; + err = readfnm (int_get1ltr, int_unget1ltr, getfrom_lptr, &s, &dummyc); + + if (err) + { + hcurread = s; + switch (err) + { + case 1: + case 3: + ERRLIN (25); + case 2: + ERRLIN (26); + case 4: + ERRLIN (27); + } + } + de_bcksla (fnmtmparea, fnmtmparea); + + if (*++base == ENDOF_NestFileArea) + { + base--; + ERRLIN (23); + } + *base = trytoopen (fnmtmparea, &dirnamptr, &err); + if (err) + { + switch (err) + { + case 1: + case 3: + case 2: + case 4: + base--; + ERRLIN (24); + } + } + } + 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); + *memptr++ = modsrcL (t1buf) | IMODNM; + atermscan (socp, t1buf, 2); + 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); + *memptr++ = (n = modsrcL (t1buf)) | IMODNM; + atermscan (socp, t1buf, 3); + err = chkL_get_int (t1buf, &stat, modesw[n].moderng); + if (err != 0) + ERRLIN (29); + *memptr++ = stat; + atermscan (socp, t1buf, 2); + break; + } + + /* 普通(引数を取らないものを含む) */ + default: /* toupper,tolower… */ + *memptr++ = fnnum | IKANSU; + *memptr = EOLTTR; + for (i = 0; i < func[fnnum].argnum; i++) + { + blankpass (socp, 1); + if (eval1cpy (socp, m, 1) != 0) + ERRLIN (13); + } + atermscan (socp, dummy, 2); /* 余分にあれば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) + letter *shiki; + int num; /* 変域を決定しつつある変数の内部番号 */ +{ + letter hyoukabuf[TRMSIZ]; + + rangeset (num, hen_iki); + *hen_iki = EOLTTR; + + if (*shiki++ != '(') + ERRLIN (8); + atermscan (&shiki, hyoukabuf, 1); + + if (!ltrstrcmp (hyoukabuf, "all")) + { + *hen_iki++ = VARRNG; + *hen_iki++ = 0; + *hen_iki++ = LTRHUG; /* 変域は全文字 */ + *hen_iki++ = EOLTTR; + *hen_iki = EOLTTR; + atermscan (&shiki, dummy, 2); /* 余分にあればERR */ + } + else if (!ltrstrcmp (hyoukabuf, "between")) + { + int i; + + *hen_iki++ = VARRNG; + while (blankpass (&shiki, 1), *shiki != ')') + { + for (i = 1; i <= 2; i++) + { + switch (*shiki) + { + case '\'': + shiki++; + *hen_iki++ = onescan (&shiki, dummy); + shiki++; + break; + case ')': + case '"': + case '(': + ERRLIN (8); + default: + *hen_iki++ = *shiki++; + } + if (i < 2) + { + if (!is_eolsp (*shiki)) + ERRLIN (8); + blankpass (&shiki, 1); + } + } + } + *hen_iki++ = EOLTTR; + *hen_iki = EOLTTR; + } + else if (!ltrstrcmp (hyoukabuf, "list")) + { + while (blankpass (&shiki, 1), *shiki != ')') + { + switch (*shiki) + { + case '"': + case '(': + ERRLIN (8); + case '\'': + shiki++; + *hen_iki++ = onescan (&shiki, dummy); + shiki++; /* 本当に「'」が閉じているか + どうかの検査はもう済んでいる。 */ + break; + default: + *hen_iki++ = *shiki++; + } + if (!is_eolsp (*shiki)) + ERRLIN (8); + } + *hen_iki++ = EOLTTR; + *hen_iki = EOLTTR; + } + else + { + ERRLIN (8); /* 将来はこの他の構文も許す予定であった */ + } + + return (henorg[num].range); +} + + /** num番目の変数の変域を指すべきポインタの指し先を決定し、その変数を + 既登録状態にする。*/ +static void +rangeset (num, range) + letter *range; /* 変域の入る場所のポインタ */ + int num; +{ + 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) + letter *name; + int flg; +{ + int i; + + for (i = 0; henorg[i].name != NULL; i++) + { + if (ltrcmp (henorg[i].name, name)) + continue; + /* found */ + if (flg & 04) + ERRLIN (28); + if (flg & 02 && henorg[i].regdflg != 0) + ERRLIN (10); + if (flg & 01 && henorg[i].curlinflg == 0 && henorg[i].constflg == 0) + ERRLIN (5); + henorg[i].curlinflg = 1; + return (i); + } + if (henorg + i != hentourkptr) + BUGreport (5); + + /* ここへ来たということは、初出の変数ということ。当然、flg & 01が + 非0ならエラー。 */ + if (flg & 01) + ERRLIN (5); + 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) + letter *lp; +{ + if (is_digit (*lp)) + ERRLIN (3); + for (; *lp != EOLTTR; lp++) + { + /* if(is_lower(*lp)) *lp = to_upper(*lp); */ + if (!is_alnum (*lp) && *lp != '_') + ERRLIN (3); + } +} + + /** 一項目を取り出す。取り出しに成功すると1を返す。flgが非0の時は、')'が + 見つかるとエラー、';'はそれだけで一項目扱い。*/ +static int +termsscan (socp, dest, flg) + register letter **socp, *dest; + /* socpの指しているポインタが指している所から取り出してdestに入れる。 + その後、socpが指しているポインタを進める。このファイルの **scan() + という関数は全てそうなってる。 */ + int flg; +{ + letter *bgn; + + bgn = dest; + + if (blankpass (socp, 0) == 0) + { + if (flg && **socp == ';') + { + *dest++ = *(*socp)++; + } + else + while (!is_eolsp (**socp)) + { + if (**socp == ')') + { + if (flg) + ERRLIN (0); + break; + } + else + { + partscan (socp, dest); + totail (dest); + } + } + } + + *dest = EOLTTR; + return (bgn != dest); +} + + /** リスト一つか、単純項の一まとまりを取り出す。成功したら1を返す。 + flgが1のとき、')'が見つかるとエラー。 + flgが2のとき、取り出しに成功したらエラー。 + flgが3のとき、取り出しに失敗したらエラー。*/ +static int +atermscan (socp, dest, flg) + register letter **socp, *dest; + int flg; +{ + letter *bgn; + int found; + + bgn = dest; + + if (blankpass (socp, 0) == 0) + { + if (**socp == '(') + { + listscan (socp, dest); + totail (dest); + } + else + { + while (!is_eolsp (**socp) && **socp != '(') + { + if (**socp == ')') + { + if (flg == 1) + ERRLIN (0); + break; + } + else + { + partscan (socp, dest); + totail (dest); + } + } + } + } + + *dest = EOLTTR; + + found = (bgn != dest); + if ((!found && flg == 3) || (found && flg == 2)) + ERRLIN (7); + return (found); +} + + /** 項一つを取り出す。取り出したものがリストなら返値は0、単文字なら1、 + 引用文字なら2、引用文字列なら3。*/ +static int +partscan (socp, dest) + register letter **socp, *dest; +{ + switch (**socp) + { + case '(': + listscan (socp, dest); + return (0); + case '\'': + singleqscan (socp, dest); + return (2); + case '"': + doubleqscan (socp, dest); + return (3); + default: + *dest++ = *(*socp)++; + *dest = EOLTTR; + return (1); + } +} + + /** シングルクォート表現一つを取り出す。*/ +static void +singleqscan (socp, dest) + letter **socp, *dest; +{ + *dest++ = *(*socp)++; + onescan (socp, dest); + totail (dest); + if ((*dest++ = *(*socp)++) != '\'') + ERRLIN (1); + + *dest = EOLTTR; +} + + /** ダブルクォート表現一つを取り出す。*/ +static void +doubleqscan (socp, dest) + letter **socp, *dest; +{ + *dest++ = *(*socp)++; + while (**socp != '"') + { + if (**socp == EOLTTR) + ERRLIN (1); + onescan (socp, dest); + 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の逆 */ +/* *INDENT-OFF* */ +letter +vtol (l) + letter l; +/* *INDENT-ON* */ +{ + if (BASEMX <= l) + return ('*'); + return (l + (l < 10 ? '0' : 'A' - 10)); +} + + /** シングル・ダブルクォートの中での一文字取り出し。 + 「^」によるコントロールコード表現、「\」による8・10・16進表現にも + 対応。「\」表現は、「\[o又はd又はx]数字の並び[;]」である。*/ +/* *INDENT-OFF* */ +letter +onescan (socp, dest) + letter **socp, *dest; +/* *INDENT-ON* */ +{ + letter l, realcode; + int digflg; + + switch (realcode = *dest++ = *(*socp)++) + { + case '^': + if (!(' ' <= (l = *(*socp)++) && l < '\177')) + ERRLIN (2); + 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); + 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); + 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); + 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) + register letter **pptr; + /* letterの列のポインタへのポインタ。これが指しているものを進める */ + int flg; +{ + while (is_eolsp (**pptr)) + { + if (EOLTTR == **pptr) + { + if (flg) + ERRLIN (4); + return (1); + } + (*pptr)++; + } + return (0); +} + + /** リスト一個取り出し */ +static void +listscan (socp, dest) + register letter **socp, *dest; +{ + int eofreach; + + *dest++ = *(*socp)++; /* = '(' */ + *dest++ = ' '; + + while (eofreach = blankpass (socp, 0), **socp != ')') + { + if (eofreach) + { + if (!readln ((uns_chr *) hcurread)) + ERRLIN (20); + ustrtoltr ((uns_chr *) hcurread, (*socp = ltrbufbgn), 1); + /* listの中で行が切れている場合、一行追加読み込みを + する。uns_chr用のバッファも、letter用のものも、 + 以前の物を先頭から再利用しているので注意。また、 + エラーが起きた場合、 エラーの位置にかかわらず、 + 現在行として表示されるのは、最後に読まれた行のみ */ + } + else + { + termsscan (socp, dest, 0); + totail (dest); + *dest++ = ' '; + } + } + *dest++ = *(*socp)++; /* = ')' */ + *dest = EOLTTR; +} + + /** lpで指定されたモード名を探す。見つからないとエラー */ +static int +modsrcL (lp) + letter *lp; +{ + int n; + + for (n = 0; modmeibgn[n] != NULL; n++) + if (!ltrstrcmp (lp, modmeibgn[n])) + return (n); + + ERRLIN (16); + /*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); + out *= 10; + 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) /* モード定義表がオープンできない */ + unsigned int n; +{ + 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) /* 変換対応表がオープンできない */ + unsigned int n; +{ + 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) /* モード定義表のエラー */ + unsigned int n; +{ + 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) /* 変換対応表のエラー */ + unsigned int n; +{ + 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) /* ERRLINと同様、対応表のエラーだが、一行だけの誤りでなく + 全体を見ないとわからない誤り。今の所、「未定義変数の出現」のみ。 */ + unsigned int n; +{ + 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); +}