/*****************************************************************************/
/* 変数対応 式評価ルーチン */
/*****************************************************************************/

#include "defines.h"
#include "amacro.h"
#include "vsiki.h"

extern	VSSYS	Vsikis;

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

static int Dainyu(long v2,VARSYS *var)
/* 変数への代入処理 */
{
long p;
	p=Vsikis.pstack[Vsikis.vs-1];
	if (p<0) { /* 未確定変数 */
		if (var->mode&BIT15) return(VARNAC); /* 未確定変数に代入しようとした */
		p=-p; /* 未確定->確定代入 */
	}
	else
	if (p==0) return(VSNUMST); /* 数値に代入しようとした */
	/* ここでは数値代入しかできない */
	if (var_num_write(p,v2,0,var)<0) return(VARCSTA); /* 再代入不可ならエラー */
	/* vsiki内ではエリアのエラーは出ない */
	return(0);
}

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

int vsiki(unchar *(*str0),long *num0,VARSYS *gvar,VARSYS *lvar)
/* 式評価ルーチン（変数対応）*/
/* return : >0:error , 0=継続無し , -1=継続(',''\n')あり */
{
long num,p=0;
unsint en,een;
unchar *str,*str1,c;
short fv=0,fc=0,ff=1; /* 数値フラグ、括弧フラグ、符号フラグ */
int status,err;
VARSYS *var;
	/* 代入時、ローカル／グローバル、どちらの変数が有効か */
	var=(lvar==NULL||lvar->vwork==NULL||lvar==gvar? gvar:lvar);
	
	/* スタックに数値、演算子を積む */
	Vsikis.vs=Vsikis.es=0;
	str=*str0;
	while (c=*str,c!=0&&c!=','&&c!='\n') {
	    if (c==SPC||c==TAB) {
		str++;
		continue;
	    }
	    /* 演算子読み取り */
	    if ((str1=EnzanRead(str,&en))!=NULL) {
		str=str1;
		switch (en) {
		    default:/* 演算子 */
			if (p<0&&en!='=') return(VAROST); /* 未確定変数には代入しかできない */
			fv=fc=0;
			if (ff) {
				if (en=='-') en=VMINUS; /* 単項演算子：負号 */
				if (en=='+') {
					ff=0;
					continue; /* 単項演算子：正号->消す */
				}
			}
			if (Vsikis.vs==0&&en!=VMINUS&&en!='~'&&en!='!') return(VSOEN); /* 演算子のみ */
			if (Vsikis.es>0) {
			    /* 優先順位の同じ／高い演算子が出てきた時は先に演算する */
			    /* ただし代入だけは、それが続く場合、後の代入を優先する */
			    een=en;
			    while (Vsikis.es>0
			        && Yusen(een)<=Yusen(Vsikis.estack[Vsikis.es-1]) && een!='=') {
				int ret;
				ret=Enzan(Dainyu,var,&err);
				if (ret<0) return(err);
				een=ret;
			    }
			}
			/* 演算子をスタックに積む */
			if (Vsikis.es==Vsikis.emax) return(VSCPXE); /* stack over */
			Vsikis.estack[Vsikis.es++]=en;
			ff=(en==VMINUS? 0:2);
			p=0;
			
			#if DEBUG
			printc('<');
			printc2(en);
			crlf();
			#endif
			
			continue;
		    /* 括弧 */
		    case '(':
			if (fv==1) return(VSENONE); /* 数値の後ろに即'(' */
			if (Vsikis.es==Vsikis.emax) return(VSCPXC);
			Vsikis.estack[Vsikis.es++]=en;
			fv=0;
			fc=1;
			ff=3;
			continue;
		    case ')':
			if (fc==1) return(VSNNONE);
			/* 括弧を閉じる時、それまでのスタック内容で演算を行なう */
			while (Vsikis.estack[Vsikis.es-1]!='(') {
			    int ret;
				ret=Enzan(Dainyu,var,&err);
				if (ret<0) return(err);
				if (Vsikis.es==0) return(VSCNONE);
			}
			--Vsikis.es; /* (も消す */
			fv=fc=ff=0;
			continue;
		}
	    }
	    /* 数値変数読み取り */
	    if (fv==1) return(VSDBL); /* 数値が２つ続く */
	    if (Vsikis.vs==Vsikis.vmax) return(VSCPXS); /* stack over */
	    
	    /* 変数はその内容の数値が対象になる */
	    str1=NumVarRead(str,&num,NULL,&p,&status,gvar,lvar);
	    if (str1==NULL) return(status);
	
	    Vsikis.pstack[Vsikis.vs]=p; /* p==0:定数 , p>0:変数（確定）,p<0:変数（未確定）*/
	    Vsikis.vstack[Vsikis.vs++]=num;
	
	    fv=1;	/* 数値を積んだ */
	    fc=ff=0;	/* 括弧/演算子は積んでない */
	    str=str1;
	
	    #if DEBUG
	    printf("[%ld\n",num);
	    #endif
	
	}
	if (p<0) return(VARNST); /* 未確定変数への代入がない */
	
	/* スタックに積んである数値を演算子で計算する */
	while (Vsikis.es>0) {
	    int ret;
		ret=Enzan(Dainyu,var,&err);
		if (ret<0) {
		    if (err==VSILL) {
			if (Vsikis.estack[Vsikis.es-1]=='(') err=VSCNENG;
		    }
		    return(err);
		}
	}
	/* 正常終了 */
	*num0=Vsikis.vstack[0];
	if (c==','||c=='\n') str++;
	*str0=str;
	return(-(c==','||c=='\n')); /* 0=継続無し , -1=継続あり */
}

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