/*  yachead.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <string.h>

#include "outtok.h"
#include "usercom.h"
#include "portable.h"
#include "intfc.h"
#include "user.h"
#include "lexnum.h"
#include "hrdarth.h"
#include "hrdcmp.h"

#include "yacintfc.h"
/* #include "y.tab.h"  included in lexhead.h */
#include "lexhead.h"
#include "baseio.h"
#include "interp.h"
#include "cgidbg.h"
#include "dspe_app.h"
#include "typemap.h"


ValueType::~ValueType()
{
	switch (Type) {
case DecFloat:
case DecInt:
		break;
case DecString:
case DecName:
		//delete Value.ValName;
		break;
case DecDspPP:
		//delete Value.Obj ;
		break;
case DecParam:
/*
 *		if (Value.ValParam) {
 *			Value.ValParam->Clear();
 *			delete Value.ValParam ;
 *		}
 */
		break ;
case DecProcedure:
		delete Value.ValProcedure ;
		break ;
case DecComplex:
case DecMachWord:
case DecCxMachWord:
case DecAccMachWord:
case DecCxAccMachWord:
		// delete Value.ValBuiltInClass ;
		break ;
case DecEnt:
case DecInvalid:
default:
		break ;
	}
}

int ValueType::IsScalar()
{
	if (Class != DeclBasic) return 1;
	SimpleUserObject * Obj = Declared.Basic ;
	return Obj->GetArray() == 0 ;
}

ArrayData * ValueType::array_data()
{
	SimpleUserObject * Obj = Declared.Basic ;
	if (!Obj) return 0 ;
	return Obj->GetArray();
}

int32 ValueType::GetArraySize()
{
	if (Class != DeclBasic) return 0;
	SimpleUserObject * Obj = Declared.Basic ;
	if (!Obj->GetArray()) return 0;
	return Obj->GetArraySize() ;
}

void * ValueType::GetArrayData()
{
	if (Class != DeclBasic) return 0;
	SimpleUserObject * Obj = Declared.Basic ;
	ValueType * Val = Obj->GetValue();
	return Val->Value.ValBuiltInClass ;
}

int DoubleAssign(ValueType * Dest, DecType Type, double * Source)
{
	// LogMsg("DoubleAssign - Source = ", ConvertToString(*Source));
	Dest->Type = Type ;
	void * Temp = DeclareObjectArray(Type,1);
	if (!DoubleAssign(Temp,Type,Source)) return 0; 
	if (Type == DecInt) {
		Dest->Value.ValInt = *(int32 *) Temp ;
		// LogForm("DoubleAssign int32 = %d",Dest->Value.ValInt );
		delete Temp ;
	} else if (Type == DecFloat) {
		Dest->Value.ValFloat = *(double *) Temp;
/*
 *		LogMsg("DoubleAssign double = ",
 *			ConvertToString(Dest->Value.ValFloat));
 */
		delete Temp ;
	} else Dest->Value.ValBuiltInClass = Temp ;
	return 1 ;
}


int DoubleAssign(void * Dest, int index, DecType Type, double * Temp)
{
	// LogForm("DoubleAssign Temp = %d", (long) *Temp);
	// LogForm("DoubleAssign (MachWord) *Temp = %d", (MachWord) *Temp);
	double PosTemp = fabs(*Temp);
	double temp = *Temp ;
	int TooLarge = 0;
	if (Type == DecFloat) *(((double *)Dest) +index) = temp ;
	else if (Type == DecInt) {
		if (temp == (int32) 0x80000000) PosTemp = 0. ;
		if (PosTemp > 0x7fffffff) {
			TooLarge = 1 ;
			if (temp < 0) temp = (int32) 0x80000000 ;
			else temp = 0x7fffffff ;
		}
		*(((int *)Dest)+index) = (int) temp ;
	} else if (Type == DecMachWord) {
		if (PosTemp > MachWord::max_positive) {
			TooLarge = 1;
			if (temp < 0) temp = -MachWord::max_positive ;
			else temp = MachWord::max_positive ;
		}
		*(((MachWord *)Dest)+index) = (MachWord) temp ;
	} else if (Type == DecAccMachWord) {
		if (PosTemp > AccMachWord::max_positive) {
			TooLarge = 1;
			if (temp < 0) temp = -AccMachWord::max_positive ;
			else temp = AccMachWord::max_positive ;
		}
		*(((AccMachWord *)Dest)+index) = (AccMachWord) temp ;
	} else {
		TheLog << "Type = " <<  (int)  Type << "\n" ;
		DbgError("DoubleAssign","Bad type");
	}
	if (TooLarge) {
		const char * type = "unknown" ;
		type = get_dec_type_name(Type);
		MachWord::hard_limit_warn(type);
		return 1;
	}
	return 1;
}

