/*****************************************************************************/
// ＳＴＫ：オリジナル言語モジュール STacK（中間言語実行型）
/*****************************************************************************/

#include <stdio.h>
#include <doslibm.h>
#include "abuff.h"
#include "stk.h"

/*****************************************************************************/
/* ＳＴＫ内部データ */

STKSYS	*stksys; // 内部データ構造体のアドレス：プログラム全体から参照される
		 // 内部データ構造体の本体はユーザーが与える

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

int OpenSTK(STKSYS *sys)
// ＳＴＫ内部構造体初期化＆ワークエリア確保
{
unchar *work;
	// 変数エリア＆スタック一括確保
	// もし変数システムにバグが有ってあふれた場合、それをスタックがおかしいことで
	// 発見出来る・・・等ということも考えて変数エリアを先に取る
	work=newmalloc(  sys->locmax*sizeof(VAR0 *)
			+sys->nmax  *sizeof(NSTACK)
			+sys->lmax  *sizeof(LSTACK)
			+sys->rmax  *sizeof(RSTACK));
	if (work==NULL) return(1);
	
	/* ワークエリアをそれぞれに割り当てる */
	sys->Lvar  =(VAR0 **)work;			// 変数エリアポインター
	sys->nstack=(NSTACK *)&sys->Lvar[sys->locmax];	// 数値スタック
	sys->lstack=(LSTACK *)&sys->nstack[sys->nmax];	// ラベルスタック
	sys->rstack=(RSTACK *)&sys->lstack[sys->lmax];	// ループスタック
	
	// 内部データ初期化
	sys->loc=sys->ntop=sys->ltop=sys->rtop=0;
	
	// 変数エリアポインターを未使用で初期化
	// [0]はグローバルで使う
	{ int i;
	for (i=0;i<sys->locmax;i++) sys->Lvar[i]=NULL;
	}
	
	return(0);
}

/*****************************************************************************/
/* STKSYS : 次の項目を設定してから呼び出すこと
	argc  : main()のargc
	argv  : main()のargv
	nmax    数値スタック段数   1〜32767（16:NPOPS以下にはしない方がよい）
	lmax    ラベルスタック段数 1〜32767
	rmax    ループスタック段数 1〜32767
	locmax  ローカル変数段数   1〜32767（1の場合ローカル変数は使えなくなる）
	vsize   変数最大個数	   8〜32767
	vlmax   １変数名最大長	   8〜250
	lsize   ラベル最大個数	   8〜32767
	llmax   １ラベル名最大長   8〜250
 各引数の範囲チェックはしていないので注意

mode	動作モード
	MDfctrl		0=BREAK/CTRL-Cをtoken毎にチェック
			1=BREAK/CTRL-C無効
	MDftrace	00=なし, 01=token表示あり , 10=callのみ表示（表示固定位置）
			       , 11=toke表示（表示固定位置）
	MDntrace	0=なし , 1=nstack内容表示あり
	MDltrace	0=なし , 1=lstack内容表示あり
	MDrtrace	0=なし , 1=rstack内容表示あり
*/
/*****************************************************************************/

int STK(unchar *text,STKCOM *tkntbls[],STKSYS *sys,unlong mode,long *num)
// ＳＴＫ実行（初期化・中間コード化・実行・終了）
{
int brk;   // Human68K break状態
int badrs; // 元のCTRL-Cベクター
unchar *ctext;
int ret;
extern void _BREAK();
#define	BRKVEC	0x2d	// CTRL-Cベクター番号
	// CTRL-Cを無視させる
	badrs=INTVCS(BRKVEC,(char *)_BREAK);
	brk=BREAKCK(-1);
	BREAKCK(2);
	
	// ＳＴＫ初期化
	if (OpenSTK(sys)) {
		ret=STKOPEN;
		goto RETC;
	}
	
	// 内部データ構造体アドレス記録
	stksys=sys;
	sys->mode=mode; // 実行モードだけは変更しやすいように別に与える
	
	// 外部コマンドトークン追加
	// 必要なコマンドトークンは中間コード化前にリンクしておく
	AddComToken(tkntbls);
	
	// グローバル変数処理初期化（変数名記録は名前のみ）
	// 中間コード化時にも使うのでここで初期化する
	if (sys->vlmax>=SCVMAX ||
	    VarOpen(sys->vsize,sys->vlmax,0,&sys->Gvar)) {
		ret=VAROPEN;
		goto RETS;
	}
	
	// 中間コード化（領域確保込み;コマンドリンクはこの中で行われる）
	ret=STKSemiCompile(text,&ctext);
	if (!ret) {
		// メイン処理
		ret=STKmain(ctext,num);
		if (ret>0) ErrCode2Token(); // エラー時：エラーメッセージ固定
		// 中間コードエリア解放
		free(ctext);
	}
	// グローバル変数領域解放
	VarClose(&sys->Gvar);
	
    RETS:;
	// ＳＴＫ終了
	CloseSTK();
	
    RETC:;
	// CTRL-Cを戻す（不要かも知れないけど）
	BREAKCK(brk);
	INTVCS(BRKVEC,(char *)badrs);
	return(ret);
}

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