/*  interp.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */

#include "baseio.h"
#include "hrdarth.h"
#include "newaloc.h"
#include "usercom.h"
#include "interp.h"
#include "lexhead.h"
#include "intfc.h"
#include "prsdrv.h"
#include "yacintfc.h"
#include "array.h"
#include "outtok.h"
#include "cgidbg.h"
#include "user.h"
#include "stattyp.h"

// void TestAlloc(const char * msg);

static void DeclPtErr(const char * err)
{
	DbgError("Declare",err);
} 


void EntityList::Describe(OutTokens& Out,enum ListEntity Lst)
{
	EntityListIterator Next(*this) ;
	UserEntity * AnEntity ;
	while (AnEntity = Next()) AnEntity->Describe(Out,Lst) ;
}



void * DeclareObjectArray(DecType Type,int Size)
{
	switch (Type) {
case DecFloat:
		// LogForm("Declaring double[%d]",Size);
		return new double[Size];
case DecInt:
		// LogForm("Declaring int[%d]",Size);
		return new int[Size];
case DecString:
		// LogForm("Declaring char *[%d]",Size);
		return new char * [Size];
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecInvalid:
default:
		DbgError("DeclareObjectArray","bad type");
case DecMachWord:
		// LogForm("Declaring MachWord[%d]",Size);
		return NEW(MachWord,Size);
case DecAccMachWord:
		// LogForm("Declaring AccMachWord[%d]",Size);
		return NEW(AccMachWord,Size);
case DecComplex:
		// LogForm("Declaring complex[%d]",Size);
		return NEW(complex,Size) ;
case DecCxMachWord:
		// LogForm("Declaring CxMachWord[%d]",Size);
		return NEW(CxMachWord,Size);
case DecCxAccMachWord:
		// LogForm("Declaring CxAccMachWord[%d]",Size);
		return NEW(CxAccMachWord,Size);
	}
}


static const StatusCheckComplex =		0x1   ;
static const StatusCheckFloat =			0x2   ;
static const StatusCheckNotNumeric =		0x4   ;
static const StatusCheckAllocationNeeded =	0x8   ;
static const StatusCheckBuiltIn = 		0x10  ;
static const StatusCheckMachWord = 		0x20  ;
static const StatusCheckAcc = 			0x40  ;

static int StatusCheck(DecType Type)
{
	int mach_word_float = is_floating_point_simulator() ? StatusCheckFloat:0  ;
	
	int Return = 0 ;
	switch (Type) {
case DecFloat:
		Return = StatusCheckFloat;
		break ;
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
		Return = StatusCheckNotNumeric ;
case DecInt:
		break ;
case DecMachWord:
		Return = StatusCheckAllocationNeeded | StatusCheckBuiltIn
			| StatusCheckMachWord | mach_word_float ;
		break ;
case DecAccMachWord:
		Return = StatusCheckAllocationNeeded | StatusCheckBuiltIn
			| StatusCheckMachWord | StatusCheckAcc  | mach_word_float ;
		break ;
case DecComplex:
		Return = StatusCheckComplex | StatusCheckFloat |
			StatusCheckAllocationNeeded | StatusCheckBuiltIn ;
		break ;
case DecCxMachWord:
		Return = StatusCheckComplex | StatusCheckAllocationNeeded |
			StatusCheckBuiltIn | StatusCheckMachWord  | mach_word_float ;
		break ;
case DecCxAccMachWord:
		Return = StatusCheckComplex | StatusCheckAllocationNeeded |
			StatusCheckBuiltIn | StatusCheckMachWord |
			StatusCheckAcc  | mach_word_float ;
		break ;
case DecInvalid:
default:
	DbgError("IsComplex","bad type");
	}
	return Return ;
}

int IsAllocationNeeded(DecType Type)
{
	return (StatusCheck(Type) & StatusCheckAllocationNeeded) != 0;
}

int IsComplex(DecType Type)
{
	return (StatusCheck(Type) & StatusCheckComplex) != 0 ;
}

int IsFloat(DecType Type)
{
	return (StatusCheck(Type) & StatusCheckFloat) != 0 ;
}