void * DoubleConvert(DecType Type, double * Temp)
{
	void * Return = DeclareObjectArray(Type,1) ;
	if(!DoubleAssign(Return, 0, Type, Temp)) return 0;
	// LogForm("DoubleConvert val = %d",*(int16 *) Return) ;
	return Return ;
}

int ComplexAssign(ValueType * Dest, DecType Type, complex * Temp)
{
	Dest->Type = Type ;
	return ComplexAssign(Dest->Value.ValBuiltInClass,0,Type,Temp); 
}

int ComplexAssign(void * Dest, int index, DecType Type, complex * Temp)
{
	double RealPosTemp = fabs(real(*Temp));
	double ImagPosTemp = fabs(imag(*Temp));
	int TooLarge = 1;
	if (Type == DecCxMachWord) {
		if (RealPosTemp > MachWord::max_positive ||
			ImagPosTemp > MachWord::max_positive) TooLarge = 1;
		*((CxMachWord *)(Dest)+index) = MakeCxMachWord(*Temp) ;
	} else if (Type == DecCxAccMachWord) {
		if (RealPosTemp >  AccMachWord::max_positive ||
			ImagPosTemp > AccMachWord::max_positive) TooLarge = 1;
		else *((CxAccMachWord *)(Dest)+index) =
			MakeCxAccMachWord(*Temp) ;
	} else if (Type == DecComplex) *((complex *)(Dest)+index) = *Temp;
	else DbgError("ComplexConvert","Bad type");
	if (TooLarge) {
		*Output + OutputCppHelp << "Value overflows.\n";
		return 0;
	}
	return 1 ;
}
		

void * ComplexConvert(DecType Type, complex * Temp)
{
	void * Return = DeclareObjectArray(Type,1);
	if (!ComplexAssign(Return, 0, Type, Temp)) return 0;
	return Return ;
}


static void PromptError(char * error)
{
	DbgError("ValueType::CheckValueDefined",error);
}

int ValueType::CheckValueDefined()
{
	if (ValueDefined) return 1;
	if (Class != DeclBasic) PromptError("bad Class");
	*Output + OutputCppHelp << "Variable " << Declared.Basic->GetName() <<
		" has no value defined.\n" ;
	*Output + OutputCppHelp << "It must be defined before it is used.\n" ;
	int Ret ;
	enum GetData {GetDone,GetDouble,GetComplex};
	GetData Action = GetDone ;
	const char * PromptString ;
	switch (Type) {
case DecString:
		Ret = GetStringValue("string",&Value.ValName);
		break ;
case DecInt:
		Ret = GetIntValue("integer value",Value.ValInt);
		break ;
case DecFloat:
		Ret = GetDoubleValue("floating point value", Value.ValFloat);
		break ;
case DecMachWord:
		PromptString = "single precision machine value" ;
		Action = GetDouble ;
		break ;
case DecAccMachWord:
		PromptString = "double precision machine value" ;
		Action = GetDouble ;
		break ;
case DecCxMachWord:
		PromptString = "single precision complex machine value" ;
		Action = GetComplex ;
		break ;
case DecCxAccMachWord:
		PromptString = "double precision complex machine value" ;
		Action = GetComplex ;
		break ;
case DecComplex:
		PromptString = "floating point complex number" ;
		Action = GetComplex ;
		break ;
case DecEnt:
case DecDspPP:
		PromptError("DecDspPP object not in yet");
		Ret = 0;
		break ;
case DecProcedure:
case DecParam:
case DecName:
case DecInvalid:
default:
		PromptError("bad type");
		Ret = 0;
		break;
	}
	switch(Action) {
case GetDouble:
		{
			double * Temp = new double ;
			Ret = GetDoubleValue(PromptString, *Temp);
			if (!(Value.ValBuiltInClass = DoubleConvert(Type,Temp)))
				Ret = 0 ;
		}
		break ;
case GetComplex:
		{
			complex * Temp = new complex ;
			Ret = GetComplexValue(PromptString,Temp);
			if (!(Value.ValBuiltInClass = ComplexConvert(Type,Temp)))
				Ret = 0 ;
		}
		break;
case GetDone:
		break;
	}
	if (Ret) ValueDefined = 1;
	return Ret ;
}

