/*  domknode.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include "ObjProGen/cpyrght_exe.h"
#include "fileios.h"
#include <stream.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include "slist.h"
#include "debug.h"
#include "mkstr.h"
#include "mknodelx.h"
#include "mknodey.h"
#include "spellfil.h"
#include "text.h"
#include "textfrag.h"
#include "genmenu.h"
#include "menunm.h"
#include "myfloat.h"
#include "domknode.h"
#include "text2.h"
#include "nodeparm.h"
#include "outfilnm.h"
#include "member.h"
#include "buftype.h"
#include "ctorinit.h"
#include "instance.h"
#include "fileios.h"
#include "includ.h"
#include "warn.h"
#include "gentex.h"
#include "outtok.h"
#include "texutil.h"
#include "textrans.h"
#include "cgidbg.h"
#include "othbse.h"
#include "arthtyp.h"
#include "makedir.h"
#include "opf.h"
#include "specarth.h"
#include "dosname.h"
#include "sysconst.h"

// #define TEST_ALLOC
#ifdef TEST_ALLOC
void TestAlloc(const char * Msg=0)
{
    if (Msg) cerr <<  Msg << "\n"  ;
    cerr << "Enter TestAlloc\n";
    const Number = 40 ;
    char * Tests[Number];
    for (int i = 0 ; i < Number; i++) {
        int Limit = 2*i+4 ;
        char * Temp ;
        Tests[i] = Temp = new char[Limit];
        for (int j = 0 ; j < Limit ; j++) Temp[j] = rand();
        delete Tests[i] ;
        Tests[i] = 0 ;
    }
    for (i = 0 ; i < Number; i++) delete Tests[i] ;
    cerr << "Exit TestAlloc\n";
}
#endif



int InteractiveCodeGen = 1 ;
int TargetCodeGen = 0 ;
int MultipleArithmeticGen = 0 ;
const char * TargetDir = "../target" ;
static const char * SaveTargetDir = TargetDir ;
static const char * SourceCodeDir = "" ;
static const char * SaveMenuDirectory = MenuDirectory ;

int BaseSwitch = 0 ;
int PublicFlag;
char * InputFileName = "input.file" ;
const char * InputFileNameBase = 0;

int NetworkRefFlag = 0 ;

MofStream * HeaderOut = 0;
MofStream * CppOut = 0;
ostream * BaseClassHeadOut = 0 ;
ostream * BaseClassBodyOut = 0 ;

const MaxFileName = 12 ;

static char XXHeaderName[MaxFileName+1];
char * HeaderName = XXHeaderName ;
static char CppName[MaxFileName+1] ;
// static char RemoteName[MaxFileName+1] ;
// static char LocalName[MaxFileName+1] ;
static char XXSpellFileName[MaxFileName+1] ;
char * SpellFileName = XXSpellFileName ;

const char * NodeName ;



/*
 *	DfNode(const char * name, int16 in, int16 out, int32 EltSz =1,
 *		int32 NodeDelay=0, int32 DeltaIn =1, int32 DeltaOut=1,
 *		int32 Overlap= 0, int32 DelayIn=0) ;
 */

static LineOfstream::HeaderOptions user_copyright = LineOfstream::None ;
int user_copyright_flag = 0 ;

void SetUserCopyright()
{
	user_copyright = LineOfstream::UserCopyrightBit ;
	user_copyright_flag = 1 ;
}


ParameterFunction::~ParameterFunction()
{
	delete NameList;
	delete Code;

}

struct NodeVariable {
	int Type ;
	int Ptr ;
	int ChangeFlag;
	const char * Name ;
	NodeVariable(int type, const char * name, int isptr = 0,
		int flag=0)
		{Type = type; Name = name; Ptr = isptr; int ChangeFlag = flag;}
	~NodeVariable() {delete[] (void *) Name;}
};


class NodeVariableList: public SingleList {
public:
	ErrCode Insert(NodeVariable *nt) {return SingleList::Insert(nt);}
	ErrCode Append(NodeVariable *nt) {return SingleList::Append(nt);}
	NodeVariable * Get()   {return (NodeVariable *) SingleList::Get();}
	NodeVariable * Pop() {return (NodeVariable *) SingleList::Pop();}
	NodeVariable * GetNFromTop(int N) ;
	NodeVariable * GetNthEntry(int N) ;
	NodeVariableList(){}
	~NodeVariableList();
	int Size(){return SingleList::Size();}
} ;


NodeVariableList::~NodeVariableList()
{
	NodeVariable * node ;
	while (node = Get()) delete node;
}

class NodeVariableListIterator: public SingleListIterator {
public:
	NodeVariableListIterator(NodeVariableList& df):
		SingleListIterator((SingleList&) df){}
	NodeVariable * operator()()
		{return (NodeVariable *) Next();}
};

NodeParameterList::~NodeParameterList()
{
	NodeParameter * param ;
	while (param = Get()) delete param ;
}


static NodeParameterList * TheNodeParameters = 0;
MemberFunction * TheNodeCtor = 0 ;
static NodeParameterList * SaveTheNodeParameters = 0;
static NodeVariableList * TheNodeVariables = 0;
static Description * TheNodeDescription = 0;
static struct TextFragmentList * TheDeclarationCode = 0 ;

Description::~Description()
{
	delete[] (void *) HelpLine;
	delete[] (void *) Full;
	delete[] (void *) HelpFileName;
	// delete[] (void *) MenuName;
}



enum CheckGlobalName {CheckGlobalOk, CheckGlobalDoubleDef} ;

static CheckGlobalName DoOneGlobCheck(const char * NewName,
	ConstStringList * TheList)
{
	ConstStringListIterator Next(*TheList);
	const char * Check ;
	while (Check = Next()) if (!strcmp(NewName,Check))
		return CheckGlobalDoubleDef ;
	TheList->Append(MakeName(NewName));
	return CheckGlobalOk ;
}


enum GlobalNameType {GlobalFile,GlobalNode,GlobalNodeInternal} ;

static const char * MemberFunctionName = 0;

static void ParameterNameCheck(const char * Name=0)
{
	static ConstStringList * ParamNames = 0;
	if (!Name) {
		if (ParamNames)  {
			delete ParamNames ;
			ParamNames = 0 ;
		}
		return ;
	}
	if (!ParamNames) ParamNames = new ConstStringList ;
	CheckGlobalName Status = DoOneGlobCheck(Name,ParamNames);
	switch (Status) {
case CheckGlobalOk:
		break ;
case CheckGlobalDoubleDef:
		cerr << "Parameter `" << Name <<
			"' defined twice in member function `" << 
			MemberFunctionName << "'\n" ;
		break ;
	}
	
}

void NewMember(const char * Name)
{
	ParameterNameCheck(0);
	MemberFunctionName = Name ;
}

static void GlobalNameCheck(GlobalNameType Type, const char * Name=0)
{
	static ConstStringList * NodeNames = 0;
	if (!NodeNames) NodeNames = new ConstStringList ;
	static ConstStringList * FileNames = 0;
	if (!FileNames) FileNames = new ConstStringList ;
	static ConstStringList * NodeInternalNames = 0 ;
	if (!NodeInternalNames) NodeInternalNames = new ConstStringList ;
	if (!Name) {
		switch (Type)  {
case GlobalFile :
			delete FileNames ;
			FileNames = 0 ;
			break ;
case GlobalNode :
			delete NodeNames ;
			NodeNames = 0 ;
			break ;
case GlobalNodeInternal :
			delete NodeInternalNames ;
			NodeInternalNames = 0 ;
			break ;
		}
		return ;
	}

	const char * NameType ;
	CheckGlobalName Status ;

	switch (Type)  {
case GlobalFile :
		NameType = "File name" ;
		Status = DoOneGlobCheck(Name,FileNames);
		break ;
case GlobalNode :
		NameType = "Node name" ;
		Status = DoOneGlobCheck(Name,NodeNames);
		break ;
case GlobalNodeInternal :
		NameType = "Node internal name" ;
		Status = DoOneGlobCheck(Name,NodeInternalNames);
		break ;
	}
	switch (Status) {
case CheckGlobalOk:
		break ;
case CheckGlobalDoubleDef:
		cerr << NameType << " `" << Name << "' defined twice.\n" ;
		break ;
	}
}


void FoundNetworkRef()
{
	NetworkRefFlag = 1 ;
}


