/*****************************************************************************/
/* ＳＴＫコマンド：配列（切り放し可能だけどしない方がいい）*/
/*****************************************************************************/

#include <limits.h>
#include "defines.h"
#include "stk.h"

extern STKSYS *stksys;

/*****************************************************************************/

static int Sarray(NSTACK nstk[],int mode)
// 配列変数の定義
// ( x y z r ).次元(1) name(NVADRN:0) ARY.L/W/B → NADRS(0;先頭アドレス)
//              len(1) name(NVADRN:0) STRING    → NADRS(0;先頭アドレス)
//       str(NOSTR1:1) name(NVADRN:0) STRINGS   → NADRS(0;先頭アドレス)
{
int ret=OK,jigen=1; // for STRING? : １次元のみ
unsint jsize[JIMAX];
long len=0L; // コピーフラグ：コピーサイズもかねる
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	if (sys->loc>0) return(ARYLOCAL); // ローカル変数には配列を定義出来ない
	switch (mode) {
	    case 5: // STRINGS
		len=(NA1==NSTR1? NP1:ARYosize(&NS1));
		if (len>=USHRT_MAX) return(ARYOUSO);
			// 要素番号に16bitより大きい数値は使えない
			// 文字列長なので負数はない
		jsize[0]=(unsint)len; // xsize=len
		mode=ARYBYTE;
		break;
	    case 4: // STRING
		jsize[0]=(unsint)NN1; // xsize=len
		if (NN1>=USHRT_MAX||NN1<0L) return(ARYOUSO);
			// 要素番号に16bitより大きい数値や負数は使えない
		mode=ARYBYTE;
		break;
	    default: // ARY.?
		/* 次元サイズ読みとり */
		jigen=(int)NN1;
		if ((ret=ARYyouso(jigen,jsize))) return(ret);
		break;
	}
	// mode=要素type
	
	// 定義先はグローバルの未定義変数のみ
	// ARY変数は再代入不可である
	// 変数にはARRAYの先頭のオフセットを入れる
	// グローバルのみなので直書きする：エラーはない
	{ VAR0 *gv;
	gv=&sys->Lvar[0][NP0];
	gv->num =sys->Apoint;
	gv->type=VDAI|VARY;
	}
	
	// スタックに積むのは[0]の相対アドレス
	NA0=NADRS;
	NP0=sys->Apoint; // 配列先頭位置
	nstk[0].loc=0; // グローバル
	
	// 配列確保
	ret=ARYMake(jigen,jsize,mode,&NN0); // Abuffが動く可能性がある
	if (len && !ret) { // STRINGS:文字列コピー付き
	    NSTACK ns;
		// nstk[0]を絶対アドレス化したものを使う
		ns=NS0;
		ns.num  +=(long)sys->Abuff;
		ns.point+=(long)sys->Abuff;
		ret=ARYStoreB(&ns,ARYSTRoadrs(&NS1),len);
		// ARYMake()で配列アドレスが変わることがあるので、最初のARYSTRoadrs()と
		// ここをまとめないこと
	}
	return(ret);
}

/*****************************************************************************/

static int Saryadrs(NSTACK nstk[])
/* 配列要素のアドレス計算 */
/* ( x y z ).次元(1) name(NVADR.VARY:0) @ → NADRS(0) */
{
unsint jofst[JIMAX];
int ret,jigen;
	// 配列を示す変数のみ有効
	if ((NA0>>8)!=VARY) return(ARGILL);
	
	/* オフセットの取得 */
	jigen=(int)NN1;
	if ((ret=ARYyouso(jigen,jofst))) return(ret);
	
	#if DEBUG
	{ int i;
	printf2("次元=%d",jigen);
	for (i=0;i<jigen;i++) printf2(",%d",jofst[i]);
	}
	#endif
	
	/* 指定オフセットからアドレスを求める */
	NP0=NN0; // 先頭アドレス
	NA0=NADRS;
	return(ARYJAdrs(NP0,jigen,jofst,&NN0));
}

/*****************************************************************************/

static int Saryrw(NSTACK nstk[],int mode)
// 配列要素のread/write
// write(0) : NADRS(1) data(0) <- → なし
// read (1) : NADRS(0) ->  → data(0;unsigned)
// read (2) : NADRS(0) ->, → data(0;signed)
{
	return(mode==0?
		 ARYWrite(&NS1,NN0) // write
		:(NN0=ARYRead(&NS0,mode-1),NOK) // read
	);
}

/*****************************************************************************/

static int Sarenzan(NSTACK nstk[],int mode)
// 配列アドレスの演算(ofstのみ変化)
// NOADRS(0)         @++(0)/@--(1) → NADRS(0)
// NOADRS(1) NNUM(0) @+ (2)/@- (3) → NADRS(0)
{
long size;
	// アドレスはオフセットで来ている
	if (mode>=2) SwapStack(nstk,0,1); // NNUM(1) NOADRS(0) にする
	size=(long)((stksys->Abuff[NP0]&TYBITS)+1); // １要素のサイズ取得
	if (mode>=2) size*=NN1; // 増減分サイズ
	switch (mode) {
		case 0:// @++
		case 2:// @+
			// 配列のサイズ
			if (ARYosize(&NS0)<size) return(ARSZOVER);
			NN0+=size;
			break;
		case 1:// @--
		case 3:// @-
			// ARYbsize()はオフセットでもそのまま使える
			if (ARYbsize(&NS0)<size) return(ARSZOVER);
			NN0-=size;
			break;
	}
	return(OK);
}

/*****************************************************************************/
/* コマンドテーブル */

STKCOM arytbl[]={
	 {NULL		,NULL	,TNONE,0,0}
	// 定義
	,{"ARY.B"	,Sarray	,TVADRN TNUM,1,0}	// byte
	,{"ARY.W"	,Sarray	,TVADRN TNUM,1,1}	// word
	// mode=2はない(modeがtypeになるから)
	,{"ARY.L"	,Sarray	,TVADRN TNUM,1,3}	// long
	,{"STRING"	,Sarray	,TVADRN	TNUM,1,4}	// byte 1次元
	,{"STRINGS"	,Sarray	,TVADRN	TOSTR1,1,5}	// byte 1次元 with string copy
	// アドレス演算
	,{"@++"		,Sarenzan,TOADRS,1,0}		// +1(要素単位)
	,{"@--"		,Sarenzan,TOADRS,1,1}		// -1(要素単位)
	,{"@+"		,Sarenzan,TNUM TOADRS,1,2}	// +num(要素単位)
	,{"@-"		,Sarenzan,TNUM TOADRS,1,3}	// -num(要素単位)
	,{"@"		,Saryadrs,TVADR TNUM,1,0}	// 配列アドレス計算
	// 読み書き
	,{"<-"		,Saryrw	,TNUM TADRS,0,0}	// write
	,{"->"		,Saryrw	,TADRS,1,1}		// read(unsigned)
	,{"->."		,Saryrw	,TADRS,1,2}		// read(signed)
	,{NULL		,NULL	,TNONE,0,0}
};

/*****************************************************************************/