void Declaration::Dump(OutTokens& Out,DeclClass Class,ValueTypeList * Lst)
{
	if (!this) {
		Out.NextFillOut("NULL") ;
		return ;
	}
	switch (Class) {
case DeclNot:
		break ;
case DeclBasic :
		if (Basic) Basic->Dump(Out,Lst);
		break ;
case DeclEntity :
		if (Entity) Entity->Dump(Out,Lst);
		break;
case DeclMember :
		if (Entity) Entity->Dump(Out,Lst);
		break;
case DoDeclEntity :
		if (EntityClass) EntityClass->Dump(Out,Lst);
case DoDeclBasic :
		if (BasicClass) BasicClass->Dump(Out,Lst);
		break;
case DeclProcedure :
case DoDeclProcedure :
		Out.NextFillOut("Procedured declarations not in");
		break;
	}

}


void DataValue::Dump(OutTokens& Out,DecType Type,ValueTypeList * Lst)
{
	if (!this) {
		Out.NextFillOut("DataValue:NULL") ;
		return ;
	}
	char buf[BufSize] ;
	switch (Type) {
case DecString:
		Out.NextDblQuoteOut(ValName);
		break ;
case DecInt:
		Out.NextFillOut(strcpy(buf,dec(ValInt)));
		break ;
case DecFloat:
		Out.NextFillOut(ConvertToString(ValFloat));
		break ;
case DecComplex:
case DecMachWord:
case DecCxMachWord:
case DecAccMachWord:
case DecCxAccMachWord:
		Out.NextFillOut(ConvertToString(Type,ValBuiltInClass,0));
		break ;
case DecName:
		Out.NextFillOut(ValName);
		break;
case DecDspPP:
		if (Obj) Obj->Dump(Out,Lst);
		break ;
case DecEnt:	
		if (ValEnt) ValEnt->Dump(Out,Lst);
		break ;
case DecProcedure:
		if (ValProcedure) ValProcedure->Dump(Out,Lst);
		break ;
case DecParam:
		if(ValParam) ValParam->Dump(Out,Lst);
		break ;
case DecInvalid:
		Out.NextFillOut("Invalid type");
		break ;
default:
		Out.NextFillOut("Unknown type");
		break ;
	}
}

DataValue::~DataValue()
{
	// Add code to delete pointed to objects
}

int ValueType::CppList(OutTokens& Out, int i)
{
	// LogForm("ValueType::CppList ( %d )", i);
	if (i > -1 ) ArrayElementDump(Out,i);
	else Value.Dump(Out,Type,0);
	if (Type == DecProcedure || Type == DecParam) return 0;
	return 1 ;
}

const char * DecTypeToString(DecType Ty)
{
	static const char * TypeFields [] = {
	"DecFloat", "DecInt","DecName","DecProcedure","DecDspPP","DecParam",
	"DecEnt" };
	return TypeFields[Ty];
}

const char * DeclClassToString(DeclClass Cl)
{
	static const char * ClassFields[] = {
	"DeclNot", "DeclEntity", "DeclBasic", "DeclProcedure", "DeclMember",
	"DoDeclEntity", "DoDeclBasic", "DoDeclProcedure"} ;
	return ClassFields[Cl];

}


