/*****************************************************************************/
/* ＳＴＫコマンド：基本制御構文（切り放し可能だけどしない方がいい）*/
/*****************************************************************************/

#include "stk.h"

extern STKSYS *stksys;
extern STKCOM kou0tbl[]; /* 命令名を参照するため */

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

static int Sgo(NSTACK nstk[],int mode,unchar *text,unchar *(*jump),unchar *(*go))
// label GOTO／RETURN → なし
{
char atrb;
int ret;
	ret=PopLStack(go,&atrb,0); // go <- 飛び先ラベル
	if (!ret) {
		ret=LOK;
		if (mode) { // return
			if (atrb!=LRET) ret=RETERR;
		} else {    // goto
		    if (atrb!=LLBL) ret=LBLERR;
		    else {
			if (*go==NULL) ret=OK; // LNULLのときはジャンプしない
			else
			if (((int)(*go))&1) (*go)--; // LNEXTのときはアドレスを補正する
		    }
		}
	} // error
	return(ret);
}

/*---------------------------------------------------------------------------*/

static int Sif(NSTACK nstk[],int mode,unchar *text,unchar *(*jump),unchar *(*go))
// 式(0) IF(成立)/ELIF(不成立) 〜 ELSE 〜 ENDIF → なし
// 式(0) IF.(成立)/EL.(不成立) : 直後の１コマンド実行
{
	if (mode>=4) { // IF./EL.
		// 条件チェック
		if (mode==5) NN0=!NN0; // EL. : 条件の反転
		// 成立時は何もしない→後に続くtokenを実行する
		if (NN0) return(OK);
		
		// 条件不成立時には直後の１コマンドを飛ばす
		if (*jump==NULL) { // ジャンプ先がわかっていないとき
		    unchar len;
			len=*++text; // skip code
			*jump=text+1+EvenLen(len); // skip len + 偶数バイト化
		}
	} else {
	    int etoken=0; // for ELSE : ENDIFへ飛ぶだけ
		switch (mode) {	// 条件チェック
			case 1: /* elif */
				NN0=!NN0; /* 条件の反転 */
			case 0: /* if */
				/* 成立時は何もしない→後に続くtokenを実行する */
				if (NN0) {
			case 2: /* endif : 何もしない（単なる飛び先）*/
					return(OK);
				}
				/* 条件不成立時にはelse/endifまで飛ばす */
				etoken=-4; // else : nest=1でのみ有効
				break;
		} // 	case 3: // ELSE : ENDIFへ飛ぶだけ : ここでは何もしない
		if (*jump==NULL) { /* ジャンプ先がわかっていないとき */
		    unchar *btext;
			// elseまたはendifに飛ぶ(正確にはその次のトークンへ飛ぶ)
			if (STKSearchPair(kou0tbl,1,2,3,etoken,&text,&btext)) return(IFERR);
			*jump=text;
		}
	}
	// ジャンプさせる
	*go=*jump;
	return(LOK);
}

/*---------------------------------------------------------------------------*/

static int Sslabel(NSTACK nstk[],int mode,unchar *text)
// 特殊ラベル
{
	if (!mode) {
		// LNULL → なし : NULLラベル（実際にはジャンプしない）
		text=NULL;
	} else {// LNEXT → なし : NEXTラベル（次のコマンドを示す）
		text++; // わざと奇数アドレスにして他のラベルと区別する
	}
	return(PushLStack(text,LLBL));
}

/*---------------------------------------------------------------------------*/

static int Send(NSTACK nstk[],int mode)
/* 終了／CTRL-C強制チェック */
{
static int rets[]={ENDOK,ENDOK2,COK};
	return(rets[mode]);
}

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

// ここの中だけで特有なエラー
static ERRMES ERRkoubun0[]={
	 {IFERR	,"ENDIFがない"}
	,{RETERR,"RETURN異常"}
	,{0,NULL}
};
static ERLINK erlist={ERRkoubun0,NULL};

static int Kobun0Init()
/* 初期化 */
{
	return(STKErrLink(&erlist));
}

static int Kobun0End()
/* 終了 */
{
	return(stksys->ltop>0? LSTKERR:OK); /* ラベルが残っている */
}

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

STKCOM kou0tbl[]={
	 {NULL		,Kobun0Init,TNONE,0,0}
	/* IF系命令の上４つは処理内で[n]を参照するのでこの位置を変えないこと */
	,{"IF"		,Sif	,TNUM	,CFJUMP,0} 	/* 式 if endif */
	,{"ELIF"	,Sif	,TNUM	,CFJUMP,1} 	/* 式 elif endif */
	,{"ENDIF"	,Sif	,TNONE	,0,2}
	,{"ELSE"	,Sif	,TNONE	,CFJUMP,3}	/* if - else - endif */
	//
	,{"IF."		,Sif	,TNUM	,CFJUMP,4} 	// 式 if.
	,{"EL."		,Sif	,TNUM	,CFJUMP,5} 	// 式 el.
	/* */
	,{"GOTO"	,Sgo	,TNONE	,0,0}	/* label goto */
	,{"RETURN"	,Sgo	,TNONE	,0,1}	/* return */
	/* その他 */
	,{"LNULL"	,Sslabel,TNONE	,0,0}	// NULLラベル
	,{"LNEXT"	,Sslabel,TNONE	,0,1}	// NEXTラベル
	,{"END"		,Send	,TNONE	,0,0}	/* end */
	,{"END."	,Send	,TNONE	,0,1}	/* end. : ntopを返す */
	,{"CHKBRK"	,Send	,TNONE	,0,2}	/* CTRL-Cチェック */
	/* End of table */
	,{NULL		,Kobun0End,TNONE,0,0}
};

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