/*****************************************************************************/
/* ＳＴＫ外部コマンド：デバッグ用 */
/*****************************************************************************/

#include "stk.h"
#include "acdata.h"
#include "amacro.h"

extern STKSYS *stksys;

// 処理の簡略化のため、n/l/rtopすべて同じ段数ネスティング可能とする
#define TOPS	10		// topネスティング可能段数
static	short	 top[3][TOPS]	// tops=現在の段数、top=n/l/rtop位置
		,tops[3];	// 0=ntop,1=ltop,2=rtop

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

// ここの中だけで特有なエラー
static ERRMES ERRdebug[]={
	/* この順はSChkStackのmodeの順になっているの変更しないこと */
	 {NPOVER	,"[Nが多すぎる"}
	,{LPOVER	,"[Lが多すぎる"}
	,{RPOVER	,"[Rが多すぎる"}
	,{NPNONE	,"[Nがないのに]Nがある"}
	,{LPNONE	,"[Lがないのに]Lがある"}
	,{RPNONE	,"[Rがないのに]Rがある"}
	,{0,NULL}
};
static ERLINK erlist={ERRdebug,NULL};

static int SdStart()
// 初期化処理
{
int i;
	// [? 〜 ]?初期化
	for (i=0;i<3;i++) tops[i]=0; // 0=ntop,1=ltop,2=rtop
	return(STKErrLink(&erlist));
}

static int SdEnd()
// 終了
{
int i;
	for (i=0;i<3;i++) { // 0=ntop,1=ltop,2=rtop
		if (tops[i]>0) return((int)ERRdebug[i].eno);
	}
	return(OK);
}

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

static int SChkStack(NSTACK nstk[],int mode)
// スタック整合性チェック
// [? 〜 ]? : ?=N,L,R（ネスティング可）
{
STKSYS *sys;
short tp;
int md;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	md=mode%3;
	tp=(md==0? sys->ntop:(md==1? sys->ltop:sys->rtop));
	if (mode<=2) { // [?
		if (tops[md]>=TOPS) return((int)ERRdebug[mode].eno);
		top[md][tops[md]++]=tp;
	} else { // ]?
	    static short err[3]={NTOPERR,LTOPERR,RTOPERR};
		// num(0:NNUM) ]N : numには<0の設定も出来る
		if (mode!=3) NN0=0; // ]L/]Rはnum指定不可
		if (tops[md]==0) return((int)ERRdebug[mode].eno);
		if (top[md][--tops[md]]+NN0!=tp) return((int)err[md]);
	}
	return(OK);
}

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

static int Strace(NSTACK nstk[],int mode)
/* トレースモード設定 */
// mode(0) trace  → なし
{
unlong md;
	/*
	BIT0,1	1〜3	0=なし , 1=token表示あり , 2=callのみ表示（表示固定位置）
			       , 3=toke表示（表示固定位置）
	BIT2	4	0=なし , 1=nstack内容表示あり
	BIT3	8	0=なし , 1=lstack内容表示あり
	BIT4	16	0=なし , 1=rstack内容表示あり
	*/
	// NOTRACE=1のときはこのコマンドはまったく無効になる
	// ただし、ソースをそのまま実行できるようにコマンドとしては残す
	md=(unlong)NN0;
	if (md<0||md>MDTRmax) return(ARGILL);
	stksys->mode=(stksys->mode&(~(unlong)MDbitsTR))|(md<<MDTRbit);
	return(OK);
}

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

static int Scom_list()
/* コマンドリスト */
/* COMLIST → なし */
{
int i,len,tno=0;
STKCOM *tbl,*tbli;
	tbl=FirstComLink(); // 最初のテーブル
	do {
	    printf2("------------------------\n");
	    if (tbl[0].func!=NULL) printf2("[初期化有り]\n");
	    i=1;
	    while (tbli=&tbl[i],tbli->name!=NULL) {
		/* コマンド名表示 */
		len=printf2(tbli->name);
		if (len>=16) printf2("\t"); else while (len<16) {printf2(" "); len++;}
		/* 引数／リターン値表示 */
		if (printf2("入力:%s",(tbli->list[0]? tbli->list:(unchar *)"なし"))<=5+2) {
			printf2("\t");
		}
		tno++; /* 総コマンド数 */
		// printf2("\t出力:%2d\t(%3d/%3d)\n",tbli->ret,i,tno);
		printf2("\t出力:%2d\n",tbli->ret);
		i++;
	    }
	    if (tbli->func!=NULL) printf2("[終了化有り]\n");
	    tbl=(STKCOM *)tbl[0].name;
	} while (tbl!=NULL);
	return(OK);
}

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