void FoundBaseFunctionName(const char * Name)
{
	if (InitFoundBaseFunctionName(Name,NodeName)) {
		HeaderOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*HeaderOut << "#include \"" << ObjProUsr << "/" <<
		CtorBaseClassDefaults->IncludeFileName << "\"\n\n" ;
		HeaderOut->PopSecondFileSelect();
		return ;
	}
	cerr << "Unknown base function name `" << Name << "'" ;
	OutWhereEnd();
	cerr << "Aborting execution.\n" ;
	exit(2);
}



CtorParam CtorParamFound[MaxNumberDfNodeParams] ;


static void CtorParamInit()
{
	// static int FirstTime = 1 ;
	// if (!FirstTime) for (int i = 0 ; i < MaxNumberDfNodeParams; i++) {
		// cout << "Before first delete i = " << i << "\n" ;
		// delete[] (void *) CtorParamFound[i].Name;
		// cout << "Before second delete i = " << i << "\n" ;
		// delete[] (void *) CtorParamFound[i].Expression;
	// }
	// FirstTime = 0 ;
	for (int i = 0 ; i < MaxNumberDfNodeParams; i++) {
		CtorParamFound[i].Name = 0;
		CtorParamFound[i].Expression = 0;
	}
}


static void NewNodeInit()
{
	GlobalNameCheck(GlobalNodeInternal);
	delete TheNodeParameters ;
	delete TheNodeCtor ;
	TheNodeParameters = new NodeParameterList ;
	delete TheMemberFunctions ;
	TheMemberFunctions = new MemberFunctionList ;
	delete TheNodeVariables ;
	TheNodeVariables = new NodeVariableList ;
	CtorParamInit();
	delete TheNodeDescription ;
	TheNodeDescription = 0 ;
}



static int NumNodes = 0;

/*
 * enum ArithType::ArithCapabilities CapabilitiesPresent =
 *	(ArithType::ArithCapabilities) ArithType::ArithTypeUndefined ;
 */
uint32 CapabilitiesPresent ;

void FoundNodeName(const char * Node)
{
	if (BaseSwitch) TargetCodeGen = 0 ;
	// cout << "FoundNodeName(" << Node << ")\n" ;
	if (NumNodes++) {
		cerr << "Warning: more than one node is defined  in file `"
			<< InputFileName << "'\n" ;
	}
	const MaxFilePrefix = MaxFileName - 2 ;
	GlobalNameCheck(GlobalNode,Node);
	if (HeaderName) {
		delete HeaderOut ; // closes old files and frees space

		delete CppOut ;
		CppOut = 0 ;
	}

	int Leng = strlen(Node);
	if (!Leng) CantContinue("NodeName", "null node name");
	NodeName = Node ;

	Leng = strlen(InputFileNameBase) ;
	if (Leng > MaxFilePrefix - 1) {
		Leng = MaxFilePrefix - 1 ;
		GiveWarning("node name truncated for file names");
	}
	for (int i = 0 ; i < MaxFileName+1;i++) HeaderName[i] = 0;
	strncpy(HeaderName,InputFileNameBase,Leng);
	for (i = 0 ; i < Leng ; i++) HeaderName[i] = tolower(HeaderName[i]);
	strcpy(CppName,HeaderName);
	strcpy(SpellFileName,HeaderName);


	// create target file names
	char * HeaderMainName = Concatenate(OpdRoot,
		"/src/include/ObjProDSPint/",ObjProUsr,"/", HeaderName, ".h");
	char * HeaderTargetName = Concatenate(OpdRoot,
		"/src/include/ObjProDSPtar/",ObjProUsr,"/", HeaderName, ".h");
	
	char * CppTargetName = MakeCompoundName(TargetDir, "/",
		HeaderName, CPP_SUFFIX);

	
	strcat(HeaderName,".h");
	if (MultipleArithmeticGen) {
		TruncateToLength(CppName,MaxDosPrefix-1);
		strcat(CppName,"x.h");
	} else strcat(CppName,CPP_SUFFIX);
	// cerr << "CppName = `" << CppName << "'.\n" ;
	strcat(SpellFileName,".s");

	// CreateRemoteHeader(RemoteName,HeaderName);
	// pass header name for include
	HeaderOut = new MofStream(
		InteractiveCodeGen ? HeaderMainName : 0,
		TargetCodeGen ? HeaderTargetName : 0,
		InputFileName,
		(LineOfstream::HeaderOptions) (LineOfstream::Both|user_copyright),
		NodeName
	);
	char * TempName = Concatenate(SourceCodeDir,HeaderName);
	// cerr << "Header name `" << TempName << "'\n" ;
	TempName = Concatenate(SourceCodeDir,CppName); 
	CppOut = new MofStream(InteractiveCodeGen ? TempName : 0,
		TargetCodeGen ? CppTargetName : 0, InputFileName,
		user_copyright,NodeName);

	if (MultipleArithmeticGen) {
		// cerr << "Cap = " << hex << CapabilitiesPresent << dec << "\n" ;
		int ArithmeticCount = 0 ;
		for (int i = 0 ; i <= ArithType::MaxArithCapabilities;i++)
			if (CapabilitiesPresent & i) ArithmeticCount++ ;
		// cerr << "Count = " << ArithmeticCount << "\n" ;
		if ((CapabilitiesPresent |
			(1 << ArithType::ArithCapabilityFixed)) ||
		    !ArithmeticCount) CapabilitiesPresent |= 
			(1 << ArithType::ArithInt16)
			| (1 << ArithType::ArithInt32)
			| (1 << ArithType::ArithFloat)
			| (1 << ArithType::ArithDouble) ;
		CapabilitiesPresent = CapabilitiesPresent &
			~ (1 << ArithType::ArithCapabilityFixed);
		ArithmeticCount = 0 ;
		// cerr << "Cap = " << hex << CapabilitiesPresent << dec << "\n" ;
		for (i = 0 ; i <= ArithType::MaxArithCapabilities;i++)
			if (CapabilitiesPresent & i) ArithmeticCount++ ;
		// output variable arithmetic include
		// const char * GenHead =  SpecArithIncludeFile ;
		*CppOut << SpecArithListPrefix ;
		for (i = 0 ; i <= ArithType::MaxArithCapabilities;i++)
		    if (CapabilitiesPresent & (1<<i)) {
			// *CppOut << " " << ArithType::CapabilityNames[i] ;
			// create subdirectories if they do not exist
			const char * Suffix = ArithType::ClassSuffix[i] ;
		 	char * Name = Concatenate(InputFileNameBase,"_",
				Suffix);
			Name = TruncateToDosPrefix(
				Name,strlen(Suffix));
			char * FileName = Concatenate(SourceCodeDir,
				Name,".","C");
			delete Name ;
			ostream * TheHead =
				&(OpenFile(FileName,"arithmetic"));
			*TheHead << "#define " << NodeName << " " << NodeName
				<< "_" << Suffix << "\n" ;
			*TheHead << "#include \"" << ObjProUsr << "/" << CppName << "\"\n" ;
			// delete DirName ;
			// delete HeaderName ;
			delete TheHead ;
			delete FileName ;
		}
		*CppOut << "\n" ;
		// open C file for base class
		char * BaseClassHeadName =
			Concatenate(SourceCodeDir,InputFileNameBase, "_B.h") ;
		char * BaseClassBodyName = 
			Concatenate(SourceCodeDir,InputFileNameBase, "_B",CPP_SUFFIX) ;
		BaseClassHeadOut = &(OpenFile(BaseClassHeadName,
			"base class header"));
		BaseClassBodyOut = &(OpenFile(BaseClassBodyName,
			"base class body"));
		delete BaseClassHeadName ;
		delete BaseClassBodyName ;
		EmitHeaderIncludes(*BaseClassHeadOut);
		EmitBodyIncludes(*BaseClassBodyOut);
	} else {
	}
	HeaderOut->PushFirstFileSelect(BaseStreamBuf::Off);
	*HeaderOut << "#define __DSP_PP_TARGET_CODE__\n" ;
	HeaderOut->PopFirstFileSelect();

	EmitIncludeFiles(*HeaderOut,*CppOut,1);
	// AddHeaders(TheHIncludes,HeaderOut);
	// AddHeaders(TheCIncludes,CppOut);

		
	EmitHeaderIncludes(*HeaderOut);
	HeaderOut->PushSecondFileSelect(BaseStreamBuf::Off);
	HeaderOut->PopSecondFileSelect();
	HeaderOut->PushFirstFileSelect(BaseStreamBuf::Off);
	*HeaderOut << "#include \"" << ObjProCom << "/tarnod.h\"\n" ; // prevent excessive include
						// nesting
	HeaderOut->PopFirstFileSelect();

	*CppOut << "#include \"" << ObjProNet << "/dfnode.h\"\n" ;// prevent excessive include
	*CppOut << "\n#include \"" << ObjProUsr << "/" << HeaderName << "\"\n" ;
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	EmitBodyIncludes(*CppOut);
	CppOut->PopSecondFileSelect();
	EmitIncludeFiles(*HeaderOut,*CppOut,0);
	// AddHeaders(ThehIncludes,HeaderOut);
	// AddHeaders(ThecIncludes,CppOut);
	NewNodeInit();
	// *CppOut << "ck3\n" ;
	OpenNodFile(NodeName,HeaderName);
}

