/*  mknodey.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <string.h>
#include "mknodelx.h"
		// this includes y.tab.h and stdio.h
#include "portable.h"
#include "stdyac.h"
#include "stdyacp.h"
#include "mknodey.h"
#include "domknode.h"
#include "debug.h"
#include "genmenu.h"
#include "member.h"
#include "nodeparm.h"
#include "textfrag.h"
#include "mkstr.h"

Double * DoubleOne ;
const char * DefBaseName = "Node" ;
const char * NewReserved = " new " ;

Compound::~Compound()
{
	switch (Type) {
case TypeTerm:
case TypeInt:
		break ;
case TypeDouble:
		delete Item.Dbl ;
		break ;
case TypeName:
case TypeString:
		delete[] (void *) Item.Str ;
		break ;
case TypeText:
		delete Item.Text ;
		break ;
case TypeCompound:
		delete Item.Tree ;
		break ;
case TypeDescription:
		delete Item.Desc ;
		break ;
case TypeList:
		delete Item.List ;
		break ;
case TypeParamFunc:
		delete Item.ParamFunc ;
		break ;
case TypeSize:
		delete Item.Size ;
		break ;
case TypeParameter:
		break ;
case TypeScaledType:
		delete Item.TheScaledType ;
		break ;
default:
		DbgError("Compound::~Compound", "bad ItemType");
	}
}

CompoundList::~CompoundList()
{
	CompoundListIterator Next(*this);
	Compound * Item ;
	while (Item = Next()) delete Item ;
}

Compound * MakeZeroIntItem(int32 Val)
{
	if (Val) {
		// cerr << "Only a 0 is allowed (for a void pointer)" ;
		OutWhereEnd();
	}
	return new Compound(TypeInt,Object(Val));
}

Compound * MakeIntItem(int32 Val)
{
	return new Compound(TypeInt,Object(Val));
}

Compound * MakeStringItem(const char * Str)
{
	return new Compound(TypeString,Object(Str));
}

Compound * MakeTermItem(int term)
{
	return new Compound(TypeTerm,Object(term));
}

Compound * MakeDoubleItem(Double * flt)
{
	// cout << "MakeDoubleItem:: flt->String = " << flt->String << "\n" ;
	// flt->String = MakeName(flt->String);
	Compound *Return = new Compound(TypeDouble,flt);
	const char * Value = Return->Item.Dbl->String ;
	// cout << "Return->Item.Dbl->String = `" << Value << "'\n" ;
	return Return ;
}

Compound * MakeNegIntItem(int32 Value)
{
	return MakeIntItem(-Value);
}

Compound * MakeNegDoubleItem(struct Double * Value)
{
	Value->Negate();
	return MakeDoubleItem(Value);
}

Compound * FoundMenuLine(const char * MenuName, TextFragmentList * Text)
{
	if (!Text) cerr << "********FoundMenuLine no menu\n" ;
	return new Compound(TypeDescription,Object(new
		Description(Text,0,MenuName)));
}


Compound * ShortLongDesc(Compound * MenuDesc,TextFragmentList * full,
	const char * HelpFileName)
{
	if (MenuDesc->Type != TypeDescription) DbgError(
		"ShortLongDesc","bad type");
	Description * TheDesc = MenuDesc->Item.Desc ;
	if (!TheDesc->HelpLine) cerr << "***** ShortLongDesc no menu.\n" ;
	if (TheDesc->Full) DbgError("ShortLongDesc","full already set");
	TheDesc->SetFullDescription(full);
	if (TheDesc->HelpFileName) DbgError("ShortLongDesc",
		"HelpFileName already set");
	TheDesc->SetHelpFileName(HelpFileName);
	return MenuDesc;
}

Compound * CkStr(Compound * C)
{
	if (C->Type != TypeString) DbgError("CkStr","not a string");
	return C ;
}


Compound * Exp(Compound * A, char c, Compound * B)
{
	CkStr(A);
	CkStr(B);
	char * concat = new char [strlen(A->Item.Str)+strlen(B->Item.Str)+4] ;
	strcpy(concat,A->Item.Str);
	char * tmp = concat + strlen(concat);
	*tmp++ = ' ' ;
	*tmp++ = c ;
	*tmp++ = ' ' ;
	strcpy(tmp,B->Item.Str);
	delete A ;
	delete B ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Exp(Compound *A, const char *B, Compound *C)
{
	CkStr(A);
	CkStr(C);
	char * concat = new char [strlen(A->Item.Str)+strlen(B)+
		strlen(C->Item.Str)+3] ;
	strcpy(concat,A->Item.Str);
	char * tmp = concat + strlen(concat);
	*tmp++ = ' ' ;
	strcpy(tmp,B);
	tmp = concat + strlen(concat);
	*tmp++ = ' ' ;
	strcpy(tmp,C->Item.Str);
	delete A ;
	// delete B ;
	delete C ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Unary(const char * str, Compound * A)
{
	CkStr(A);
	char * concat = new char [strlen(A->Item.Str)+strlen(str)+1];
	strcpy(concat,str);
	strcat(concat,A->Item.Str);
	// delete A ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Unary(char c, Compound * A)
{
	CkStr(A);
	char * concat = new char [strlen(A->Item.Str)+2];
	*concat = c ;
	strcpy(concat+1,A->Item.Str);
	delete A ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Paren(Compound *A)
{
	CkStr(A);
	char * concat = new char [strlen(A->Item.Str)+3];
	*concat = '(' ;
	strcpy(concat+1,A->Item.Str);
	strcat(concat,")");
	delete A ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Func(Compound * A, Compound * B)
{
	CkStr(A);
	CkStr(B);
	char * concat = new char [strlen(A->Item.Str)+strlen(B->Item.Str)+3] ;
	strcpy(concat,A->Item.Str);
	char * tmp = concat + strlen(concat);
	*tmp++ = '(' ;
	strcpy(tmp,B->Item.Str);
	strcat(tmp,")");
	delete A ;
	delete B ;
	// cout << "Func returning `" << concat << "'\n" ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * Cast(Compound * A, const char * Extra, const char * B)
{
	char * Return = 0 ;
	if (Extra) Return = Concatenate("(",A->Item.Str," ",Extra,")", B);
	else Return = Concatenate("(",A->Item.Str,")",B);
	return new Compound( TypeString, Object(Return)); 
}
Compound * Cast(Compound * A, const char * Extra, Compound * B)
{
	char * Return = 0 ;
	if (Extra) Return = Concatenate("(",A->Item.Str," ",Extra,")",
		B->Item.Str);
	else Return = Concatenate("(",A->Item.Str,")",B->Item.Str);
	return new Compound( TypeString, Object(Return)); 
}

Compound * Cast(int A, const char * Extra, Compound * B)
{
	CkStr(B);
	const char * Type = TerminalToCType(A);
	if (!Type) {
		yyerror("invalid type for cast");
		Type = "ERROR BAD TYPE" ;
	}
	char * Return = 0 ;
	if (Extra) Return = Concatenate("(",Type," ",Extra,")",B->Item.Str);
	else Return = Concatenate("(",Type,")",B->Item.Str);
	return new Compound( TypeString, Object(Return)); 
}

Compound * Array(Compound * A, Compound * B)
{
	CkStr(A);
	CkStr(B);
	char * concat = new char [strlen(A->Item.Str)+strlen(B->Item.Str)+3] ;
	strcpy(concat,A->Item.Str);
	char * tmp = concat + strlen(concat);
	*tmp++ = '[' ;
	strcpy(tmp,B->Item.Str);
	strcat(tmp,"]");
	delete A ;
	delete B ;
	return new Compound( TypeString, Object(concat)); 
}

Compound * MakeTree(const char * A)
{
	return new Compound (TypeString, Object(A));
}

Compound * Null()
{ 
	char * NullObj = new char[1] ;
	NullObj[0] = '\0' ;
	return new Compound (TypeString, Object(NullObj));
}


Compound * MakeQuoteString(const char * Str)
{
	char * Return = new char [strlen(Str)+4] ;
	strcpy(Return," \"");
	strcat(Return,Str);
	strcat(Return,"\" ");
	// delete Str;
	return new Compound(TypeString, Object(Return)) ;
}

Compound * MakeStringNumber(Compound * num)
{
	const char * Return ;
	char buf[32] ;
	switch (num->Type) {
case TypeInt:
		sprintf(buf,"%d",num->Item.Int);
		Return = MakeName(buf);
		break ;
case TypeDouble:
		Return = num->Item.Dbl->String ;
/*
 *		cout << "MakeStringNumber - Str = `" <<
 *			num->Item.Dbl->String << "'\n" ;
 */
		num->Item.Str = 0;  	// do not delete this
		break ;
