/*****************************************************************************/
/* ＳＴＫコマンド：スタック操作（切り放し可能）*/
/*****************************************************************************/

#include "stk.h"

extern STKSYS *stksys;

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

static int Snstack(NSTACK nstk[],int mode)
// スタック操作
{
short n;
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	n=(short)NN0;
	switch (mode) {
		// リターン値がないもの
		case 1:	// <>  : nstack top<->top+1を入れ換える
		case 2:	// <-> : nstack top<->top+2を入れ換える
			// modeを入れ換えるスタック位置と兼ねている
			// 非常に危険な書き方なので注意
			SwapStack(nstk,0,mode);
			break;
		case 4:	// . : nstack topをコピーして積む
			NS1=NS0;
		case 3: // , : nstack topを捨てる
			// 実は何もしなくていい
			break;
		
		// 各スタックポインタ設定
		case 0:	// NCLR : nstackを空にする
			n=0;
		case 5:	// NTOP= : set ntop
			if (n<0||n>=sys->nmax) return(NTOPERR);
			sys->ntop=n;
			break;
		case 6:	// LTOP= : set ltop
			if (n<0||n>=sys->lmax) return(LTOPERR);
			sys->ltop=n;
			break;
		case 7: // RTOP= : set rtop
			if (n<0||n>=sys->rmax) return(RTOPERR);
			sys->rtop=n;
			break;
		
		// 各スタックポインタ読みだし
		case 8:	// NTOP : ntopを返す
			NN0=sys->ntop;
			break;
		case 9:	// LTOP : ltopを返す
			NN0=sys->ltop;
			break;
		case 10:// RTOP : rtopを返す
			NN0=sys->rtop;
			break;
	}
	return(mode>=8? NOK:OK);
}

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

#define TOPS	10			// ntop0ネスティング可能段数
static	short	ntop0[TOPS],tops;	// ( ) 用スタック位置記録

static int Scprev(NSTACK nstk[],int mode)
// ( 〜 )/). : nstack内容を逆順にする（同時にカウントもできる）
{
short ntop,ntp0;
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	ntop=sys->ntop;
	switch (mode) {
	    case 0: // ( : 最初の位置を記録するだけ
		if (tops>=TOPS) return(REVPOVER);
		ntop0[tops++]=ntop;
		break;
	    case 2: // ). : 反転＋カウント
		NN0=0L; // カウントできないときのため
	    case 1: // )  : 反転（ntopは不変）
		if (tops==0) return(REVPNONE);
		ntp0=ntop0[--tops];
		if (ntop>ntp0) {
		    int h,i;
			/* 入れ換え */
			h=ntop-ntp0;
			for (i=0;i<h/2;i++) SwapStack(sys->nstack,ntp0+i,ntop-1-i);
			NN0=h; // 個数を返す(mode==2でしか有効にならない)
		} /* リバース出来ない時はしない（エラーにはしない）*/
		break;
	
	}
	return(mode==2? NOK:OK);
}

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

// ここの中だけで特有なエラー
static ERRMES ERRstack[]={
	 {REVPOVER	,"(が多すぎる"}
	,{REVPNONE	,"(がないのに)/).がある"}
	,{0,NULL}
};
static ERLINK erlist={ERRstack,NULL};

static int StackInit()
// 初期化
{
	tops=0;
	return(STKErrLink(&erlist));
}

static int StackEnd()
// 終了
{
	// 最後の(状態を調べてエラー判定
	return(tops>0? REVPOVER:OK);
}

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

STKCOM stktbl[]={
	 {NULL		,StackInit,TNONE,0,0}
	/* スタック制御 */
	,{"NCLR"	,Snstack,TNONE,0,0}		// nstackを空にする
	// この<>,<->の位置(mode=1,2)は絶対に動かさないこと
	,{"<>"		,Snstack,TANO TANO,2,1}		// ntop <-> ntop+1
	,{"<->"		,Snstack,TANO TANO TANO,3,2}	// ntop <-> ntop+2
	,{","		,Snstack,TANO ,0,3}		// ntopを捨てる
	,{"."		,Snstack,TANO ,2,4}		// ntopを積む
	/* スタック保護／復帰 */
	,{"NTOP="	,Snstack,TNUM ,0,5}		// set ntop
	,{"LTOP="	,Snstack,TNUM ,0,6}		// set ltop
	,{"RTOP="	,Snstack,TNUM ,0,7}		// set rtop
	,{"NTOP"	,Snstack,TNONE,1,8}		// read ntop
	,{"LTOP"	,Snstack,TNONE,1,9}		// read ltop
	,{"RTOP"	,Snstack,TNONE,1,10}		// read rtop
	/* ↑nstackを直接扱うものは、数値化してはいけない（素のスタック内容を使う）*/
	,{"("		,Scprev,TNONE,0,0}	// 範囲のnstackを逆順にする
	,{")"		,Scprev,TNONE,0,1}
	,{")."		,Scprev,TNONE,1,2}	// 逆順＋個数数え
	,{NULL		,StackEnd,TNONE,0,0}
};

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