static void CheckType(Compound * Item, ItemType item)
{
	if(Item->Type != item) DbgError("CheckType",
		"bad type: internal problem");
}

static void CheckLegalArrayType(int TheType)
{
	switch(TheType) {
case INT32:
case MACH_WORD:
case SC_MACH_WORD:
		break ;
default:
		yyerror(
		"illegal array type (only `int32' and `MachWord' are legal");
	}
}

Compound * FoundPtrParameter(Compound *Type, const char * Name,
	Compound * Lower, Compound * Default, Compound * Upper,
	Compound * Descript, Compound *Size)
{
	if (Size->Type != TypeSize) DbgError("FoundPtrParameter",
		"size bad type");
	if (Type->Type != TypeScaledType) DbgError("FoundPtrParameter",
		"bad type type");
	int TheType = Type->Item.TheScaledType->Type ;
	CheckLegalArrayType(TheType);
	ArraySize * s = Size->Item.Size ;
	return FoundParameter(Type,Name,Lower, Default,Upper,Descript, s) ;
}

static const char * member_help_file = 0 ;

void FoundDefaultHelp(const char * name)
{
	member_help_file = Concatenate(name);
}

void FoundMemberName(const char * ClassName, const char * Name,
	Compound * Descript, int wait)
{
	TheNodeParameters->CheckAtMostOneFirstDefault() ;
	CheckType(Descript,TypeDescription);
	Description * Help = Descript->Item.Desc ;
	MemberFunction * TheMember = new MemberFunction(ClassName,Name,
		Help->HelpLine, Help->Full, TheNodeParameters,wait,member_help_file);
	TheMemberFunctions->Append(TheMember) ;
	TheNodeParameters = new NodeParameterList ;
	MemberFunctionName = 0;
}

void FoundDeclaration()
{
	delete TheNodeParameters ;
	TheNodeParameters = SaveTheNodeParameters ;
}

Description * FoundParameterCommon(const char * Name, Compound * Descript)
{
	if (MemberFunctionName) ParameterNameCheck(Name) ;
	else GlobalNameCheck(GlobalNodeInternal,Name);
	CheckType(Descript,TypeDescription);
	return Descript->Item.Desc ;
}

Compound * FoundParameterEnd(NodeParameter * ThisParameter, Description * Help,
	Compound * Descript)
{
	Help->HelpLine = 0;		// do not delete
	Help->Full = 0;		// do not delete
	delete Descript ;
	TheNodeParameters->Append(ThisParameter);
	return new Compound(TypeParameter,ThisParameter);
}

Compound * FoundParameterSubDef(const char * ClassName, const char * ParamName,
	const char * DefaultName, Compound * Descript)
{
	Description * HelpText = FoundParameterCommon(ParamName,Descript);
	NodeParameter * This = new NodeParameter(ClassName,ParamName,
		DefaultName,HelpText->HelpLine,HelpText->Full);
	This->SetSubroutineDefault();
	return FoundParameterEnd(This,HelpText,Descript);
}

int CheckBase(const char *WhatFound)
{
	if (!BaseSwitch) return 0 ;
	cerr << "Warning: " << WhatFound  << " found for `Base' class" ;
	OutWhereEnd();
	return 1;
}


Compound * FoundParameter(const char * ClassName, const char * ParamName,
	const char * DefaultName, Compound * Descript)
{
	if (DefaultName) CheckBase("default name");
	if (Descript) {
		CheckBase("parameter description");
		Description * HelpText = FoundParameterCommon(ParamName,
			Descript);
		NodeParameter * This = new NodeParameter(ClassName,ParamName,
			DefaultName,HelpText->HelpLine,HelpText->Full);
		return FoundParameterEnd(This,HelpText,Descript);
	} else {
		NodeParameter * This = new NodeParameter(ClassName,ParamName);
		TheNodeParameters->Append(This);
		return new Compound(TypeParameter,This);
	}
}

Compound * FoundParameter(Compound * Type, const char * Name)
{
	if (Type->Type != TypeScaledType) DbgError("FoundParameter",
		"bad Type for Type");
	ScaledType * ScType = Type->Item.TheScaledType ;
	NodeParameter * This = new NodeParameter(ScType,Name);
	TheNodeParameters->Append(This);
	return new Compound(TypeParameter,This);
}

Compound * FoundParameter(Compound * Type, const char * Name, Compound * Lower,
	Compound * Default, Compound * Upper, Compound * Descript,
	ArraySize *s)
{
	// cout << "Type for " << Name << " is " << Type <<"\n" ;
	if (Type->Type != TypeScaledType) DbgError("FoundParameter",
		"bad Type for Type");

	Description * HelpText = FoundParameterCommon(Name, Descript) ;
	ScaledType * ScType = Type->Item.TheScaledType ;
	NodeParameter * ThisParameter = new NodeParameter(ScType,Name,
		Lower,Default,Upper,HelpText->HelpLine, HelpText->Full,s);
	return FoundParameterEnd(ThisParameter,HelpText,Descript);
}

static void AddTypedName (int ChangeFlag,int type, const char * Name, int IsPtr)
{
	GlobalNameCheck(GlobalNodeInternal,Name);
	NodeVariable * ThisVariable = new NodeVariable(type,Name,IsPtr,
		ChangeFlag);
	TheNodeVariables->Append(ThisVariable);
	// cout << "Appending to TheNodeVariables: `" << Name << "'\n" ;
}

void FoundPtrTypedName(int ChangeFlag, int type, const char * Name)
{
	AddTypedName(ChangeFlag,type,Name,1);
}

void FoundTypedName(int ChangeFlag, int type, const char * Name)
{
	AddTypedName(ChangeFlag,type,Name,0);
}

const char * CheckPublic(const char * Text)
{
	// cout << "CheckPublic(" << Text << ")\n" ;
	const char * pt = Text ;
	while (isspace(*pt)) pt++;
	int Length = strlen("public");
	if (strncmp("public",pt,Length)) return 0;
	pt+=Length ;
	while (isspace(*pt)) pt++;
	if (*pt != ':') return 0;
	return pt+1 ;
}

void EmitCode(TextFragmentList * code, OutputFile FileType)
{
	if (!code) return ;
	MofStream * FileOut;

	switch (FileType) {
case OutputHeader:
		FileOut = HeaderOut ;
		break ;
case OutputCpp:
		FileOut = CppOut ;
		break ;
default:
		DbgError("EmitCode","bad file type");
	}


	TextFragment * Text ;
	TextFragmentListIterator Next(*code);
	int LastLine = -1 ;
	int LineCount = 0 ;
	while (Text = Next()) {
		if (LastLine != Text->Line) {
			if (LastLine < 0) FileOut->LineOut(Text->Line);
				else {
				*FileOut << "\n" ;
			}
			LastLine = Text->Line;
			LineCount = 0 ;
		}
		if (*(Text->Text)) {
			LineCount = 1;
			*FileOut << Text->Text ;
		}
	}
	if (LineCount) {
		*FileOut << "\n" ;
	}

}



static void EmitPrivateCode(TextFragmentList * code)
{
	if (!code) return ;
	TextFragment * Text ;
	TextFragmentListIterator Next(*code);
	int LastLine = -1 ;
	int LineCount = 0 ;
	while (Text = Next()) {
		if (CheckPublic(Text->Text)) break ;
		if (LastLine != Text->Line) {
			if (LastLine < 0) HeaderOut->LineOut(Text->Line);
			else *HeaderOut << "\n" ;
			LastLine = Text->Line;
			LineCount = 0 ;
		}
		if (*(Text->Text)) {
			LineCount = 1;
			*HeaderOut << Text->Text ;
		}
	}
	if (LineCount) *HeaderOut << "\n" ;
}

