//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	コンパイラ：enum関係処理
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#include "variable.h"
#include "libs.h"
#include <ctype.h>
#import "bufferCtrl.h"

//#define DBG_Func()		NSLog(@"%s",__FUNCTION__)

//--------------------------------------------------------------------------------------

typedef struct {
	// 比較に使う順にする
	uwHash	hash;		// 定数名のハッシュ値
	SWord	len;		// 定数名長
	UByte	*name;		// 名前へのポインタ
	SLong	num;		// int値
	double	fnum;		// float値
	int		fenum;		// ENUM_*	intか floatか
} ENUM_CHAIN;

static BUFF_CTRL enumBuffer;
#define ENUM_ADD_STEP	128		// enum登録バッファー増分単位
// enum値そのものはoperationStatus.intEnum/floatEnumが保持する

//--------------------------------------------------------------------------------------

#ifdef DEBUG
void enumPrintName(void *venum1)
{
	printf("enum名:");
	ENUM_CHAIN *enum1=(ENUM_CHAIN *)venum1;
	UByte *name=enum1->name;
	int i;
	for (i=0;i<enum1->len;i++) {
		int c=*name++;
		if (c>=' ') {
			switch (c) {
				case MULTI_STATEMENT3:
					c='{'; // 内部処理用マルチステートメント
					break;
				case MULTI_STATEMENT2:
					c=' '; // 内部処理用マルチステートメント
					break;
			}
			fputc(c,stdout);
		} else {
			if (c==EOS) break;
			printf("<%02x>",c); // 制御コード時
		}
	}
	printf("(長さ=%d)=",i); // lenまたはEOSまでの長さ
	switch (enum1->fenum) {
		case ENUM_INT:
			printf("%d($%x)\n",(int)enum1->num,(int)enum1->num);
			break;
					
		case ENUM_FLOAT:
			printf("=%f\n",enum1->fnum);
			break;
	}
	fflush(stdout);
}
#endif

//--------------------------------------------------------------------------------------

// 比較関数
BOOL enumCmpData(void *data1,void *data0)
{
	ENUM_CHAIN *enum1=(ENUM_CHAIN *)data1;
	ENUM_CHAIN *enum0=(ENUM_CHAIN *)data0;
	if (enum1->hash==enum0->hash) {
		if (enum1->len==enum0->len) {
			if (memcmp(enum1->name,enum0->name,enum0->len)==0) {
				// 完全一致
				nslog(@"発見");
				return (YES);
			}
		}
	}
	// 定数には存在しない
	return (NO);
}

//--------------------------------------------------------------------------------------

// enum処理の初期化
void initEnum(void)
{
	DBG_Func();
	initBuffer(&enumBuffer,ENUM_ADD_STEP,sizeof(ENUM_CHAIN),enumPrintName);
	
	// 比較関数の定義
	enumBuffer.cmpData=enumCmpData;
}

void closeEnum(void)
{
	DBG_Func();
#ifdef DEBUG
	dumpBuffer(&enumBuffer, YES);
#endif
	closeBuffer(&enumBuffer);
}

//--------------------------------------------------------------------------------------

// enum定数を得る
// リターン値 : YES=あり , NO=なし(変数の可能性有り)
BOOL getEnum(UByte *name,uwHash hash,SWord len,SLong *num,double *fnum,int *fenum)
{
	ENUM_CHAIN  enum0={hash,len,name,0,0.0,ENUM_INT}; // 値は比較しないので
	ENUM_CHAIN *enum2=(ENUM_CHAIN *)searchValueFromBuffer(&enumBuffer,&enum0);
	if (enum2!=NULL) {
		nslog(@"発見");
		*fenum=enum2->fenum;
		switch (enum2->fenum) {
			case ENUM_INT:
				*num=enum2->num;
			    break;
			case ENUM_FLOAT:
				*fnum=enum2->fnum;
				break;
		}
		return (YES);
	}
	// 定数には存在しない
	return (NO);
}

//--------------------------------------------------------------------------------------

// enum値設定
BOOL storeEnum(uwHash hash,swStrLEN len,UByte *name,int fenum)
{
	printFunc();
	
	switch (fenum) {
	  case ENUM_INT:
		{
			// 現在値の読み出し
			SLong num=operationStatus.intEnum;
			nslog(@"num=%d",(int)num);
			
			// バッファーへの記録
			ENUM_CHAIN enum1={hash,len,name,num,0.0,ENUM_INT};
			if (addValueForBufferNoRedundant(&enumBuffer, &enum1)) {
				nslog(@"重複定義");
				return (YES);
			}

			operationStatus.intEnum++; // 次の値
		}
			break;

		case ENUM_FLOAT:
		{
			// 現在値の読み出し
			double num=operationStatus.floatEnum;
			nslog(@"num=%f",num);
			
			// バッファーへの記録
			ENUM_CHAIN enum1={hash,len,name,0,num,ENUM_FLOAT};
			if (addValueForBufferNoRedundant(&enumBuffer, &enum1)) {
				nslog(@"重複定義");
				return (YES);
			}
			
			operationStatus.floatEnum+=1.0; // 次の値
		}
			break;
	}
	return (NO); // 正常終了
}

//--------------------------------------------------------------------------------------
