/*****************************************************************************/
/*	ＡＩＧライブラリ　言語モジュールＳＴＫ
		Copyright (C) 1994-96 by AIG-SOFT			     */
/*****************************************************************************/

#ifndef	__AIG_STK__
#define	__AIG_STK__	1	/* ヘッダー読み込みシンボル */

#ifndef	__DEFTYPE__
#include "deftype.h"		// 型定義
#endif
#ifndef	__AIG_VAR		// 変数処理
#include "var.h"
#endif
#ifndef	__AIG_STKERR__		/* エラーコード表 */
#include "stkerr.h"
#endif

#define	DEBUG	0		/* 0/1/2 */
#define	DEBUG2	0		/* 0/1/2 : 1=中間コード出力,2=逆テキスト出力 */

// STKはNULL=(unchar *)0を前提としている(stddef.h)

/*****************************************************************************/
/* テキスト定義 */

#define	STKEXT	"STK"	/* ソースファイル拡張子 */
#define	STKSEP	" \t\n"	/* STK tokenセパレーター */
#define	STKVER	"2.9"	/* STK system version */
// V1.0 : 完全文字列解釈型
// V2.0 : 中間コード型（高速化）
// V2.1 : 内部変数処理大幅変更（実行時小型化）
// V2.2 : 制御構文ｼﾞｬﾝﾌﾟｱﾄﾞﾚｽ格納による２回目以降の高速化
// V2.3 : 配列の大幅見直し、長さ制限見直し他
// V2.4 : 中間コードの偶数バイト化：読み取りをダイレクトに出来るようにする
// V2.5 : 配列アドレス絶対アドレス渡し対応
// V2.6 : 変数処理システム大幅変更
// V2.7 : 固定文字列スタック変更＆特別処理強化
// V2.8 : ローカル変数系改良
// V2.9 : 可変長引数取り込みにて型変換がない問題を改良

/* システムサイズ（SC?MAXはこれ以下に、その他は書換可能）*/
#define	TKLEN	250	/* 1token max length(=最大固定文字列長<255:unchar) */
#define	CSIZE	4096	/* 中間コードエリア初期サイズ */
#define	ACSIZE	1024	/* 中間コードエリア増分>=TKLEN */
#if ACSIZE < TKLEN
	/* サイズ設定がおかしかった時にわざとエラーを出す */
	"ACSIZE too small !!"
#endif
#define	SCLMAX	TKLEN	// ラベル名最大長<=TKLEN
#define	SCVMAX	TKLEN	// 変数名  最大長<=TKLEN
#define	CMTMAX	10	/* 行内コメントの最大ネスティング数 */
			/* 余り深くを許すとエラー発見の妨げになる */

/* デフォルトサイズ */
#define	LLMIN	8	// ラベル名最大長最小値（これ以下にしてはいけない長さ）
#define	VLMIN	8	// 変数名最大長最小値（これ以下にしてはいけない長さ）
			// 中間コードの関係から、VLMINは2以下にしてはいけない
#define	LLMAX	32	/* ラベル名最大長<=TKLEN */
#define	VLMAX	128	/* 変数名最大長<=TKLEN */

#define NMAX	200	/* 数値スタック段数 */
#define	LMAX	50	/* ラベルスタック段数 */
#define	RMAX	30	/* ループスタック段数 */
#define	LOCAL	40	// ローカル変数段数:[0]はグローバル
			// ローカルの段数はLOCAL-1段

/*---------------------------------------------------------------------------*/
/* 配列 */
/*---------------------------------------------------------------------------*/

#define	TYBITS	(BIT0|BIT1)	// 要素タイプ＝サイズ表現に必要なビット数
#define	JIBITS	(BIT0|BIT1)	// 配列次元表現に必要なビット数
#define	JIMAX	(JIBITS+1)	// 配列最大次元数

// 各タイプの配列要素バイト数-1
#define	ARYBYTE		0	// byte型配列
#define	ARYWORD		1	// word型配列
#define	ARYLONG		3	// long型配列

// 配列ヘッダーサイズ
#define	ARYHEAD	(LSHORT+LLONG+LSHORT*JIMAX)

#define	ASIZE	4096	/* 配列初期サイズ */
#define	ADABUFF	2048	/* 配列領域増分（このサイズずつ増える）*/

/*---------------------------------------------------------------------------*/
// シンボル
/*---------------------------------------------------------------------------*/

// label? = labelの動作区分
#define	SYMLB	':'	// label そのもの
#define	SYMCL	'.'	// label callの印