void ValueType::ArrayElementDump(class OutTokens& Out,int Index)
{
	// LogForm("ValueType::ArrayElementDump(%d)", Index);
	// char Buf[512];
	void * ToDump = Value.ValBuiltInClass;
	Out.NextFillOut(ConvertToString(Type,ToDump,Index));
}

double ValueType::GetDoubleMemberValue() const
{
	if (Type == DecInt) return Value.ValInt ;
	else if (Type == DecFloat) return Value.ValFloat ;
	State.Error("numeric value expected");
	return 0 ;
}

int32 ValueType::GetIntMemberValue() const
{
	if (Type != DecInt) {
		State.Error("integer value expected");
		return 0 ;
	}
	return Value.ValInt ;
}

void ValueType::Dump(class OutTokens& Out,ValueTypeList * Lst)
{
	if (!this) {
		Out.NextFillOut("NULL ValueType");
		return ;
	}
	if (Type <0 || Type > DecEnt) {
		Out.NextFillOut("ValueType: Bad Type");
		return ;
	}
	char buf[BufSize] ;
	if (!Lst) Lst = new ValueTypeList ;
	else {
		ValueTypeListIterator Next(*Lst) ;
		ValueType * Prev ;
		int i = 1;
		while (Prev=Next()) if (Prev == this) {
			Out.NextFillOut("Recursive reference at");
			Out.NextFillOut(strcpy(buf,dec(i)));
			Out.NextConcat(".");
			return ;
		} else i++ ;
	}
/*	if (Class == DeclNot) {
 *		Out.NextFillOut("DeclNot");
 *		return ;
 *	}
 */
	Lst->Append(this) ;
	
	static char * Fields [] = {
	"Type","Value","Class","Declared"};

	Out.NextFillOut(Fields[0]);
	Out.NextFillOut("=") ;
	Out.NextFillOut(DecTypeToString(Type)) ;
	Out.NextConcat(",") ;

	Out.NextFillOut(Fields[1]);
	Out.NextFillOut("=") ;
	Value.Dump(Out,Type,Lst);
	Out.NextConcat(",") ;

	Out.NextFillOut(Fields[2]);
	Out.NextFillOut("=") ;
	Out.NextFillOut(DeclClassToString(Class));
	Out.NextConcat(",") ;

	Out.NewLine();
	Out.NextFillOut(Fields[3]);
	Out.NextFillOut("=") ;
	Declared.Dump(Out,Class,Lst);
	Out.NextConcat(".") ;
}

int FoundName(char * yytext)
{
	struct ValueType * TypPtr ;
	if (!DspApplication::valid_object_name(yytext)) 
		State.Error("Invalid name: `", yytext, "'.\n",
			(HelpDo.All() ? DspApplication::explain_legal_object_name():0)
		);

	if (TypPtr=CheckDeclarator(yytext)) {
		yylval.Value = TypPtr ;
/*
 *		OutTokens Out(&cout);
 *		Out.NextFillOut("Dump from FoundName");
 *		Out.NewLine();
 *		TypPtr->Dump(Out,0);
 */
		return DECL ;
	} else if
		(TypPtr=CheckDeclared(yytext)) {
		yylval.Value = TypPtr ;
		return DECL_NAME ;
	}
	yylval.Name = MakeLitString(yytext) ;
	return NAME ;
}

const char * NameOfObj(ValueType * Obj)
{
	// LogOut << "NameOfObj\n" ;
	// LogOut << "Type = " << Obj->Type << "\n" ;
	if (!Obj) DbgError("NameOfObj","NULL");
	if (Obj->Type==DecName) return Obj->Value.ValName ;
	if (Obj->Type==DecProcedure) {
		if (Obj->Value.ValProcedure) {
			// LogOut << "Found Procedure\n" ;
			// LogOut << Obj->Value.ValProcedure->GetName() << "\n" ;
			// LogOut << "NameOfObj - returning\n" ;
			return Obj->Value.ValProcedure->GetName();
		}
		DbgError("NameOfObj","bad procedure");
	}
	if (Obj->Type==DecEnt)return Obj->Value.ValEnt->GetName() ;
	if (Obj->Class==DeclBasic) return Obj->Declared.Basic->GetName();
	if (Obj->Class==DeclEntity) return Obj->Declared.Entity->GetName();
	if (Obj->Class==DoDeclEntity) return
		Obj->Declared.EntityClass->GetClassName();
	if (Obj->Class==DoDeclBasic) {
		SimpleUserObject * Ob = Obj->Value.Obj ;
		if (!Ob) {
			OutTokens Out(&(LogOut)) ;
			Obj->Dump(Out,0) ;
			DbgError("NameOfObj","NULL Value.Obj");
		}
		return Ob->GetTypeName() ;
	} else {
		OutTokens Out(&(LogOut)) ;
		Obj->Dump(Out,0) ;
		DbgError("NameOfObj","Bad obj");
	}
	return 0 ;
}