void StateEmitDec( MofStream& Out, const char * Class=0)
{
	static int DoEmit = 0;
	if (Class) DoEmit = 1 ;
	else {
		if (!DoEmit) return ;
		DoEmit = 0;
	}
	if (!Class) Out << "\tvirtual " ;
	Out << "const char * " ;
	if (Class)  Out << Class << "::" ;
	Out << "EmitState(OutTokens& Out)" ;
	if (!Class) Out << " ;\n" ;
}


static const char * DescribeString =
	"Describe(OutTokens& Out, ListEntity Option)";

static const char * CppListString =
	"CppList(OutTokens& Out, CppListCmds Cmd)";


static void EmitPublicCode(TextFragmentList * code, int IsTiming)
{
	if (!BaseSwitch) {
		if (CtorBaseClassDefaults->KernelFlag) *HeaderOut <<
			"\tvirtual ErrCode DoNode(int32);\n" ;
		HeaderOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*HeaderOut << "\tvoid "  << DescribeString << ";\n" ;
		*HeaderOut << "\tvirtual int "  <<
			CppListString << ";\n" ;
		HeaderOut->PopSecondFileSelect();
		StateEmitDec(*HeaderOut);
		if (IsTiming) {
			*HeaderOut <<
		"\tvirtual double TimeFirst(DfNodeInLink *,DfNodeOutLink *);\n";
		}
		TheNodeCtor->EmitSetNodeVariables(*HeaderOut);
	}
	HeaderOut->PushSecondFileSelect(BaseStreamBuf::Off);
	TheMemberFunctions->EmitMemberDeclarations(*HeaderOut);
	HeaderOut->PopSecondFileSelect();
	if (!code) return ;
	TextFragment * Text ;
	TextFragmentListIterator Next(*code);
	int LastLine = -1 ;
	int LineCount = 0 ;
	int NotPublicYet = 1 ;
	while (Text = Next()) {
		const char * LineContents = Text->Text ;
		if (NotPublicYet) {
			const char * StartPublic ;
			if (!(StartPublic = CheckPublic(LineContents)))
				continue ;
			while(isspace(*StartPublic)) StartPublic++ ;
			NotPublicYet = 0 ;
			if (!*StartPublic) continue ;
			LineContents = StartPublic ;
		}
		if (LastLine != Text->Line) {
			if (LastLine < 0) HeaderOut->LineOut(Text->Line);
			else *HeaderOut << "\n" ;
			LastLine = Text->Line;
			LineCount = 0 ;
		}
		if (*(LineContents)) {
			LineCount = 1;
			*HeaderOut << LineContents ;
		}
	}
	if (LineCount) *HeaderOut << "\n" ;
}





const ScaledNumericType = 1 ;
const ComplexNumericType = 2 ;
const VoidNumericType = 4 ;
const BasicNumericType = 8 ;

static int GetTypeCharacteristics(int Type)
{
	switch(Type) {
case INT16:
case INT32:
case DOUBLE:
case INT:
		return BasicNumericType ;
case COMPLEX:
		return ComplexNumericType | VoidNumericType ;
case SC_MACH_WORD:
case SC_ACC_MACH_WORD:
		return ScaledNumericType | VoidNumericType ;
case SC_CX_ACC_MACH_WORD:
case SC_CX_MACH_WORD:
		return ComplexNumericType | VoidNumericType | ScaledNumericType;
case CX_MACH_WORD:
case CX_ACC_MACH_WORD:
		return ComplexNumericType | VoidNumericType ;
case MACH_WORD:
case ACC_MACH_WORD:
		return VoidNumericType ;
default:
		return 0;
	}
}

static int IsComplexType(int Type)
{
	return (GetTypeCharacteristics(Type) & ComplexNumericType) != 0 ;
}

static int IsNumericType(int Type)
{
	return GetTypeCharacteristics(Type) != 0 ;
}

int IsVoidNumericType(NodeParameter * Param)
{
	if (Param->Size) return 1;
	if (!Param->Type) return 0;
	return (GetTypeCharacteristics(Param->Type->Type) &
		VoidNumericType) != 0;
}
	
int IsVoidNumericType(int Type)
{
	return (GetTypeCharacteristics(Type) & VoidNumericType) != 0;
}
	

const char * DecTypeSuffix(int Token)
{
	switch(Token) {
case COMPLEX:
		return "complex" ;
case SC_ACC_MACH_WORD:
case ACC_MACH_WORD:
		return "AccMachWord" ;
case SC_CX_ACC_MACH_WORD:
case CX_ACC_MACH_WORD:
		return "CxAccMachWord" ;
case SC_MACH_WORD:
case MACH_WORD:
		return "MachWord" ;
case SC_CX_MACH_WORD:
case CX_MACH_WORD:
		return "CxMachWord" ;
case INT16:
case INT32:
case INT:
		return "Int" ;
case DOUBLE:
		return "Float" ;
case STRING:
		return "String" ;
default:
		DbgError("DecTypeSuffix","unknown or invalid type");
	}
	return 0 ;
}

static void EmitValue(Compound * Value)
{
	switch (Value->Type) {
case TypeInt:
		*CppOut << Value->Item.Int ;
		break ;
case TypeDouble:
		*CppOut << Value->Item.Dbl->String ;
		break ;
case TypeString:
		*CppOut << "\"" << Value->Item.Str << "\"" ;
		break ;
case TypeScaledType:
		*CppOut << "Add code for scaled type\n" ;
		break ;
case TypeTerm:
case TypeName:
case TypeText:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeParameter:
default:
		cerr << "Bad type = " << (int) Value->Type  << "\n" ;
		DbgError("EmitValue","bad type");
	}
}


const char * WhatTypeString(int Type, InitFlagType InitFlag)
{
	const char * Return ;
	const char * Init = 0;
	const char * InitDecType = 0;
	static const char * ArrayDec = "Array " ;
	// cerr << "WhatTypeString(" << Type << "," << InitFlag << ")\n" ;
	switch(Type) {
case INT:
		Return = "int " ;
		InitDecType = "Int " ;
		break ;
case INT16:
		Return = "int16 " ;
		InitDecType = "Int " ;
		break ;
case INT32:
		Return = "int32 " ;
		InitDecType = "Int " ;
		break ;
case DOUBLE:
		Return = "double " ;
		InitDecType = "Float " ;
		break ;
case SC_CX_MACH_WORD:
case CX_MACH_WORD:
		Return = "CxMachWord " ;
		Init =   "CxMachWordType " ;
		InitDecType = ArrayDec ;
		break ;
case SC_MACH_WORD:
case MACH_WORD:
		Return = "MachWord " ;
		Init =   "MachWordType " ;
		InitDecType = ArrayDec ;
		break ;
case SC_CX_ACC_MACH_WORD:
case CX_ACC_MACH_WORD:
		Return = "CxAccMachWord " ;
		Init =   "CxAccMachWordType " ;
		InitDecType = ArrayDec ;
		break ;
case SC_ACC_MACH_WORD:
case ACC_MACH_WORD:
		Return = "AccMachWord " ;
		Init =   "AccMachWordType " ;
		InitDecType = ArrayDec ;
		break ;
case COMPLEX:
		Return = "complex " ;
		InitDecType = "Complex " ;
		Init =   "complexType " ;
		break ;
case STRING:
		Return = "const char * " ;
		break ;
default:
		cerr << "Bad type = " << Type << "\n" ;
		DbgError("WhatTypeString","unknown type");
	}
	static char PrefixType[32];
	switch (InitFlag) {
case DataDecType:
		return Return ;
case DataPhonyDecType:
		if (!Init) Init = Return ;
		return Init ;
case DataDecEnumType:
		if (!InitDecType) InitDecType = Return ;
		return InitDecType ;
case DataDecPrefixType:
		if (!InitDecType) InitDecType = Return ;
		strcpy(PrefixType,InitDecType);
		int Blank = strlen(PrefixType);
		if (!Blank) DbgError("WhatTypeString","null prefix");
		PrefixType[Blank-1] = '\0' ; // remove trailing blank
		// cerr << "PrefixType = `" << PrefixType << "'\n" ;
		return PrefixType ;
	}

	return PrefixType ;
}