int IsNumeric(DecType Type)
{
	return !(StatusCheck(Type) & StatusCheckNotNumeric) ;
}

int IsBuiltInClass(DecType Type)
{
	return (StatusCheck(Type) & StatusCheckBuiltIn);
}

int IsMachWordType(DecType Type)
{
	return StatusCheck(Type) & StatusCheckMachWord ;
}

int IsAccWordType(DecType Type)
{
	return StatusCheck(Type) & StatusCheckAcc ;
}

void * GetNthValue(DecType Type, void * Val, int index)
{
	switch (Type) {
case DecFloat:
		return ((double *) Val)+index ;
case DecInt:
		return ((int *) Val)+index ;
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecInvalid:
default:
		DbgError("GetNthValue","bad type");
case DecComplex:
		return ((complex *) Val)+index ;
case DecCxMachWord:
		return ((CxMachWord *) Val)+index ;
case DecCxAccMachWord:
		return ((CxAccMachWord *) Val)+index ;
case DecMachWord:
		return ((MachWord *) Val)+index ;
case DecAccMachWord:
		return ((AccMachWord *) Val)+index ;
	}
}

complex ConvertToComplex (DecType Type, const void * Val, int index)
{
#ifdef __NT_VC__
	complex x ;
	double rl ;
	double ig;
	x.y = 0 ;
#endif
	switch (Type) {
case DecFloat:
#ifndef __NT_VC__
		return complex(*(((double *) Val)+index)) ;
#else
		x.x= *((double *) Val + index) ;	
		break ;
#endif
case DecInt:
#ifndef __NT_VC__
		return complex(*(((int *) Val)+index)) ;
#else
		x.x= *((int *) Val + index) ;	
		break ;
#endif
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecInvalid:
default:
		DbgError("ConvertToComplex","bad type");
#ifndef __NT_VC__
case DecComplex:
		return complex(*(((complex *) Val)+index)) ;
case DecCxMachWord:
		return complex(*(((CxMachWord *) Val)+index)) ;
case DecCxAccMachWord:
		return complex(*(((CxAccMachWord *) Val)+index)) ;
case DecMachWord:
		return complex((*(((MachWord *) Val)+index)).val()) ;
case DecAccMachWord:
		return complex((*(((AccMachWord *) Val)+index)).val()) ;
#else
case DecComplex:
		x.x = ((complex *) Val + index)->x ;
		x.y = ((complex *) Val + index)->y ;
		break ;
case DecCxMachWord:
		x.x = (MachWordCast) MachReal(*((CxMachWord *) Val + index)) ;
		x.y = (MachWordCast) MachReal(*((CxMachWord *) Val + index)) ;
		break ;
case DecCxAccMachWord:
		x.x = (AccMachWordCast) MachReal(*((CxAccMachWord *) Val + index)) ;
		x.y = (AccMachWordCast) MachReal(*((CxAccMachWord *) Val + index)) ;
		break ;
case DecMachWord:
		x.x = (MachWordCast) (((MachWord *) Val) + index)->val() ;
		break ;
case DecAccMachWord:
		x.x = (AccMachWordCast) (((AccMachWord *) Val) + index)->val() ;
		break ;
#endif
	}
#ifdef __NT_VC__
	return x ;
#endif
}

complex ConvertToComplex (DecType Type, const DataValue& Val)
{
#ifdef __NT_VC__
	complex x;
	x.x = 0 ;
#endif
	
	switch (Type) {
#ifndef __NT_VC__
case DecFloat:
		return complex(Val.ValFloat) ;
case DecInt:
		return complex(Val.ValInt) ;
#else
case DecFloat:
		x.x = Val.ValFloat ;
		return x ;
case DecInt:
		x.x = Val.ValInt ;
		return x ;
#endif
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecInvalid:
default:
		DbgError("ConvertToComplex","bad type");
case DecComplex:
		return *Val.GetComplex();
case DecCxMachWord:
		return GetComplexFromPtr(Val.GetCxMachWord());
case DecCxAccMachWord:
		return GetComplexFromPtr(Val.GetCxAccMachWord());
case DecMachWord:
		return GetComplexFromPtr(Val.GetMachWord());
case DecAccMachWord:
		return GetComplexFromPtr(Val.GetAccMachWord());
	}
}