static int Sary_dump(NSTACK nstk[])
// 配列領域簡易ダンプ
// size(0) ARYDUMP → なし
// size : >0 先頭のsize要素のみ表示(int範囲)
{
static unchar *ymes[]={"BYTE","WORD","異常","LONG"};
int i,type,jigen;
long p,sz;
unchar *src;
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	printf2("--- 配列 ---\n");
	if (sys->Apoint==0) {
		printf2("なし\n");
	} else { // 配列はある
	    p=0L;
	    while (p<sys->Apoint) {
		/* 属性 */
		src=&sys->Abuff[p];
		type=(*src++)&TYBITS;      // 要素サイズ
		jigen=((*src++)&JIBITS)+1; // 次元
		sz=*(long *)src;	   // 本体サイズ
		src+=LLONG;
		printf2("%p[%d]:%s:",sys->Abuff,p,ymes[type]);
		for (i=0;i<jigen;i++) {
			printf2("%d%c",*(unsint *)(src+i*LSHORT)
						,i==jigen-1? '\n':',');
		}
		src+=(LSHORT*JIMAX); // 今の配列の本体へ
		  p+=(ARYHEAD+sz); // 次の配列の先頭まで飛ばす
		// 内容表示
		type++;
		sz/=type; // 要素数に変換
		if (NN0<sz) sz=NN0;
		for (i=0;i<(int)sz;i++) {
		    switch (type) {
			case ARYBYTE+1:
				printf2(" %02x",*src);
				break;
			case ARYWORD+1:
				printf2(" %04x",*(unsint *)src);
				break;
			case ARYLONG+1:
				printf2(" %08x",*(unlong *)src);
				break;
		    }
		    src+=type;
		}
		if (sz>0L) printf2("\n");
	    }
	}
	return(OK);
}

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

static unchar *Vmode(int level)
// 変数のレベルを示す文字列を返す
{
	return(level? "ローカル":"グローバル");
}

static void STKVarDump(int base,int loc)
// 変数領域ダンプ
{
STKSYS *sys;
short p;
unsint type;
VAR0 *lv;
VAR1 *gv;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	for (p=VTOP2;p<sys->Gvar.vpoint;p++) {
	    // 型
	    lv=&sys->Lvar[loc][p];
	    type=lv->type;
	    if (!(type&VKAKU)) {
		// ----------- 表示 ---------------------------
		// 変数名
		gv=&sys->Gvar.vwork[p];
		printf2("%s\t",gv->adrs+(sys->Gvar.mode&BIT0));
		// 数値
		printf2("%d",lv->num);
		if (base!=10) { // 10進以外指定の時は同時表示
		    unchar dec[2+BINT+1];
			printf2("(%s)",&dec[make_base(lv->num,dec,base+100)]);
		}
		// type
		printf2("[%d]%s\n",type&VTYPE,(type&VDAI? "(LOCK)":""));
	    } // 現在の変数システムでは未確定変数は表示できないのでスキップする
	}
}

static int Svar_dump(NSTACK nstk[])
/* 変数のダンプ */
/* level(1) base(0) VARDUMP → なし */
/* level : 0=グローバル , 1=現在レベルのローカル（グローバルの場合もあり）*/
/* base  : 表示進数(2/8/10/16) , BIT15 */
{
int n,level=0; /* グローバル */
	if (NN1) level=stksys->loc;
	printf2("--- 変数(%s) ---\n",Vmode(level));
	n=NN0&(~BIT15);
	if (n<2||n>16) return(ARGERR); /* 表示出来ない進数 */
	STKVarDump((int)NN0,level);
	return(OK);
}

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

static int Ssys_dump()
// システム状態表示 : SYSDUMP → なし
{
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	printf2(
		/* 変数管理 */
		"-- 変数 --\n"
		"状態:%s(%d)\n"
		"最大数:%d\n"
		"最大長:%d\n"
		"段数:%d\n"
		
		/* 配列エリア */
		"-- 配列 --\n"
		"領域サイズ:%d\n"
		"書込アドレス:%x\n"
		
		/* 変数管理 */
		,Vmode(sys->loc),sys->loc
		,sys->Gvar.vwsize
		,sys->Gvar.vlmax
		,sys->locmax
		
		/* 配列エリア */
		,sys->Asize
		,&sys->Abuff[sys->Apoint]
	);
	return(OK);
}

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