const char * WhatTypeString(NodeParameter * Param,int AlwaysPtr)
{
	const BufSize = 64 ;
	static char Buf[BufSize];
	const char * Base = "ERROR" ;
	if (Param->Type) Base = WhatTypeString(Param->Type->Type) ;
	else if (Param->ClassType) Base = Param->ClassType ;
	else CantContinue("WhatTypeString", "bad Param");
	if (!Param->Size && !AlwaysPtr && !Param->ClassType) return Base ;

	if (strlen(Base) > BufSize - 4) DbgError("WhatTypeString",
		"string too long");
	strcpy(Buf,Base);
	if (Param->Size) strcat(Buf,"* ");
	char Last = Buf[strlen(Buf)-1] ;
	if (Last != ' ' && Last != '&' && Last != '*') strcat(Buf," ");
	return Buf ;
}




void EmitScaledValue(Compound * Value, const char * StrScaleFac, int Type)
{
	const char * symbolic_value = 0 ;
	int no_scale = 0 ;
	if (Value->Type == TypeTerm) symbolic_value =
		StringArrayBound(Value->Item.Terminal,Type,&no_scale);
	if (no_scale) StrScaleFac = 0 ;

	if (StrScaleFac) {
		if (IsComplexType(Type)) DbgError("EmitScaledValue",
			"complex arrays not supported" );
		if (IsVoidNumericType(Type)) *CppOut << "( Cast" <<
			WhatTypeString(Type) << ") ";
		*CppOut << "NormToHardLimit" << WhatTypeString(Type) << "(" ;
/*
 *		*CppOut << "(" ;
 *		if (strcmp("1.",StrScaleFac)) *CppOut << StrScaleFac << " *" ;
 *		*CppOut << "NormToOne" << WhatTypeString(Type) << " * " ;
 */
	}
	if (symbolic_value) *CppOut << symbolic_value ;
	else EmitValue(Value);
	if (StrScaleFac) *CppOut << ")" ;
}


void EmitScaledValue(Compound * Value)
{
	EmitScaledValue(Value,0,0);
}


static void EmitVariables()
{
	if (!TheNodeVariables) return ;
	NodeVariableListIterator Next(*TheNodeVariables);
	NodeVariable * Variable ;
	while (Variable = Next()) {
		*HeaderOut << "\t" << WhatTypeString(Variable->Type) ;
		if (Variable->Ptr) *HeaderOut << "* " ;
		*HeaderOut << " " << Variable->Name << ";\n" ;
	}
}

static void EmitGetVariables()
{
	// cout << "EmitGetVariables - TheNodeVariables = 0x" <<
	// 	hex((long)TheNodeVariables) << "\n" ;
	if (!TheNodeVariables) return ;
	NodeVariableListIterator Next(*TheNodeVariables);
	NodeVariable * Variable ;
	while (Variable = Next()) {
		// cout << "Emitting `" << Variable->Name << "'\n" ;
		*HeaderOut << "\t" << WhatTypeString(Variable->Type) ;
		if (Variable->Ptr) *HeaderOut << "* " ;
		*HeaderOut << "Get" << Variable->Name << "() const { return " <<
			Variable->Name << ";}\n" ;
	}
}

int EmitCheckSafe = 0;

static void DeclareNodesInit(MofStream * Out)
{
	*Out << "void " << NodeName << "NodesInit()" ;
}


void EmitDeclarationCode(int IsTiming)
{
	// time to emit the declaration of the DfNode
	*HeaderOut << "class " << NodeName << ": " ;
	if (PublicFlag) *HeaderOut << "public " ;
	else *HeaderOut << "private " ;
	PublicFlag = 0 ;
	CtorBaseClassDefaults->EmitBaseFunctionName(*HeaderOut);
	EmitOtherBaseClasses(*HeaderOut);
	*HeaderOut << " {\n" ;
	// *HeaderOut << CtorBaseClassDefaults->BaseFunctionName << " {\n" ;
	EmitPrivateCode(TheDeclarationCode);
	HeaderOut->LineOut();
	EmitVariables();
	EmitStaticInitVariables(*HeaderOut);
	if (NetworkRefFlag)
		*HeaderOut << "\tNetworkStateControl** TheNetworkReference;\n";
	// cout << "After EmitVariables\n" ;
	TheNodeCtor->EmitCtor(*HeaderOut);
	HeaderOut->PushSecondFileSelect(BaseStreamBuf::Off);
	if (EmitCheckSafe) *HeaderOut << "\tvirtual int CheckSafeDelete() ;\n" ;
	HeaderOut->PopSecondFileSelect();
	EmitGetVariables();
	EmitPublicCode(TheDeclarationCode,IsTiming);
	HeaderOut->LineOut();
	*HeaderOut << "};\n\n" ;
	delete TheDeclarationCode ;
	TheDeclarationCode = 0 ;

	if (!BaseSwitch) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*CppOut << NodeName << " * " << NodeName << "Def;\n\n" ;
		// DeclareNodesInit(HeaderOut);
		// *HeaderOut << " ;\n" ;
		CppOut->PopSecondFileSelect();
	}
}

void FoundDeclarationCode(TextFragmentList * code)
{
	TheDeclarationCode = code ;
}

void FoundDfNodeCtor()
{
	TheNodeParameters->CheckAtMostOneFirstDefault() ;
	SaveTheNodeParameters = TheNodeParameters ;
	TheNodeCtor = new MemberFunction("",NodeName,0,0,TheNodeParameters);
	TheNodeParameters = new NodeParameterList ;
}

void FoundCtorParam(const char * name, Compound * exp)
{
	if (!name) return ;
	CkStr(exp) ;
	for (int i = 0 ; i < CtorBaseClassDefaults->NumberParameters ; i++) {
		if (!strcmp(name,CtorBaseClassDefaults->
			Parameters[i].UserName)) {
			if(CtorParamFound[i].Name) yyerror(
				"constructor parameter name used twice");
			else {
				CtorParamFound[i].Name = name ;
				CtorParamFound[i].Expression = exp->Item.Str;
				exp->Item.Str = 0; // don't delete
				name = 0; 	   // don't delete
			}
			break ;
		}
	}
	// delete name ;
	delete exp ;
	if (i < CtorBaseClassDefaults->NumberParameters) return ;
	cerr << "Constructor parameter name `" << name << "' is invalid.\n" ;
	yyerror("unknown constructor parameter");
}

static const char * TeXdirectory = 0 ;

static void MakeTeXDoc(Description * NodeDesc)
{
	if (! TeXdirectory) return ;
	// cerr << "MakeTeXDoc called\n" ;
	TheTeXDocumentation = new TeXDocumentation(InputFileNameBase,TeXdirectory) ;
	TheTeXDocumentation->FoundNode(NodeName,TheNodeParameters, NodeDesc);
	if (TheMemberFunctions) {
		MemberFunction * TheMember ;
		MemberFunctionListIterator Next(*TheMemberFunctions) ;
		while (TheMember = Next()) TheTeXDocumentation->
			FoundMemberFunction(TheMember);
	}
}

void FoundBaseDescription(TextFragmentList * List)
{
	if (!TheMemberFunctions) {
		cerr << "Warning: base description and no member functions.\n";
		cerr << "Description ignored.\n" ;	
		return ;
	}
	Description TempDesc(0, List);
	MakeTeXDoc(&TempDesc);
}

void FoundNodeDescription(Compound * Descript)
{
	if (!Descript && BaseSwitch) return ;
	if (CheckBase("node description")) return ;
	if (Descript->Type != TypeDescription) DbgError("FoundNodeDescription",
		"bad type");
	TheNodeDescription = Descript->Item.Desc;
	if (!TheNodeDescription->HelpLine) cerr <<
		"*********FoundNodeDescription no menu\n" ;
	Descript->Item.Desc = 0;
	if (!BaseSwitch) MakeTeXDoc(TheNodeDescription) ;
	delete Descript ;
}

Compound * NullDescription()
{
	return new Compound(TypeDescription, *(new Object ((Description *) 0)));
}


static void CheckValidConstant (Compound * Con)
{
	switch(Con->Type) {
case TypeInt:
case TypeDouble:
case TypeString:
		return ;
case TypeName:
case TypeTerm:
case TypeText:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeSize:
case TypeParameter:
case TypeParamFunc:
case TypeScaledType:
default:
		DbgError("CheckValidConstant","bad type");
	}
}


