/*  doop.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
// File contains semantic interface for network operations
#include <stream.h>
#include <fstream.h>
#include <stdio.h>
#include <string.h>

#include "debug.h"
#include "portable.h"
#include "baseio.h"

#include "y.tab.h"
#include "yachead.h"
#include "intfc.h"
#include "yacintfc.h"

#include "optab.h"
#include "doop.h"
#include "cgidbg.h"
#include "decptr.h"
#include "user.h"
#include "outtok.h"
#include "interp.h"
#include "yacoper.h"
#include "typemap.h"

struct OperTab {
	int Oper ;
	const char * StringOper ;
} TheOperands[] = {
	{SHIFT_L, " << "},
	{SHIFT_R, " >> "},
	{PLUS_EQUAL, " += "},
	{MINUS_EQUAL, " -= "},
	{0}
};

static const char * GetOperString(int Oper)
{
	
	static char * RetChar = " X " ;
	if (Oper < 128) {
		RetChar[1] = Oper ;
		return RetChar ;
	}

	OperTab * Pt = TheOperands ;

	while (Pt->Oper) if (Pt->Oper == Oper) return Pt->StringOper ;
	else Pt++ ;
	static char buf[BufSize];
	sprintf(buf," `Operand %d' ",Oper);
	return buf ;
}

void static DumpAll()
{
	TheLog << "Dump of Un's\n";
	TheLog << "Nodes are 0x" << hex <<  (long) UnTheNodes.EntityList << "\n" ;
	TheLog << "CmpdNodes are 0x" << (long) UnTheCmpdNodes.EntityList << "\n" ;
	TheLog << "Displays are 0x" << (long) UnTheDisplays.EntityList << "\n" ;
	TheLog << "Signals are 0x" << (long) UnTheSignals.EntityList << "\n" ;
	TheLog << "Nets are 0x" << (long) UnTheNets.EntityList << dec << "\n" ;
	
	TheLog << "Dump of operand tables\n";
	for (ClassOp * r = AllClassBinaryOps ; r->Operator ; r++) r->Dump();
}



struct ValueType * BinOpEnt(ValueType* Op1, int Oper, ValueType* Op2)
{
	OutTokens Out(OutputPrompt,0,""," ","",78);
	InteractiveEntity * Op2Ent = 0;
	if (Op2->Type == DecEnt) Op2Ent = GetIntEntFromObj(Op2);
	if (Op1->Type == DecEnt) {
		InteractiveEntity * Ent = GetIntEntFromObj(Op1);
		if (!Ent) DbgError("BinOpEnt","no such entity");

/*
 *		LogOut << "BinOpEnt(" << Ent->GetClassName() << ", "
 *			<< Op2Ent->GetClassName() << ")\n" ;
 */

		// Procedure * ThisProc =
		//	Ent->GetMemberProcedure(GetOperatorName(Oper));
		// LogOut << "ThisProc = 0x" << hex((long)ThisProc) << "\n" ;
		for (Procedure * ThisProc =
		  Ent->GetMemberProcedure(GetOperatorName(Oper));
		  ThisProc; ThisProc = ThisProc->GetOverload()) {
		  // while (TheProc) {
			// Procedure * ThisProc = TheProc ;
			// TheProc = ThisProc->GetOverload();
			// LogOut << "ThisProc = 0x" << (long) ThisProc << "\n" ;
			OneParameter * Param =
				ThisProc->GetParameters()->GetAllParameters();
			if (!Param->Name) continue ; // unary operator
			if (Param[1].Name) continue ; // not binary
			EntityParam * EntP = Param->EntityP ;
			if (EntP) {
				while (Op2Ent) {
/*
 *					LogOut << "Cmp1 - " <<
 *						EntP->EntityClass << " : " <<
 *						Op2Ent->GetClassName() << "\n" ;
 */
					if (!strobjcmp(EntP->EntityClass,
						Op2Ent->GetClassName())) {
						ParameterList TempList ;
						TempList.SetName(ThisProc->GetName());
						TempList.Append(Op2);
						ValueType Temp(DecParam,
							&TempList);
						ThisProc->GetParameters()->
							SetParamValues(-1,
								&Temp);
						State.DoingThis(
							"Doing operation: ",
							ThisProc->GetMenuLine(),
							".");
						ValueType * Res=MakeReturnValue(
							ThisProc->DoCall(Out,
							EntityReqCall,
							Op1->Value.ValEnt),
							ThisProc->
							GetTypeName());
						// TempList.Clear();
						delete Op2 ;
						return Res ;
						// return Op1 ;
						// This is not general and
						// must be changed
					}
					Op2Ent = Op2Ent->GetBaseEntity();
				}
				continue ;
			}	
			// add code for built in (int double etc.) parameters
		}
	}
	
	BinarySemanticRoutine Routine ;
	// DumpAll();
	for (ClassOp * Ptr = AllClassBinaryOps ; Ptr->Operator ; Ptr++)  {
		if (Ptr->Operator == Oper) {
			for ( OperandOpt * OpPtr = Ptr->Operands ;
			OpPtr->Op1.Type != OperandEnd; OpPtr++) {
/*
 *				LogForm(
 *			"Checking Type = %d, List1 = 0x%x, List2 = 0x%x",
 *					OpPtr->Op1.Type,
 *					(long) OpPtr->Op1.Op ,
 *					(long) OpPtr->Op2->Op2.Op) ;
 */
				if (Routine = OpPtr->CheckOperands(Op1,Op2))
					return Routine(Op1,Op2) ;
			}
		}
	}
	State.Error(NameOfObj(Op1),GetOperString(Oper),NameOfObj(Op2),
		" is not a valid expression");
	return 0 ;
}