static void DispNSTACK(short i)
{
static unchar *vmode[]={":VNUM",":VARY",":VSTR1"};
NSTACK *nstk;
unchar c;
	nstk=&stksys->nstack[i];
	//c=nstk->atrb&0xff;
	c=(unchar)nstk->atrb;
	printf2("%d/$%x[%c]\t%d%s:%d"
		,nstk->num,nstk->num
		,c
		,nstk->point
		,c==(unchar)NVADR? vmode[nstk->atrb>>8]:(unchar *)""
		,nstk->loc
	);
}

static void DispLSTACK(short i)
{
LSTACK *lstk;
	lstk=&stksys->lstack[i];
	printf2("$%x[%c]",lstk->adrs,lstk->atrb);
}

static void DispRSTACK(short i)
{
RSTACK *rstk;
	rstk=&stksys->rstack[i];
	printf2("%d,%d",rstk->start,rstk->end);
}

static int Sstk_dump(NSTACK nstk[],int mode)
/* スタックダンプ */
/* mode(0) ?STKDUMP → なし : 0=ダンプ無し , 1=ダンプあり */
{
short max,top,i;
unchar *mes;
void (*func)(short);
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	switch (mode) {
	    case 0: // 数値スタック   : mode(0) NSTKDUMP -> なし
		mes="n数値";
		max=sys->nmax;
		top=sys->ntop;
		func=DispNSTACK;
		break;
	    case 1: // ラベルスタック : mode(0) LSTKDUMP -> なし
		mes="lラベル";
		max=sys->lmax;
		top=sys->ltop;
		func=DispLSTACK;
		break;
	    case 2: // ループスタック : mode(0) RSTKDUMP -> なし
		mes="rループ";
		max=sys->rmax;
		top=sys->rtop;
		func=DispRSTACK;
		break;
	}
	printf2("--- %sスタック ---\n段数=%d,%ctop=%d\n",mes+1,max,*mes,top);
	if (NN0) {
		for (i=0;i<top;i++) {
			printf2("%3d\t",i);
			func(i);
			printf2("\n");
		}
	}
	return(OK);
}

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

STKCOM systbl[]={
	 {NULL		,SdStart	,TNONE,0,0}
	,{"[N"		,SChkStack	,TNONE,0,0}	// 数値ｽﾀｯｸﾁｪｯｸ開始
	,{"[L"		,SChkStack	,TNONE,0,1}	// ﾗﾍﾞﾙｽﾀｯｸﾁｪｯｸ開始
	,{"[R"		,SChkStack	,TNONE,0,2}	// ﾙｰﾌﾟｽﾀｯｸﾁｪｯｸ開始
	,{"]N"		,SChkStack	,TNUM ,0,3}	// 数値ｽﾀｯｸﾁｪｯｸ
	,{"]L"		,SChkStack	,TNONE,0,4}	// ﾗﾍﾞﾙｽﾀｯｸﾁｪｯｸ
	,{"]R"		,SChkStack	,TNONE,0,5}	// ﾙｰﾌﾟｽﾀｯｸﾁｪｯｸ
	,{"TRACE"	,Strace		,TNUM ,0,0}	// トレースモード設定
	,{"COMLIST"	,Scom_list	,TNONE,0,0}	// コマンド表示
	,{"ARYDUMP"	,Sary_dump	,TNUM ,0,0}	// 配列内容表示
	,{"VARDUMP"	,Svar_dump	,TNUM TNUM,0,0}	// 変数表示
	,{"SYSDUMP"	,Ssys_dump	,TNONE,0,0}	// システム情報表示
	,{"NSTKDUMP"	,Sstk_dump	,TNUM ,0,0}	// 数値スタック表示
	,{"LSTKDUMP"	,Sstk_dump	,TNUM ,0,1}	// ラベルスタック表示
	,{"RSTKDUMP"	,Sstk_dump	,TNUM ,0,2}	// ループスタック表示
	,{NULL		,SdEnd		,TNONE,0,0}
};

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