InteractiveEntity * ValueType::interactive_entity() const
{
	if (Class != DoDeclEntity) {
		// LogOut << "ValueType::GetClassName - Class = " << Class << "\n" ;
		return 0 ;
	}
	return Declared.EntityClass ;
}

const char * ValueType::GetClassName() const
{
	InteractiveEntity * Ent = interactive_entity();
	if (!Ent) {
		// LogOut << "ValueType::GetClassName - no EntityClass\n" ;
		return 0 ;
	}
	return Ent->GetClassName();
}

void ValueType::double_assign(double val)
{
	double abs_val = fabs(val);
	switch (Type) {
case DecFloat:
		Value.ValFloat = val ;
		break ;
case DecInt:
		Value.ValInt = (int) val  ;
		break ;
case DecMachWord:
		if (abs_val > MachWord::max_positive) {
			MachWord::hard_limit_warn();
			if (val < 0) val = -MachWord::max_positive ;
			else val = MachWord::max_positive ;
		}
		*Value.GetMachWord() = (MachWordCast) val ;
		break ;
case DecAccMachWord:
		if (abs_val > AccMachWord::max_positive) {
			MachWord::hard_limit_warn("AccMachWord");
			if (val < 0) val = -AccMachWord::max_positive ;
			else val = AccMachWord::max_positive ;
		}
		*Value.GetAccMachWord() = (MachWordCast) val ;
		break;
/*
 * case DecString:
 * case DecName:
 * case DecDspPP:
 * case DecParam:
 * case DecProcedure:
 * case DecComplex:
 * case DecCxMachWord:
 * case DecCxAccMachWord:
 * case DecEnt:
 * case DecInvalid:
 */
default:
		DbgError("ValueType::double_assign","bad type");
	}
	ValueDefined = 1;
}

double ValueType::double_value(DecType typ)
{
	double val ;
	int is_mach = 0 ;
	int is_float = 0 ;
	int is_int = 0 ;
	switch (Type) {
case DecFloat:
		val = Value.ValFloat ;
		is_float = 1 ;
		break ;
case DecInt:
		val = Value.ValInt ;
		is_int = 1 ;
		break ;
case DecMachWord:
		val = Value.GetMachWord()->val() ;
		is_mach = 1 ;
		break ;
case DecAccMachWord:
		val = Value.GetAccMachWord()->val() ;
		is_mach = 1 ;
		break;
/*
 * case DecString:
 * case DecName:
 * case DecDspPP:
 * case DecParam:
 * case DecProcedure:
 * case DecComplex:
 * case DecCxMachWord:
 * case DecCxAccMachWord:
 * case DecEnt:
 * case DecInvalid:
 */
default:
		DbgError("ValueType::double_value","bad type");
	}
	if (!is_floating_point_simulator()) switch (typ) {
case DecFloat:
		if (is_mach) val /= (MachWord::max_positive + 1);
		break ;
case DecInt:
case DecMachWord:
case DecAccMachWord:
		break;
/*
 * case DecString:
 * case DecName:
 * case DecDspPP:
 * case DecParam:
 * case DecProcedure:
 * case DecComplex:
 * case DecCxMachWord:
 * case DecCxAccMachWord:
 * case DecEnt:
 * case DecInvalid:
 */
default:
		DbgError("ValueType::double_value","bad type  2");
	}
	return val ;
}