Compound * FoundConstant(Compound * Con)
{
	CheckValidConstant(Con) ;
	return new Compound ( TypeList, *(new Object(new CompoundList(Con))));
}

Compound * FoundConstant(Compound * ConList, Compound * Con)
{
	if (ConList->Type != TypeList) DbgError("FoundConstant","bad type");
	ConList->Item.List->Append(Con);
	return ConList ;
}



void EmitDfNodeParam()
{
	CtorBaseClassDefaults->EmitDfNodeParam(*CppOut);
}


static void EmitCtorPrologue()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	*CppOut << "static EntityList * " << NodeName << "NodeList = 0 ;\n" ;
	*CppOut << "static InteractiveEntity * IntEnt" << NodeName <<" ;\n" ;
	DeclareNodesInit(CppOut) ;
	*CppOut << ";\n" ;
	CppOut->PopSecondFileSelect();
}

static void EmitIfNeedInit(const char * Neg = 0)
{
	*CppOut << "\tif (" ;
	if (Neg) * CppOut << Neg ;
	*CppOut << NodeName << "NodeList) " ;
}

static void EmitCtorInit()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	if (!BaseSwitch) {
		EmitIfNeedInit("!") ;
		*CppOut << NodeName << "NodesInit() ;\n" ;
		*CppOut << "\t" << NodeName <<
			"NodeList->Append(MakeDeclaredEntity(this, IntEnt"
			<< NodeName << ")) ;\n" ;
		*CppOut << "\tInitArithType(TheArithType);\n" ;
	}
	CppOut->PopSecondFileSelect();
}

static void EndOfBlock(const char * Where)
{
	CppOut->LineOut();
	*CppOut << "} // end " << Where << "\n\n" ;
}

static void EmitC_DtorMenuItem(const char * Type)
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	*CppOut << "\t" ;
	if (!strcmp(Type,"Delete")) *CppOut << "TheMenuServer->" ;
	*CppOut << Type << "MenuItem(" ;
	*CppOut << "\"" << NodeName << "\",GetName());\n" ;
	CppOut->PopSecondFileSelect();
}

inline void EmitCtorMenuItem()
{
	EmitC_DtorMenuItem("New");
}
	
inline void EmitDtorMenuItem()
{
	EmitC_DtorMenuItem("Delete");
}

void FoundCtor(TextFragmentList * code)
{
	EmitCtorPrologue();
	*CppOut << NodeName << "::" ;
	TheNodeCtor->EmitCtorFunc(*CppOut);
	EmitDfNodeParam();
	TheNodeCtor->EmitAssignCtorParam(*CppOut);
	EmitStaticInitCtors(*CppOut);
	if (NetworkRefFlag) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*CppOut << ",\n\tTheNetworkReference(0)" ;
		CppOut->PopSecondFileSelect();
		CppOut->PushFirstFileSelect(BaseStreamBuf::Off);
		*CppOut << ",\n\tTheNetworkReference(network_ref)" ;
		CppOut->PopFirstFileSelect();
	}
	EmitOtherBaseFunctionCtors();
	*CppOut << "\n{\n" ;
	EmitCtorInit();
	if (!BaseSwitch) EmitCtorMenuItem();
	if (StaticInitCode) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		EmitCppCode(StaticInitCode);
		StaticInitCode = 0 ;
		CppOut->PopSecondFileSelect();
	}
	if (NetworkRefFlag) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*CppOut << "\tTheDfNodeOptions = (DfNode::DfNodeOptionFlags)\n" <<
		    "\t\t(TheDfNodeOptions|NetworkReferenceDfNodeOption) ;\n";
		CppOut->PopSecondFileSelect();
	}
	EmitCppCode(code);
	EndOfBlock("constructor");
	EmitStaticEmitCtorFuncBody(*CppOut) ;
	EmitStaticEmitFuncBody(*CppOut) ;
}

static void DtorHeadOut()
{
	*CppOut << NodeName << "::~" << NodeName << "()\n{\n" ;
}

static void EmitDeleteInstance()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	if (!BaseSwitch) *CppOut << "\t" << NodeName <<
		"NodeList->Delete(GetName()) ;\n" ;
	CppOut->PopSecondFileSelect();
}

void FoundDtor(TextFragmentList * code)
{
	DtorHeadOut() ;
	if (!BaseSwitch) EmitDtorMenuItem();
	EmitDeleteInstance();
	if (code) EmitCppCode(code);
	EndOfBlock("destructor") ;
}

void FoundCheckSafeDelete(TextFragmentList * code)
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	const char * BaseCheck = CtorBaseClassDefaults->BaseCheckSafe ;
	if (code || BaseCheck) {
		EmitCheckSafe = 1 ;
		*CppOut << "int " << NodeName << "::CheckSafeDelete()\n{\n" ;
		if (BaseCheck) *CppOut << "\tint Safe_Check_Return = " <<
			BaseCheck << "::CheckSafeDelete();\n"
			<< "\tif (!Safe_Check_Return) return 0;\n";
		if (code) EmitCppCode(code);
		else *CppOut << "\treturn 1;\n" ;
		EndOfBlock("check safe delete");
	}
	CppOut->PopSecondFileSelect();
}

static void TimingDeclOut(const char * In, const char * Out)
{
	*CppOut << "double " << NodeName << "::TimeFirst( DfNodeInLink * ";
	if (In) *CppOut << In ;
	*CppOut << ", DfNodeOutLink * " ;
	if (Out) *CppOut << Out ;
	*CppOut << ")\n{\n" ;
}


void FoundTiming(TextFragmentList * code)
{
	FoundTiming(0,0,code);
}

static void EmitInitCode()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	*CppOut << "static InitObj LocalInit(" << NodeName << "NodesInit, \"" <<
		NodeName << "\", " ;
	if (CtorBaseClassDefaults) if (CtorBaseClassDefaults->BaseFunctionName)
		*CppOut << "\"" <<
			CtorBaseClassDefaults->BaseFunctionName << "\"" ;
	else *CppOut << "0" ;
	 * CppOut << ");\n\n" ;
	CppOut->PopSecondFileSelect();
}

void FoundTiming(const char * In, const char * Out, TextFragmentList *code)
{
	TimingDeclOut(In,Out);
	EmitCppCode(code);
	EndOfBlock("timing code");

	EmitDeclarationCode(1);

}

void NoTiming()
{
	EmitDeclarationCode(0);
}


void FoundStateEmit(TextFragmentList * code)
{
	if (!code) return ;
	if (CheckBase("state emit")) return ;
	StateEmitDec(*CppOut, NodeName);
	*CppOut << "\n{\n" ;
	EmitCppCode(code);
	EndOfBlock("state emit");
}



void FoundKernel(TextFragmentList * code)
{
	if (!code) return ;
	if (CheckBase("kernel")) return ;
	if (CtorBaseClassDefaults->KernelFlag) {
		if (!code) {
			yyerror(
		"Kernel specification required for this user object type");
			return ;
		}
	} else if (code) {
		yyerror(
		"No kernel specification allowd for this user object type");
		return ;
	}
	*CppOut << "ErrCode " << NodeName << "::DoNode(int32 k)\n{\n" ;
	if (NetworkRefFlag) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		*CppOut<<"\tif (!TheNetworkReference) TheNetworkReference = GetNetworkReference();\n";
		CppOut->PopSecondFileSelect();
	}
	EmitCppCode(code);
	EndOfBlock("kernel code");
}






static void EmitMakeDeclaration(int DeclareOnlyFlag)
{
	*CppOut << "static UserEntity * Make" << NodeName
		<< "(OutTokens& Out, EntityReq Request,\n\t"
		<< "InteractiveEntity& IntNode,"
		<< "\n\tArithType::ArithCapabilities arith" ;
	if (DeclareOnlyFlag) *CppOut
		<< " = (ArithType::ArithCapabilities) TheArithType) ;\n" ;
	else *CppOut << ")\n" ;
}

static void EmitCppListFunction()
{
	*CppOut << "int " << NodeName << "::" << CppListString  <<
		"\n{\n\t" << "return IntEnt" << NodeName <<
		"->CppList(Out,Cmd,this);" << "\n}\n\n" ;
}


static void EmitDescribeDeclaration()
{
	*CppOut << "void " << NodeName << "::" << DescribeString ;
}