case TypeString:
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeList:
case TypeDescription:
case TypeParamFunc:
case TypeSize:
case TypeParameter:
case TypeScaledType:
default:
		DbgError("MakeStringNumber", "bad ItemType");
	}
	delete num ;
	return new Compound(TypeString, Object(Return));
 
}

Compound * MakeParamFunc(Compound * list, TextFragmentList * code)
{
	return new Compound(TypeParamFunc, Object (new
		ParameterFunction(list->Item.List,code))) ;
}

Compound * MakeParamFunc(TextFragmentList * code)
{
	return MakeParamFunc(0,code) ;
}

Compound * MakeNameList(Compound * list, const char * name) 
{
	if (list->Type != TypeList) DbgError("MakeNameList", "bad list");
	list->Item.List->Append(new Compound (TypeName, Object(name))) ;
	return list ;
}

Compound * MakeNameList(const char * name) 
{
	Compound * ListItem = new Compound (TypeName, Object(name)) ;
	CompoundList * RetList = new CompoundList(ListItem);
	return new Compound(TypeList, Object(RetList));
}

Compound * MakeSize(int32 MinSize, int32 MaxSize)
{
	ArraySize * s = new ArraySize(MinSize,MaxSize) ;
	return new Compound(TypeSize,s);
}

Compound * MakeSignedComplexItem(Compound *, Compound *)
{
	DbgError("MakeSignedComplexItem","complex constant support not in yet");
	return 0;
}