complex ConvertToComplex ( const ValueType& Val)
{
	return ConvertToComplex (Val.Type,Val.Value);
} 

double ConvertToDouble (enum DecType Type, const void * Val, int index)
{
/*
 *	LogOut << "ConvertToDouble(" << Type << ", " << Val << "," <<
 *		index << ")\n" ;
 */
	switch (Type) {
case DecFloat:
		return *(((double *) Val)+index) ;
case DecInt:
		return double(*(((int32 *) Val)+index)) ;
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecComplex:
case DecCxMachWord:
case DecCxAccMachWord:
case DecInvalid:
default:
		DbgError("ConvertToDouble","bad type");
case DecMachWord:
		return double(*(((MachWord *) Val)+index)) ;
case DecAccMachWord:
		return double(*(((AccMachWord *) Val)+index)) ;
	}
}

double ConvertToDouble (enum DecType Type, const DataValue& Val)
{
	switch (Type) {
case DecFloat:
		return Val.ValFloat ;
case DecInt:
		return Val.ValInt ;
case DecString:
case DecName:
case DecDspPP:
case DecParam:
case DecEnt:
case DecProcedure:
case DecComplex:
case DecCxMachWord:
case DecCxAccMachWord:
case DecInvalid:
default:
		DbgError("ConvertToDouble","bad type");
case DecMachWord:
		return (double) *Val.GetMachWord();
case DecAccMachWord:
		return (double) *Val.GetAccMachWord();
	}
}

double ConvertToDouble (const ValueType& Val)
{
	return ConvertToDouble(Val.Type,Val.Value);
}


static int AssignConvert(DecType Type, void * Destination,int Index,
	ValueType * Source)
{
	if (IsComplex(Type)) {
		complex CmpxVal = ConvertToComplex(*Source);
		if (!ComplexAssign(Destination,Index,Type,&CmpxVal))
			return 0;
	} else {
		if (IsComplex(Source->Type)) {
			State.Error(
			"cannot use a complex value to initialize a scalar");
			return 0;
		}
		double DoubVal = ConvertToDouble(*Source);
		if (!DoubleAssign(Destination,Index,Type,&DoubVal)) return 0;
	}
	// LogMsg("ExitAssignConvert");
	return 1;
}

const char * ConvertToString(const ValueType& Data)
{
	return ConvertToString(Data.Type,(const void *) &Data.Value,0);
}

const char * ConvertToString(DecType Type, const DataValue& Data)
{
	return ConvertToString(Type,Data.ValBuiltInClass,0);
}

const char * ConvertToString(DecType Type, const void * Data,int Index)
{
	return ConvertToString(Type,Data,Index,CppListCtor);
}


ArithType::ArithTypes DecTypeToArithType(DecType type)
{
	switch(type) {
case DecInt:
		return ArithType::ArithInt32 ;
case DecComplex:
case DecMachWord:
case DecCxMachWord:
case DecAccMachWord:
case DecCxAccMachWord:
case DecFloat:
		return ArithType::ArithDouble ;
case DecEnt:
case DecProcedure:
case DecParam:
case DecName:
case DecDspPP:
case DecString:
case DecInvalid:
		break ;
	}
	return ArithType::ArithTypeUndefined ;
}

static const char * LocalValueToString(DecType Type, double val,
	CppListCmds Cmd)
{
/*
 *	LogOut << "LocalValueToString(" << Type << ", " << val <<
 *		", " << Cmd << ")\n" ;
 */
	static char Buf[64] ;
	if (Cmd == CppListTargetCtor) {
		if (IsMachWordType(Type)) {
			ArithType::ArithTypes
				LocalTheArithType = DecTypeToArithType(Type);
			if (LocalTheArithType == ArithType::ArithInt16) {
				strcpy(Buf,dec((int)val)) ;
				return Buf ;
			}
			if (LocalTheArithType == ArithType::ArithFloat)
				return FullDoubleValue(val);
			if (LocalTheArithType == ArithType::ArithDouble)
				return FullDoubleValue(val);
		 	DbgError("LocalValueToString","bad type");
		}
	}
	if (IsMachWordType(Type)) if (IsAccWordType(Type))
		val = NormFromAccMachWord(val);
	else val = NormFromMachWord(val);
	const char *Return = FullDoubleValue(val);
	// LogOut << "Returning " << Return << "\n" ;
	return Return ;
}