// 固定文字列系
#define	SYMSTR	'\"'	// 固定文字列
#define	SYMCSTR	'.'	// コード変換無し
#define	SYMCODE	'\''	// １文字コード
#define	SYMEXT	'\\'	// コード変換特殊コード指定文字

// コメント
#define	SYMCMT	';'	// １行コメント
#define	SYMCMTS	'/'	// 行内コメント初め
#define	SYMCMTE	'*'	// 行内コメント終わり
// 行内コメントはSYMSMTS+SYMCMTEで始まり、SYMCMTE+SYMCMTSで終わる

/*---------------------------------------------------------------------------*/
/* スタック定義 */
/*---------------------------------------------------------------------------*/
/* 数値スタック */

typedef struct { /* 数値スタック構造体 */
	long	num;	// 数値内容
	long	point;	// 変数ポイント/配列先頭ofst
	unsint	atrb;	// 属性:上位8bit=変数モード(mode),下位8bit=属性(atrb)
	short	loc;	// 変数段
} NSTACK;
/* 数値スタック構造体内容表
名称		atrb		mode		num		point	 loc
---------------------------------------------------------------------------
数値		NNUM		0		num		無効	 無効
固定文字列	NSTR1		0		絶対アドレス	長さ	 無効
配列アドレス	NADRS		0		要素ofst	先頭ofst 無効
変数		NVADR		VNUM		num      	p	 loc
				VSTR1		絶対アドレス	p	 loc
				VARY		先頭ofst	p	 loc
未確定変数	NVADRN		0		stksys.loc	p	 無効
---------------------------------------------------------------------------
p=変数格納ofst(short),loc=変数段
*/
/* 識別子（識別子の大文字小文字の関係は変更しないこと）*/
// 識別子はそのまま表示できるように可読文字にすること
#define	NNUM	'n'	/* 数値 */
#define	NSTR1	's'	// 固定文字列
#define	NADRS	'S'	// アドレス（スタック中ではオフセット）
#define	NVADR	'v'	// 確定済み変数
#define	NVADRN	'V'	// 未確定変数
			/* 変数は確定の印がtolower()で求められるようにする */
// 以下のものはT*との対応のため存在し、実際にはスタック上には存在しない
#define	NANO	'*'	// TANO
#define	NANO2	'.'	// TANO2
#define	NOSTR1	'o'	// TOSTR1
#define	NOADRS	'O'	// TOADRS

/* 引数型識別子（数値スタック識別子と合わせること）*/
#define	TNONE	""	/* 引数無し */
#define	TANO	"*"	/* その他：変数変換無し（コマンド内で判断する）*/
#define	TANO2	"."	/* その他：変数変換有り（コマンド内で判断する）*/
#define	TNUM	"n"	/* 数値（数値化付き）*/
#define	TSTR1	"s"	// 固定文字列/絶対アドレス
#define	TADRS	"S"	// 絶対アドレス
#define	TOSTR1	"o"	// 固定文字列/オフセットアドレス
#define	TOADRS	"O"	// オフセットアドレス
#define	TVADR	"v"	// 確定済み変数アドレス
#define	TVADRN	"V"	// 未確定変数アドレス

#define NPOPS	16	/* コマンドの１回の処理で取り出せる数値スタック数<=64 */

/* 変数型 */
#define	VNUM	0	/* 数値 */
#define	VARY	1	/* 配列 */
#define	VSTR1	2	/* 固定文字列 */
// アドレスは変数には代入できないので無い。
// 現在の変数の構造上、配列のアドレスを変数に入れること＝オフセットと先頭アドレスを
// 同時に記録する）ことは不可能である。
// ここを変更した時はstkvchg内の配列,stkfncdのDispNSTACK内の文字列も変更すること。

// 引数名置き換え（よく使われるので）
#define	NS0	(nstk[0])
#define	NS1	(nstk[1])
#define	NS2	(nstk[2])
#define	NS3	(nstk[3])
#define	NN0	(NS0.num)
#define	NN1	(NS1.num)
#define	NN2	(NS2.num)
#define	NN3	(NS3.num)
#define	NA0	(NS0.atrb)
#define	NA1	(NS1.atrb)
#define	NA2	(NS2.atrb)
#define	NA3	(NS3.atrb)
#define	NP0	(NS0.point)
#define	NP1	(NS1.point)
#define	NP2	(NS2.point)
#define	NP3	(NS3.point)

/*---------------------------------------------------------------------------*/
/* ラベルスタック */