static void GetFillTypeOut(const char * String, int Type)
{
	if (!IsNumericType(Type)) {
		cerr << "Bad type = " << Type <<"\n" ;
		DbgError("GetFillTypeOut","bad type");
	}
	*CppOut << "\t\tOut.NextFillOut(\"(\");\n" ;
	*CppOut << "\t\tOut.NextFillOut(TypeToString(Get" << String
		<< "()));\n" ;
	*CppOut << "\t\tOut.NextFillOut(\")\");\n" ;
}

static void GetFillOut(const char * String)
{
	*CppOut << "\t\tOut.NextFillOut(Get" << String << "());\n" ;
}

static void GetNameQuoteOut(const char * String)
{
	*CppOut << "\t\tOut.NextQuoteOut(Get" << String << "()->GetName());\n" ;
}

static void GetQuoteOut(const char * String)
{
	*CppOut << "\t\tOut.NextQuoteOut(Get" << String << "());\n" ;
}

inline void LocLitFillQuoteConcat(const char * String)
{
	// LogOut << "ConcatQuote`" << String << "'\n" ;
	LitFillQuoteConcat(String,CppOut);
}


inline void LocLitFillConcat(const char * String) 
{
	// LogOut << "Concat`" << String << "'\n" ;
	LitFillConcat(String,CppOut);
}

inline void LocLitQuoteOut(const char * Name)
{
	LitQuoteOut(Name,CppOut);
}

inline void LocLitFillOut(const char * Name)
{
	LitFillOut(Name,CppOut);
}


// declared and used in $generic/yacc/text.[ch]
void EmitEmbeddedReference(const char * String, int OutOnce)
{
	if (!strcmp(String,"Name")) GetQuoteOut("Name");
	else if(!strcmp(String,NodeName)) LocLitQuoteOut(NodeName);
	else {
		NodeParameterListIterator Next(*TheNodeParameters);
		NodeParameter * Param ;
		while (Param = Next()) if(!strcmp(Param->Name,String)) {
			LocLitQuoteOut(String) ;
			if (!OutOnce) {
				if (Param->Size) return ;
				// Do not output anything for array

				if (Param->ClassType) GetNameQuoteOut(String);
				else if (!Param->Type) GetQuoteOut(String) ;
				else if (Param->Type->Type == STRING)
					GetQuoteOut(String);
				else GetFillTypeOut(String,Param->Type->Type);
			}
			return ;
		}
		cerr << "Warning: embedded name `$" << String <<
			"' is undefined.\n" ;
	}
}



static void EmitDescribe()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	EmitMakeDeclaration(1);
	// *CppOut << ";\n" ;
	EmitCppListFunction() ;
	EmitDescribeDeclaration();
	*CppOut << "\n{\n\tswitch(Option) {\n" ;

	*CppOut << "case ListSingleEntity:\n" ;
	TheNodeCtor->EmitNodeParameterDescriptions(*CppOut);
	*CppOut << "\t\tbreak;\n" ;

	*CppOut << "case ListEntityMembers:\n\t\tOut.NextOut(GetName());\n\t\tbreak;\n" ;

	*CppOut << "case ListGlobalClasses:\n" ;

	*CppOut << "case ListEntityClasses:\n\t\tbreak ;\n" ;

	*CppOut << "case ListSetParameterValues:\n" ;
	if (!BaseSwitch) TheNodeCtor->EmitSetNodeParameterValues(*CppOut);
	*CppOut << "\t\tbreak;\n\t}\n" ;

	EndOfBlock(" list entity switch");
	CppOut->PopSecondFileSelect();
}

const char * InteractiveEntityListName = "InteractiveNode" ;

void FoundInteractiveList(const char * Text)
{
	InteractiveEntityListName = Text ;
}


static void StartEmitInit() ;



const char * TypePrefix(int Type)
{
	switch(Type) {
case INT:
case INT16:
case INT32:
		return "Int" ;
case DOUBLE:
		return "Float" ;
default:
		cerr << "Bad type = " << Type << "\n" ;
		DbgError("TypePrefix","unknown type");
	}
	return 0 ;
}



const char * GetOneParType(int Type)
{
	switch (Type) {
case INT16:
case INT32:
		return "Int" ;
case DOUBLE:
		return "Float" ;
case STRING:
		return "String" ;
default:
		if (IsVoidNumericType(Type)) return "Array" ;
		return "GetOneParType bad type" ;
		// DbgError("GetOneParType","unknown type");
	}
	return 0;

}

void EmitQuotedHelpLine( MofStream& Out,TextFragmentList * Text)
{
	Out << "\"" ;
	EmitHelpLine(&Out,Text);
	Out << "\"" ;
}



	

/*
 * static IntParam GraphOptParam =	{1,0,0,0,0,2} ;
 * 
 * static OneParameter GraphParamList[] = {
 * 	{"Option",0,"display option 0-short, 1-full, 2-timing",&GraphOptParam},
 *	{0}};
 */

static void CommonComplete()
{
	EmitInitCode() ;
}


void CodeComplete()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	if (!BaseSwitch) {
		CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
		if (DefaultInstance) *HeaderOut << "extern " << NodeName
			<< " * " << NodeName << "Def;\n\n" ;
		CppOut->PopSecondFileSelect();
		EmitDescribe();
	}
/*
 *	*CppOut << "static OneParameter * " ;
 *	EmitParArrayName() ;
 *	*CppOut <<";\n";
 */
	if (!BaseSwitch) {
		TheNodeCtor->EmitParamCheckFuncs(*CppOut,CheckFuncExternal);
		TheNodeCtor->EmitSetVariables(*CppOut) ;
	}
	TheMemberFunctions->EmitMemberParmCheckFuncs();
	TheMemberFunctions->EmitInteractiveFunctions();
	// CommonComplete();
	CppOut->PopSecondFileSelect();
	StartEmitInit() ;
}

static void StartEmitInit()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	if (!BaseSwitch) TheNodeCtor->CheckForArrayExt(*CppOut,*HeaderOut);
	TheMemberFunctions->EmitMemberFunctions(*CppOut);
	TheNodeCtor->EmitCheckLegalFunctions(*CppOut,NodeName);
	DeclareNodesInit(CppOut) ;
	*CppOut << "\n{\n" ;
	EmitIfNeedInit() ;
	*CppOut << " return ;\n" ;
	if (!BaseSwitch)   {
		*CppOut <<
		"\n\tstatic StringParam " << NodeName << "NameParam =\n\t\t{"
		<< "\""
		<< NodeName << "\", MakeNewEntityName, 0, LegalEntityName};\n" ;
		TheNodeCtor->EmitParamCheckFuncs(*CppOut,CheckFuncHeader);
		TheNodeCtor->EmitCtorParameterChecks(*CppOut);
		TheNodeCtor->EmitCtorParameterArray(*CppOut);
		TheNodeCtor->EmitParamCheckFuncs(*CppOut,CheckFuncAssign);
	}
	TheNodeCtor->EmitInteractiveInterface(*CppOut,TheMemberFunctions);
	TheNodeCtor->EmitDecInteractiveEntity(*CppOut,TheMemberFunctions) ;
	if (!BaseSwitch) *CppOut << "\tIntEnt" << NodeName <<
		"->SetParameters(new UserParameters(" << NodeName <<
		"ParArray));\n" ;
	*CppOut << "\tTheNodes->Append(IntEnt" << NodeName << ");\n" ;
	EmitNodeInstances();
	CppOut->PopSecondFileSelect();
}

static void CompleteEmitInit()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	EndOfBlock("initalization");
	CppOut->PopSecondFileSelect();
}




static void EmitCtorForNode(NodeParameterList * names)
{
	*CppOut << "\t\treturn new " << NodeName << "(Name" ;
	NodeParameterListIterator Next(*names);
	NodeParameter * Name ;
	while (Name = Next()) {
		*CppOut << ", " << Name->Name ;
		if (Name->Size) *CppOut << ", " << Name->Name << "_Length" ;
	}
	*CppOut << ");\n" ;
}

static void EmitBreak()
{
	*CppOut << "\t\tbreak;\n" ;
}