Compound * MakeComplexItem(Compound *, Compound *)
{
	DbgError("MakeComplexItem","complex constant support not in yet");
	return 0;
}

Compound * MakeNumParmList(Compound * Value)
{
	return new Compound (TypeList, *(new Object (new CompoundList(Value))));
}

Compound * AppendNumParmList(Compound * List, Compound * Addition)
{
	if (List->Type != TypeList) DbgError("AppendNumParmList","bad list");
	List->Item.List->Append(Addition);
	return List ;
}

Compound * ScaleDeclaration(int ChangeFlag,int Type, Double * Dbl)
{
/*
 *	cerr << "ScaledDeclartion (" << ChangeFlag << ", "
 *			<< Type << ", 0x" << (long) Dbl << ")\n" ;
 */
	return new Compound(TypeScaledType,
		*(new Object(new ScaledType(Type,Dbl,ChangeFlag))));
}

	
		
const char * MakeClassName(int Type, int Ref)
{
	return MakeClassName(MakeClassName(Type),Ref);
}

const char * MakeClassName(int Type)
{
	const char * CppType = TerminalToCppType(Type);
	if (!CppType) {
		CppType = TerminalToString(Type);
		yyerror("bad declaration using key word `",CppType);
	}
	return CppType ;
}

const char * MakeClassName(const char * Name, int Reference)
{
	static char Ref[2] = "X" ;
	Ref[0] = Reference;
	return MakeCompoundName(Name,Ref);
}

void HeaderOnly()
{
	// *CppOut << "HeaderOnly\n" ;
	NoTiming();
	// *CppOut << "After NoTiming\n" ;
	FoundKernel(0);
	// *CppOut << "After FoundKernel\n" ;
	CodeComplete();
	// *CppOut << "After CodeComplete\n" ;
	NodeComplete();
	// *CppOut << "After NodeComplete\n" ;
	if (!TheMemberFunctions) return ;
	if (!TheMemberFunctions->Size() || BaseSwitch) return ;
	EmitSelectMemberToExecute(NodeName,"Orphan");
	EmitDescribeMembersMenu(NodeName, "Orphan");
	
}
void FoundParameterCheck(int IsFirstDefault,
	Compound * Param, TextFragmentList * Code)
{
	if (Param->Type != TypeParameter) DbgError("FoundParameterCheck",
		"bad type");
	if (Code) Param->Item.TheParameter->LegalCheck = Code ;
	if (IsFirstDefault) {
			Param->Item.TheParameter->FirstDefault = 1 ;
/*
 *			cerr << "Set first default for `" <<
 *				Param->Item.TheParameter->Name << "'.\n" ;
 */
	}
	delete Param ;
}

