/*****************************************************************************/
// ＳＴＫ：中間コード実行モジュール
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "defines.h"
#include "amacro.h"
#include "abuff.h"
#include "akey.h"
#include "stk.h"

extern STKSYS *stksys;

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

static int OnAction(int no,unchar *ctext0,unchar *(*ctext))
// 特別処理
// no:0=error , 2=break
// ctext0 : 特別処理を起こした中間コードアドレス
// ctext  : 飛び先を入れて返す
{
STKSYS *sys;
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	if (sys->onact[no+1]==NULL) {
		if (sys->onact[no]!=NULL) { // ON*設定があるときはそこに飛ぶ
		        sys->onact[no+1]=ctext0; // 戻りポイントを記録する
			*ctext=sys->onact[no];
			// Action
			return(1);
		} // 設定がないときは中断
	} // 処理中は多重処理しない
	// No Action
	return(0);
}

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

#ifndef NOTRACE
void TracePrint(unchar *mes)
// トレース表示
{
int xy,c;
	if (stksys->mode&MDftraceK) { // 固定表示
		c=B_COLOR(HLIGHT|TYELLOW); // 現在の色を保存して強調＋黄色にする
		xy=B_LOCATE(0,0);	  // 表示座標+現在のカーソル位置保存
		printf2(mes); 		  // メッセージ表示
		printf2("  ");
		B_LOCATE((xy>>16)&0xffff,xy&0xffff); // カーソル戻し
		B_COLOR(c);		  // 色戻し
	} else { // そのまま位置
		printf2(mes);		  // メッセージ表示
		printf2("\t");
	}
}
#endif

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

int STKmain(unchar *ctext,long *data)
/* 中間コードを実行する（前後処理は別に行うこと）
	ctext	中間コードテキスト
	data	<- 最後のntop.num値(END.時のみ)
*/
{
int i,ret;
unchar *text,*ctext0;
short fbrk;
STKSYS *sys;
extern volatile unchar FBREAK;	// CTRL-Cフラグ
	sys=stksys; // 省メモリーのためローカル変数に置き換える
	SetErrToken("STKmain");
	
	// 配列エリア確保(初期)
	// メモリー確保が非常に複雑なので、拡大される可能性のあるここを一番最後に確保する
	if ((sys->Abuff=newmalloc(ASIZE))==NULL) return(NGAAREA);
	sys->Asize=ASIZE;
	sys->Apoint=0;
	
	// グローバル変数準備
	// グローバル変数はadrs以外はVAR0にコピーしてローカル変数と同じアクセス方法にする
	if ((sys->Lvar[0]=(VAR0 *)newmalloc(sizeof(VAR0)*sys->Gvar.vpoint))==NULL) {
		ret=LOCOPEN;
		goto Ending2;
	}
	for (i=0;i<sys->Gvar.vpoint;i++) {
	    VAR0 *lv;
	    VAR1 *gv;
		lv=&sys->Lvar[0][i];
		gv=&sys->Gvar.vwork[i];
		lv->type=gv->type;
		lv->num =gv->num;
	}
	// 本当は、この時にGvar中で変数のみを取り出して再構成し、VarCloseしてしまえば
	// 実行時の使用メモリーが減る・・・はずだが、現在はVarCloseするとNameBuffも解放される
	// のでこの方法が使えない。残念。
	
	// コマンド初期化
	if ((ret=ComInit())) goto Ending3;
	
	/* 中間コードテキスト実行 */
	/* 中間コード化の時に主な文法エラーチェックは行われているので、
		ここでは実行時エラーのみチェックされる */
	fbrk=sys->mode&MDfctrl;
	sys->errno=OK;
	for (i=0;i<4;i++) sys->onact[i]=NULL; // エラートラップ解除
	ret=NOTOKEN; // tokenなしでいきなり終わるときのため
	FBREAK=0;
	*data=0L;
	while (1) {
	  NEXT:;
	    #ifndef NOTRACE
	    if (sys->mode&MDftrace) { // trace
		if (!( // label trace
			(sys->mode&MDftrace)==MDftraceK && *ctext!=SCCALL
		)) TracePrint(RemakeToken(ctext));
	    }
	    #endif
	    
	    ctext0=ctext; // これから実行する中間コード
	    ret=STKinterpret(&ctext,&text); // 実行
	    
	    if (ret==COK) fbrk=0; // 強制CTRL-Cチェック(いったん有効にする)
	    else
	    if (ret!=OK) { // error/end
		SetErrCode(ctext0); // エラー発生時
		break;
	    }
	    
	    if (text!=NULL) ctext=text; /* テキストポインターが変わった */
	    
	    /* BREAK/CTRL-Cチェック */
	    if (fbrk) continue; // チェック無効
	    if (ret==COK) fbrk=sys->mode&MDfctrl; // 戻す
	    if (FBREAK) { // FBREAKはCTRL-C割り込みによってセットされる
		/* キーボードバッファークリア
		   これをしないとCTRL-Cがバッファーに残り、BREAK ONされた直後に
		   CTRL-C処理されてしまう
		*/
		Kbclr();
		sys->errno=ret=CTRLC;
		if (!OnAction(2,ctext0,&ctext)) break; // 中断する
		// ONBREAK
		FBREAK=0;
	    }
	} // tokenがなくて終了した時は*data=0
	
	if (ret<=ENDOK) { /* 正常終了 */
		if (ret==ENDOK2) { // 最後のntopを返す
		    NSTACK ns;
			ret=PopNStack(&ns);
			*data=ns.num;
		} else 	ret=OK;
	} else	{ /* エラー終了 */
	    if (ret!=CTRLC) {
		sys->errno=ret;
		if (OnAction(0,ctext0,&ctext)) goto NEXT; // ONERROR
	    } // CTRL-C処理でエラー終了している時はここでは処理しない
	}
	// 後処理
	// コマンド終了処理
	if ((i=ComEnd())) {
	    // 終了処理中にｴﾗｰ発生
	    if (!ret && sys->onact[1]==NULL && sys->onact[3]==NULL) {
		// 他のエラーがなく、かつトラップ処理中でない時有効
		// onact[1,3]のどちらかがNULLでない時はどちらかの処理中
		ret=i;
		SetErrToken("ComEnd"); // ﾃｷｽﾄのどこが原因かはわからない
	    }
	}
    Ending3:;
	// 変数の領域解放
	for (i=0;i<sys->locmax;i++) {
		if (sys->Lvar[i]!=NULL) free(sys->Lvar[i]);
	}
	// 変数領域ポインターの配列も解放する
	free(stksys->Lvar);
    Ending2:;
	// 配列解放
	free(sys->Abuff);
	// なぜか↓がないとＳＴＫ内でのキー入力が外に出てしまうことがある。
	Kbclr();
	return(ret);
}

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