const char * ConvertToString(DecType Type, const void * Data,int Index,
	CppListCmds Cmd)
{
	if (IsComplex(Type)) {
		const BufSize = 256;
		static char Buf[BufSize];
		complex CmplVal = ConvertToComplex(Type,Data,Index);
		strcpy(Buf,"( ");
		double val = real(CmplVal) ;
		strcat(Buf,LocalValueToString(Type,val,Cmd)) ;
		strcat(Buf,", ");
		val = imag(CmplVal) ;
		strcat(Buf,LocalValueToString(Type,val,Cmd));
		strcat(Buf," )") ;
		return Buf ;
	} else {
		double val = ConvertToDouble(Type,Data,Index);
		return LocalValueToString(Type,val,Cmd) ;
	}
}

const char * ConvertToString(const double& Val)
{
	return ConvertToString(DecFloat,(void *) (&Val),0);
}

// Declare a pointer
struct ValueType * DeclarePtr(struct ValueType* Type,struct ValueType* ObjTar,
	ValueType * InitList)
{
	if (NoExecute()) return 0 ;
	// TestAlloc("DeclarePtr enter");
	for (;;) {
		if (State.IsError()) break ;
		if (!ObjTar || !Type || !InitList) DeclPtErr ("NULL - Ptr") ;
		if (Type->Class == DoDeclEntity) {
			State.Error(
			"pointers to class objects are not supported") ;
			break ;
		}
		// Count the objects and make an array of them
		if (InitList->Type != DecParam)
			DbgError("DeclarePtr","bad param type");
		ParameterList * Elements = InitList->Value.ValParam ;
		if (!Elements) {
			State.Error("null array declaration list");
			break ;
		}

		int Size = Elements->Size();
		if (!Size) {
			State.Error("null array size");
			break ;
		}
	
		// TestAlloc("before Declare");
		ValueType * Return = Declare(Type,ObjTar,Size);
		// TestAlloc("after Declare");
		void * Array = DeclareObjectArray(Type->Type,Size);
		
		// LogOut << "DeclarePtr::Type->Type = " << Type->Type << "\n" ;
		ArrayData * Arr  =
			(new ArrayData)->SetArrayData(0,Type->Type,Array);
		Return->Declared.Basic->SetArray(Arr);

		ParameterListIterator Next(*Elements);
		ValueType * Element ;
		int i = 0;
		while (Element = Next()) {
			if (!AssignConvert(Type->Type, Array,i++,
			Element)) return 0;
/* 
 *			LogMsg("Assigned ",ConvertToString(*Element));
 *			LogMsg("Assignee is ",
 *				ConvertToString(Type->Type,Array,i-1));
 */
		}
		Arr->Size = Size ;
		// Make an ObjTar that points to this array to pass to Declare
		Return->Value.ValBuiltInClass = Array ;
		Return->ValueDefined=1;
		State.DoingThis("Initialized array");
		// delete Type; deleted by Declare
		// delete ObjTar; deleted by Declare
		// delete InitList;
		// OutTokens Temp(OutputCppHelp);
		// Return->Dump(Temp,0);
/*
 *		LogOut << "Array initialized:\n" ;
 *		void * Xx= Return->Declared.Basic->GetArray()->Data;
 *		for (i = 0 ; i < Size ; i++) LogOut << "0x" <<
 *			hex(*((MachWord *) Xx + i)) << "\n" ;
 *		LogOut << "\n" ;
 *		OutTokens Out(&LogOut);
 *		Return->Declared.Basic->GetArray()->List(Out);
 *		Out.NewLine();
 */
		// TestAlloc("exit 1 DeclarePtr");
		return Return ;
	}
	// TestAlloc("Ptr - delete") ;
	delete Type;
	delete ObjTar;
	delete InitList;
	// LogOut << "Ptr - delete finished\n" ;
	// TestAlloc("exit 2 DeclarePtr");
	return 0 ;
}