typedef struct { /* ラベルスタック構造体 */
	unchar	*adrs;	/* アドレス */
	char	atrb;	/* 属性 */
} LSTACK;

/* 識別子 */
/* 'n'は作らないこと（数値だけは一発で区別つくように）*/
// 識別子はそのまま表示できるように可読文字にすること
// 現在のバージョンでは実際にはスタック上に存在しない識別子もある
#define	LLBL	'l'	/* label(goto/call) */
#define	LRET	't'	/* return */
#define	LREP	'r'	/* repeat */
#define	LFOR	'f'	/* for */
#define	LWHILE	'w'	/* while */
#define	LIF	'i'	/* if系 */
#define	LBRK	'b'	/* break系 */
#define	LCONT	'c'	/* continue系 */
#define	LSW	's'	/* switch */
#define	LERR	'e'	/* resume */

/*---------------------------------------------------------------------------*/
/* ループスタック */

typedef struct { /* ループスタック構造体 */
	long	start;
	long	end;
	/* 現在、ループは属性無し */
} RSTACK;

/*---------------------------------------------------------------------------*/
/* ＳＴＫ内部データ構造体 */

typedef struct {
	/* 数値スタック */
	NSTACK	*nstack;	/* スタック */
	short	nmax;		/* 段数 */
	short	ntop;		/* nstack top 位置 : 0〜nmax-1 */
	/* ラベルスタック */
	LSTACK	*lstack;	/* スタック */
	short	lmax;		/* 段数 */
	short	ltop;		/* lstack top 位置 : 0〜lmax-1 */
	/* ループスタック */
	RSTACK	*rstack;	/* スタック */
	short	rmax;		/* 段数 */
	short	rtop;		/* rstack top 位置 : 0〜rmax-1 */
	/* 変数管理 */
	VARSYS2	Gvar;		// グローバル変数
	VAR0	**Lvar;		// ローカル変数
	short	locmax;		// 変数最大段数
	short	loc;		// 現在参照中の変数段
	short	vsize;		// 変数最大個数
	short	vlmax;		// １変数名最大長
	/* 配列エリア */
	unchar	*Abuff;		/* バッファーポインター */
	long	Apoint;		/* 次の配列作成位置 */
	long	Asize;		/* バッファーサイズ */
	// ラベル領域
	short	lsize;		// ラベル最大個数
	short	llmax;		// １ラベル名最大長
	/* コマンドライン */
	int	argc;		/* コマンドラインのそれらと同じ */
	unchar	**argv;
	unlong	mode;		/* 動作モード(32bit分) */
	// その他
	// エラー処理用
	short	errno;		// エラー番号
	// 特殊ラベルアドレス（フラグを兼ねる）
	unchar	*onact[4];	// [0] ERROR 処理
				// [1] ERROR resume
				// [2] BREAK 処理
				// [3] BREAK resume
} STKSYS;

/*---------------------------------------------------------------------------*/
// 動作モード制御ビット定義（V2.9;くわしくはstk.cを参照のこと）

#define	MDfctrl		BIT0	/* CTRL-C制御 */

#define	MDTRbit		24			/* BIT24以上がトレース制御ビット(8ビット分) */
#define	MDTRmax		(BIT0123|BIT4)		/* 実際に定義されているトレース */
#define	MDbitsTR	(MDTRmax<<MDTRbit)	/* mode内でのトレース制御用ビット（定義分）*/

#define	MDftrace0	(BIT0<<MDTRbit)
#define	MDftraceK	(BIT1<<MDTRbit)		/* トレース表示位置固定 */
#define	MDftrace	(MDftrace0|MDftraceK)
#define	MDntrace	(BIT2<<MDTRbit)
#define	MDltrace	(BIT3<<MDTRbit)
#define	MDrtrace	(BIT4<<MDTRbit)

