/* 中間コード識別＆実行（実行時：もちろん切り放し不可）*/

#include "stk.h"

extern STKSYS *stksys;

int STKinterpret(unchar *(*ctext0),unchar *(*text))
/* ctextからにある１中間コードを判別して処理する */
/* text!=NULL:テキストポインターが飛ぶ , ==NULL:飛ばない */
/* ctext <- 次の命令の位置 */
{
unchar *ctext,len;
int no,ret;
long dt;
	*text=NULL; /* テキストポインタは移動しないの印 */
	ctext=*ctext0;
	no=*ctext++;		// 識別子
	len=*ctext++;		// 領域長
	dt=*(long *)ctext;	// データ
	if (no>SCCMD) { /* コマンド以外 */
	  NSTACK ns;
	    switch (no) {
		case SCCOMT: // コメント → 単に飛ばすだけ（無視される）
		    ret=OK;
		    break;
		
		case SCNUM: // 数値
		    ns.num=dt;
		    ns.point=0L;
		    ns.atrb=NNUM;
		    ret=PushNStack(&ns);
		    break;
		
		case SCVAR: // 変数
		    ns.point=dt;
		    ns.atrb=STKVarRead(dt,&ns);
		    ret=PushNStack(&ns);
		    break;
		
		case SCSTR1: // 固定文字列 : 絶対アドレスをスタックに積む
		    ns.num=(long)ctext;
		    ns.point=len; // この長さは偶数化せず元のまま
		    len=EvenLen(len); // 偶数バイト化
		    ns.atrb=NSTR1;
		    ret=PushNStack(&ns);
		    break;
		
		case SCLBL: // ラベルアドレス : labelはラベルそのものを積む
		    ret=PushLStack((unchar *)dt,LLBL);
		    break;
		
		case SCCALL:// callラベルアドレス : label.はlabel call相当
		    *text=(unchar *)dt; // 飛び先
		    /* リターンポイントを記録する */
		    ret=PushLStack((unchar *)(ctext+LLONG),LRET);
		    break;
		
		case SCEND: /* 	中間コード終わり */
		    return(ENDOK);
		
		default:
		//case SCCAL0: /* 未定義callﾗﾍﾞﾙ */
		    /* 実行時に未定義ラベルがあってはだめ */
		    return(STKCodeErr(no,"intp"));
	    }
	    ctext+=len;
	} else { /* コマンド */
	  NSTACK nstk[NPOPS];
	  STKCOM *tbl;
	  int ret0,i;
	  unchar *jump=NULL;
	    /* テーブルセット */
	    if (no&FJUMP) { /* ジャンプアドレス付き */
		no^=FJUMP; /* フラグを外す */
		jump=*(unchar **)(ctext+LLONG); /* ｼﾞｬﾝﾌﾟｱﾄﾞﾚｽ */
	    }
	    ctext+=len;
	    
	    /* 数値取り出し＆型チェック（変数の時はその内容へ変更も出来る）*/
	    tbl=(STKCOM *)dt;
	    tbl=&tbl[no];
	    if ((ret=STKChgVarNum(tbl->list,nstk))) return(ret);
	    
	    /* コマンド呼び出し */
	    ret0=tbl->func(nstk,(int)tbl->mode,ctext,&jump,text);
	    if (ret0>OK||ret0<=ENDOK) return(ret0); /* ｴﾗｰまたはENDで終了 */
	    if (ret0==NOK) { // NN0=num付き
		NP0=0L;
		NA0=NNUM;
		// 後はOKと同じ
	    }
	    /* 結果をnstackに積む（読み出した逆順に積む＝これで元に戻る）*/
	    for (i=tbl->ret-1;i>=0;i--) {
		if ((ret=PushNStack(&nstk[i]))) return(ret);
	    }
	    if (jump!=NULL) { /* ｼﾞｬﾝﾌﾟｱﾄﾞﾚｽが確定して戻ってきた時 */
		/* 中間コード領域にｼﾞｬﾝﾌﾟｱﾄﾞﾚｽを書き込む */
		*(long *)(ctext-LLONG)=(long)jump;
	    }
	    
	    /* リターン値別処理 */
	    switch (ret0) {
		default: /* 何もなし */
		    ret=OK;
		    break;
		case COK: /* CTRL-C/BREAKチェック付き */
		    ret=ret0;
		case LOK: // ｼﾞｬﾝﾌﾟ:ﾃｷｽﾄﾎﾟｲﾝﾄはﾄｰｸﾝ内で変更されている
		    break;
	    }
	}
	*ctext0=ctext;
	return(ret);
}