static void EmitMakeNode()
{
	CppOut->PushSecondFileSelect(BaseStreamBuf::Off);
	EmitMakeDeclaration(0) ;
	*CppOut << "{\n\tswitch(Request) {\ncase EntityReqDescribe:\n" ;
	*CppOut << "\ncase EntityReqDescribeFull:\n" ;
	if (!BaseSwitch) if (TheNodeDescription) if(TheNodeDescription->Full) {
		EmbeddedTextOut(TheNodeDescription->Full,CppOut);
		*CppOut << "\t\tOut.NewLine();\n";
		CheckMembers(TheNodeDescription->Full);
	}
	EmitBreak() ;
	*CppOut << "\ncase EntityReqCreate:\n\t{\n" ;
	if (!BaseSwitch) {
		TheNodeCtor->EmitGetParameters(*CppOut);
		EmitCtorForNode(TheNodeParameters);
	}
	*CppOut << "\n\t}\n\t}\n\treturn 0;\n}\n\n" ;
	CppOut->PopSecondFileSelect();
}

void Double::EmitValue(class MofStream * Out)  const
{
	*Out << String;
}

void Compound::ExpOut(MofStream * Out) const
{
	switch (Type) {
case TypeInt:
case TypeDouble:
		EmitValue(Out);
		return ;
case TypeString:
case TypeName:
		*Out << Item.Str ;
		return ;
case TypeList:
		{
			CompoundListIterator Next(*(Item.List));
			Compound * Elt ;
			while (Elt = Next()) Elt->ExpOut(Out) ;
		}
		return ;
case TypeCompound:
		Item.Tree->ExpOut(Out);
		return ;
case TypeText:
case TypeTerm:
case TypeDescription:
case TypeSize:
case TypeParameter:
case TypeParamFunc:
case TypeScaledType:
	default :
		*Out << "Compound::EmitValue bad type " << (int) Type  ;
		// DbgError("Compound::EmitValue","bad type");
	}
}

void Compound::EmitValue(MofStream * Out) const
{
	switch (Type) {
case TypeInt:
		*Out << Item.Int ;
		return ;
case TypeDouble:
		Item.Dbl->EmitValue(Out);
		return ;
case TypeString:
		// *Out << Item.Str ;
		*Out << "\"" << Item.Str << "\"" ;
		return ;
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeSize:
case TypeParameter:
case TypeList:
case TypeParamFunc:
case TypeScaledType:
	default :
		*Out << "Compound::EmitValue bad type " << (int) Type  ;
		// DbgError("Compound::EmitValue","bad type");
	}
}

static void DefErr(const char * err)
{
	DbgError("GetDefaultArraySize",err);
}

int32 GetDefaultArraySize(NodeParameter * Param)
{
	Compound * Def = Param->Default ;
	if (!Def) DefErr("null Default");
 	if (Def->Type != TypeList) DefErr("bad type");
 	CompoundList * Lst = Def->Item.List ;
	if (Lst->Size() != 1) DefErr("list bad size");
	CompoundListIterator Next(*Lst);
	Compound * Val = Next();
	if (Val->Type != TypeInt) DefErr("list element type");
	return Val->Item.Int ;
}
 
	


void NodeComplete()
{
	if (! TheTeXDocumentation &&TheMemberFunctions->Size() && TeXdirectory) {
		cerr<<"Warning member functions and no object description.\n" ;
		cerr << "No TeX documentation created.\n" ;
	}
	CompleteEmitInit();
	WriteMenuData(/* LocalName, RemoteName, */ NodeName,
			TheNodeParameters,TheNodeDescription);
	if (!BaseSwitch) EmitMakeNode();
	CommonComplete();
}


void Double::Negate()
{
	Value = -Value ;
	const char * Temp = String ;
	String = MakeCompoundName("-",String);
	// delete Temp ;
}

static void Usage(const char * Pgm)
{
	if (!SaveMenuDirectory) SaveMenuDirectory = "." ;
	cerr << "Usage is: " << Pgm <<
		" [-m dir] [-t dir] [-u dir] [-d dir] [-c] [-i] file\n" ;
	cerr << "or: " << Pgm << "`-D'  for create developers's manual documentation\n" ;
	cerr << "`-m dir' directory for the interactive C code.\n" ;
	cerr << "`-t dir' make target code in directory `dir'.\n" ;
	cerr << "`-u dir' directory of the `.nod' files for the menu data base.\n" ;
	cerr << "`-d dir' create tex documentation in directories `dir' and `dirs'.\n" ;
	cerr << "         (The second directory is `dir' with an `s' appended.)\n" ;
	cerr << "`-c' clears code generation." <<
		" It must be followed by `-i' or `-t dir'.\n" ;
	cerr << "`-i' generate interactive code (default is set).\n" ;
	cerr << "The default directory for `.nod' files is `" << SaveMenuDirectory
		<< "'.\n" ;
	exit (1);
}

void FoundArithType(const char * TargetType)
{
	// Check if it is legal
	uint32 Count = 0 ;
	for (const char **ck = ArithType::CapabilityNames; *ck ; ck++,Count++)
		if (!strcmp(*ck,TargetType)) break ;
	if (*ck) if (!strcmp(ArithType::ClassSuffix[Count],"illegal")) ck =0;
	if (!*ck) {
		cerr << "Warning: invalid arithmetic type `" <<
			TargetType << "' ignored" ;
		OutWhereEnd();
		return ;
	}
	// Check if it is already specified
	Count = 1 << Count ;
	if (CapabilitiesPresent  & Count) {
		cerr << "Warning: duplicate arithmetic type `" <<
			TargetType << "'" ;
		OutWhereEnd();
		return ;
	}
	// Add capability
	CapabilitiesPresent = CapabilitiesPresent | Count ;
	MultipleArithmeticGen= 1;
}

void FoundFirstArithType(const char * TargetType)
{
	FoundArithType(TargetType);
}

void FoundTargetType(int Type)
{
	// cerr << "FoundTargetType(" << Type << ")\n" ;
	switch(Type) {
case InteractiveFileOnly:
		TargetCodeGen = 0 ;
		InteractiveCodeGen = 1 ;
		break ;	
case TargetFileOnly:
		TargetCodeGen = 1 ;
		InteractiveCodeGen = 0 ;
		break ;	
	}
}


void main(int argc,char ** argv)
{
	int c;
	int errflg = 0;
	while (( c = getopt(argc,argv,"Du:t:icm:d:")) != EOF) { switch(c) {
case 'D':
		create_prgramming_documentation();
		exit(0);
case 'm':
		SourceCodeDir = Concatenate(optarg,"/") ;
		break ;
case 'u':
		MenuDirectory = optarg ;
		break ;
case 't' :
		TargetCodeGen = 1 ;
		TargetDir = optarg ;
		break ;
case 'i' :
		InteractiveCodeGen = 1 ;
		break ;
case 'd' :
		TeXdirectory = optarg ;
		break ;
case 'c' :
		TargetCodeGen = InteractiveCodeGen = 0 ;
		break ;
default:
		errflg++;
		break ;
	}}
	if (errflg || (!InteractiveCodeGen && !TargetCodeGen)) {
		cerr << "Invalid command line.\n" ;
		Usage(argv[0]);
	}
	int OneName = 0;
	for (; optind < argc; optind++) {
		// cerr << "optind = " << optind << "\n" ;
		if (OneName) {
			cerr << "Only one input file is allowed.\n" ;
			Usage(argv[0]);
		}
		OneName = 1;
		InputFileName = new char[strlen(argv[optind])+1];
		strcpy(InputFileName,argv[optind]);
		FILE * Temp = freopen(InputFileName,"r",stdin);
		if (!Temp) {
			cerr << "Cannot open input file `" << InputFileName <<
				"'\n" ;
			exit(2);
		}
		CurrentFileName = InputFileName ;
		InputFileNameBase = MakeOutFileName(InputFileName);
	}
	
	const char *Root = "OPD_ROOT" ;
	OpdRoot = getenv(Root);
	if (!OpdRoot) {
		cerr << "Environmental variable `" << Root << "' not set.\n" ;
		exit(1);
	}
	DoubleOne = new Double(1.,"1.");
	// cout << "Started execution\n" ;
	InitTheIncludes() ;
	int Success = ParseMain();
	if (!Success) exit(1);
	delete HeaderOut;		// flush output
	delete CppOut ;
	if (TheTeXDocumentation) delete TheTeXDocumentation ;
	delete BaseClassHeadOut ;
	delete BaseClassBodyOut ;
	CloseSpellFile();
	CloseMenuFile();
	CtorParamInit(); 		// clean up storage
	exit(0);
}

void EmitCppCode(TextFragmentList *code)
{
	EmitCode(code,OutputCpp);
	CppOut->LineOut();
}