/*---------------------------------------------------------------------------*/
/* STKのコマンドは中間コードの制約から、１テーブル内に63個までである。*/
/* 全テーブルでの総数は32768個まで。*/
/* もっとも、そんなにたくさんのコマンドを一度に使うことは無いだろうが。 */
/* code
    「基本形態」
	中間コードはすべて次の形態を持つ。識別子は１バイトで、下記の通りになる。
	長さは後に続く属性領域の長さを１バイトで示す。属性がない場合には$00になる。
	
	識別子(8bit) 長さ(8bit) 属性(長さバイト)
	
	長さには奇数バイトもあるが、属性領域は常に偶数バイト化される。
	
	識別子区分
	 $00/$40   : 未使用（現在のシステムでは使用出来ず）
		    ただしコマンド扱される
	 $01〜$3f  : コマンド
	  +BIT6    : 後ろにジャンプアドレスを持つコマンド
		    ｼﾞｬﾝﾌﾟｱﾄﾞﾚｽを持つのは、基本的に飛び先を前方参照するコマンドである
		   （後方参照の場合、アドレスはすでに確定しているので不要。）
	 $80〜$ef  : コマンド以外
	
	中間コードはすべて偶数バイトになる。
	サイズ的には不利であるが、読み取りが直接出来るため、高速化出来る。

    「中間コード定数」
	以下、adrsは中間コードコンパイル時にはすべて３２ビットの中間ｺｰﾄﾞ領域の
	オフセットアドレス（中間コードコンパイル中には中間コード領域が拡大にともなって
	移動する可能性があるから）。実行時には絶対アドレスに変わる。
	
	$01〜$3f $04 tbl      : コマンド番号(8bit)+$04+ﾃｰﾌﾞﾙｱﾄﾞﾚｽ(32bit)
	$41〜$7f $08 tbl adrs : コマンド番号(8bit)+$08+ﾃｰﾌﾞﾙｱﾄﾞﾚｽ(32bit)+ｼﾞｬﾝﾌﾟｱﾄﾞﾚｽ(32bit)
				ジャンプアドレスは初期はNULL,<>NULLなら確定アドレス。
	
	SCNUM  $04 num        : 数値(32bit)
	SCLBL  $04 adrs       : gotoラベルアドレス(32bit)
	SCCALL $04 adrs       : callラベルアドレス(32bit)
	SCVAR  $04 vpoint     : 変数名
	SCCAL0 $04 vpoint     : 未定義callﾗﾍﾞﾙ(中間コード定義途中にしか現れない)
	
	SCCOMT $04 tadrs      : ソーステキストアドレス(32bit)
				このコメントの中間ｺｰﾄﾞを示すテキストのアドレス。
				エラー時のテキスト表示用に（現在は）ラベル、
				固定文字列、数値に付く。
	
	$04(LLONGまたはLCPOINT)/$08(LLONG+LCPOINT)はその後に続く領域サイズを示す。
	中間コードはすべてLLONG=LCPOINTを前提にしている。
	
	SCSTR1 len str1       : 固定文字列
	
	lenはその後に続く領域の長さを示し、この分skipすればよい。
	lenが奇数になるときは、後ろに$00を入れて全体として偶数化する。ただし、
	lenそのものは処理の都合上奇数のままとする。
	
	SCEND $00 : End of Code
*/
#define	CMDMAX	0x3f		/* １テーブル中のコマンドの最大数 */
				// 必ずまとまったビット単位で与えること
#define	FJUMP	BIT6		/* ジャンプアドレスを持つコマンドのフラグ */
#define	SCCMD	(FJUMP|CMDMAX)	/* コマンド番号の最大値 */

#define	SCNUM	0x80		/* 数値 */
#define SCLBL	0x81		/* ラベルアドレス */
#define SCCALL	0x82		/* callラベルアドレス */
#define	SCVAR	0x83		// 変数
#define	SCCAL0	0x84		// 未定義callﾗﾍﾞﾙ(中間コード定義途中にしか現れない)
#define SCCOMT	0x85		// テキストアドレス用コメント（そのもの）

#define	SCSTR1	0x86		/* 固定文字列 */

#define SCEND	0xff		/* 中間コード終わり */

/*---------------------------------------------------------------------------*/
/* ＳＴＫコマンド構造体 */

typedef struct {
	unchar	*name;		/* コマンド名 */
	int	(*func)();	// 処理本体:func(NSTACK *,int,unchar *,unchar *(*),unchar *(*))
				// ただし、引数は無くても良い
	unchar	*list;		/* 引数リスト */
				/* 引数の個数とその型を指定する */
	unsint	ret;		/* リターン後にnstack topへ積む数 */
				/* 初期にBIT15=1の場合、このコマンドはｼﾞｬﾝﾌﾟｱﾄﾞﾚｽを持つ */
	unsint	mode;		/* 処理ルーチンに与えられる引数 */
				/* 複数のコマンドを１ルーチンで処理するため */
} STKCOM;

#define	CFJUMP	BIT15		/* ジャンプアドレスを持つコマンドのフラグ */
#define	NCFJUMP	(~BIT15)	/* フラグ以外を抜き出す(unsint用) */

/*---------------------------------------------------------------------------*/
/* STATUS code */
/* >0  : エラー */
/* <=0 : 正常終了 */
#define	OK	VOK	// 正常終了==0
#define	NOK	(-1)	// NS0=num付きリターン(NP0=0,NA0=NNUM,他はOKと同じ)
#define	LOK	(-2)	// テキストポインタ変更付き正常終了
#define	COK	(-100)	// この後にCTRL-Cチェックをする正常終了
#define	ENDOK	(-254)	// テキスト終了
#define	ENDOK2	(-255)	// テキスト終了(ntopを返す)

/*****************************************************************************/
/* プロトタイプ宣言 */
/* STKは言語なので、チェック強化のためプロトタイプ宣言のみとする */

#ifdef	__cplusplus	// 95/12 : G++対応
extern	"C" {
#endif

int	STK(unchar *,STKCOM **,STKSYS *,unlong ,long *);
int	OpenSTK(STKSYS *);
void	CloseSTK(void);
int	STKmain(unchar *,long *);
void	TracePrint(unchar *);

unsint	STKVarRead(long,NSTACK *);

int	STKinterpret(unchar *(*),unchar *(*));
int	STKSearchPair(STKCOM *,int ,int ,int ,int ,unchar *(*),unchar *(*));
int	STKTokenGet(unchar *,unchar *(*),unchar *(*));

void	SetErrToken(unchar *);
void	SetErrCode(unchar *);
void	ErrCode2Token(void);
unchar	*STKErrToken(void);
int	STKCodeErr(unchar ,unchar *);
int	STKSysErr(unchar *);
int	STKErrLink(ERLINK *);
unchar	*STKError(int );
unchar	*RemakeToken(unchar *);

int	PushNStack(NSTACK *);
int	PopNStack(NSTACK *);
int	PushLStack(unchar *,char );
int	PopLStack(unchar *(*),char *,int );
int	PushRStack(long ,long );
int	PopRStack(long *,long *,int );
void	SwapStack(NSTACK *,int ,int );

int	STKChgVarNumSub(unchar ,NSTACK *);
int	STKChgVarNum(unchar *,NSTACK *);
int	STKVarChange(NSTACK *,int);

int	ARYZoom(long );
int	ARYMake(int ,unsint *,int ,long *);
int	ARYJAdrs(long ,int ,unsint *,long *);
int	ARYyouso(int ,unsint *);
unchar *ARYSTRoadrs(NSTACK *);
long	ARYosize(NSTACK *);
long	ARYbsize(NSTACK *);
long	ARYsize(NSTACK *);
long	ARYSTRSize(NSTACK *);
long	ARYSTRLen(NSTACK *,NSTACK *);
int	ARYStoreB(NSTACK *,unchar *,long );
long	ARYRead(NSTACK *,int );
int	ARYWrite(NSTACK *,long);

int	STKSemiCompile(unchar *,unchar *(*));
int	STKSetLabelAdrs(unchar *,VARSYS2 *);
int	STKCheckName(unchar *);

int	AddComToken(STKCOM **);

STKCOM	*FirstComLink(void);
void	SetComLink(STKCOM *);
int	ComInit(void);
int	ComEnd(void);
int	OpenCommand(void);
void	CloseCommand(void);
int	CheckCommand(unchar *,STKCOM *(*));

// マクロ関数
unchar	*ARYadrs(long);
unchar	*ARYHtop(long);
int	ARYSTRChkSize(NSTACK *,long );
int	ARYChkSize(NSTACK *,long );
unchar	*Cadrs(long);
unchar	EvenLen(unchar );

#ifdef	__cplusplus
}
#endif

/*****************************************************************************/
// マクロ関数

// 絶対アドレスに変換する式
#define ARYadrs(ofst)		(&stksys->Abuff[ofst])

// 配列本体先頭アドレスを配列topから計算する
#define	ARYHtop(ofst)		(ARYadrs((ofst)+ARYHEAD))

// 配列領域オーバーチェック
#define	ARYChkSize(ns,len)	(ARYsize(ns)<len)

// ARYSTRSizeで長さをチェックする
#define	ARYSTRChkSize(ns,len)	(ARYSTRSize(ns)<len)

// アドレス化
#define	Cadrs(n)		((unchar *)(n))

// 長さ偶数バイト化
#define	EvenLen(len)		(((len)+1)&0xfe)

// 旧関数との互換性のため
#define	CloseSTK()		/* なにもしない */

/*****************************************************************************/
#endif
/*****************************************************************************/
