
//-----------------------------------------------------------------
//  support.C
//
//  A support file for  `ADT INTERPRETER PROJECT'. Contains some
//  support functions.
//
//  Items included in this file:
//
//	strupr  (only for Unix)
//	GetUserTypes
//	GetParentTypes
//	BasicType
//	OverloadedOperator
//	FixOverloadedName
//	StripQuotes
//	GetOperations
//	GetTypeIndex
//	GetBuiltinTypeIndex
//	GetExportedType
//
//-----------------------------------------------------------------


#include "drgen.h"

extern char BuiltinTypes[][KEYWORD_LEN];

//-------------------------------------------------------------------
// Converts a string to upper-case
//-------------------------------------------------------------------
#ifdef UNIX
void strupr(char *str) {
	int len = strlen(str);
	for (int i=0; i<len; i++)
		str[i] = toupper(str[i]);
}
#endif

//-------------------------------------------------------------------
// Updates the total number of TYPES in TypeList.
// Reads the file `ancestor.dat'. The first filename after every
// `!!!!' string is a file which potentially contains an EXPORTED
// PRIVATE TYPE. If it does, a node is inserted in `TypeList'.
// Other files till the string `....' potentially contain
// ancestor ADTs (which, if present, are inserted in `ancestor lists').
//-------------------------------------------------------------------
void GetUserTypes(LinkedList &TypeList) {
	ifstream fin("ancestor.dat", ios::in);     // open ANCESTOR file
	if (!fin) {
		cerr << "Can't open `ancestor.dat' for input\n";
		exit(1);
	}

	char str[81] = "";
	char FileName[FILENAME_LEN];
	char PkgName[PKGNAME_LEN];
	char TypeName[TYPENAME_LEN];
	TypeNode *typ_ptr;

	fin >> str;		// reading from ancestor.dat, should be OK
	while (!fin.eof()) {
		if (strcmp(str, "!!!!") == 0) {
			fin >> FileName;	// read from ancestor.dat, OK
			// if it EXPORTS a PRIVATE TYPE, update TypeList
			if (GetExportedType(FileName, PkgName, TypeName)) {
				typ_ptr=new TypeNode(PkgName,TypeName,FileName);
				TypeList.InsertAtTail(typ_ptr);
				// also get a list of PARENT TYPES
				GetParentTypes(fin, typ_ptr);
			}
		}
		fin >> str;		// another read from ancestor.dat
	}
	fin.close();
}


//--------------------------------------------------------------------
// Generates a list of Parent types for a PRIVATE TYPE.
// Reads the file `ancestor.dat' to do so.
//--------------------------------------------------------------------
void GetParentTypes(ifstream &fin, TypeNode *typ_ptr) {
	char FileName[FILENAME_LEN];
	char PkgName[PKGNAME_LEN];
	char TypeName[TYPENAME_LEN];
	ParentNode *prt_ptr;
	while (1) {                           // loop until you hit `....'
		fin >> FileName;              // read from ancestor.dat, OK
		if (strcmp(FileName, "....") == 0)
			return;
		// if it EXPORTS a PRIVATE TYPE, include it in parent list
		if (GetExportedType(FileName, PkgName, TypeName)) {
			prt_ptr = new ParentNode(PkgName, TypeName, FileName);
			typ_ptr -> ParentList.InsertAtTail(prt_ptr);
		}
	}
}



int BasicType(char *str) {
	if (strcmp(str, "INTEGER") && strcmp(str, "FLOAT")
				   && strcmp(str, "BOOLEAN")
				   && strcmp(str, "NATURAL")
				   && strcmp(str, "POSITIVE")
				   && strcmp(str,  "CHARACTER"))
		return 0;
	else
		return 1;
}


int OverloadedOperator(char *str) {
	if (strcmp(str, "+") && strcmp(str, "-")
			   && strcmp(str, "&")
			   && strcmp(str, "*")
			   && strcmp(str, "/")
			   && strcmp(str, "=")
			   && strcmp(str, "<")
			   && strcmp(str, ">")
			   && strcmp(str, ">=")
			   && strcmp(str, "<=")
			   && strcmp(str, "**"))
		return 0;
	else
		return 1;
}

char *FixOverloadedName(char *str) {
	if (strcmp(str, "+") == 0) return "OVERLOADED_ADDITION";
	if (strcmp(str, "-") == 0) return "OVERLOADED_SUBTRACTION";
	if (strcmp(str, "&") == 0) return "OVERLOADED_CONCATENATE";
	if (strcmp(str, "*") == 0) return "OVERLOADED_MULTIPLY";
	if (strcmp(str, "/") == 0) return "OVERLOADED_DIVIDE";
	if (strcmp(str, "=") == 0) return "OVERLOADED_EQUAL";
	if (strcmp(str, "<") == 0) return "OVERLOADED_LESS";
	if (strcmp(str, ">") == 0) return "OVERLOADED_GREATER";
	if (strcmp(str, ">=") == 0) return "OVERLOADED_GREATER_EQUAL";
	if (strcmp(str, "<=") == 0) return "OVERLOADED_LESS_EQUAL";
	if (strcmp(str, "**") == 0) return "OVERLOADED_EXPONENT";
	return str;
}


//	Remove any quotes from the string passed to it
void StripQuotes(char *str) {
	int i, j;
	for (i = j = 0; str[i] != '\0'; i++)
		if (str[i] != '\"')
			str[j++] = str[i];
	str[j] = '\0';
}

//----------------------------------------------------------
// Opens LISA file and reads in all the information about
// Operation names, their parameters, parameter types and
// modes into memory.
//----------------------------------------------------------
void GetOperations(char *LISAFile, LinkedList &OperationList, char *Infile) {
	int flag;
	char line[81];
	char Package[PKGNAME_LEN];
	char PrivateType[TYPENAME_LEN];
	char dummy[81];
	OprNode *op_ptr, *temp;
	ParamNode *par_ptr;

	ifstream fin(LISAFile, ios::in);     // open LISA file
	if (!fin) {
		cerr << "Can't open " << LISAFile << " for input\n";
		exit(1);
	}

	fin.getline(line, 81);
	sscanf(line, "%s", Package);          // read in package name

	// get PRIVATE TYPE, dummy is used because we already have `Package'
	flag = GetExportedType(Infile, dummy, PrivateType);

	while (!fin.eof()) {
		line[0] = '\0';
		fin.getline(line, 81);

		// read in operation name and return type
		if (strncmp(line, "====", 4) == 0) {
			op_ptr = new OprNode;

			fin.getline(line, 81);
			StripQuotes(line);
			sscanf(line, "%s", op_ptr -> OprName);

			line[0] = '\0';
			fin.getline(line, 81);
			sscanf(line, "%s", op_ptr->RetType);

			strcpy(op_ptr->PkgName, Package);
			if (flag == 1)
				strcpy(op_ptr->PrivateType, PrivateType);

			// find number of prior occurrances of this "procname"
			temp = new OprNode;
			OperationList.Start();
			while ( (temp = (OprNode *) OperationList.NextNode()) )
				if ( temp->Compare(op_ptr) )
					op_ptr->IncOverload();

			// add all information into linked list of ops
			OperationList.InsertAtTail(op_ptr);
		}

		// read in parameter name, mode and type
		else if (strncmp(line, "&&&&", 4) == 0) {
			par_ptr = new ParamNode;

			fin.getline(line, 81);
			sscanf(line, "%s", par_ptr -> ParamName);

			fin.getline(line, 81);
			sscanf(line, "%s", par_ptr -> Mode);

			fin.getline(line, 81);
			sscanf(line, "%s", par_ptr -> Type);

			op_ptr -> IncParamCount();
			op_ptr -> ParamList.InsertAtTail(par_ptr);
		}
	}

	fin.close();
}


//-----------------------------------------------------------
// Returns index of TYPE in TypeList which matches with 'str'
//-----------------------------------------------------------
int GetTypeIndex(char *str, LinkedList &TypeList) {
	TypeNode *p;
	int TotalTypes = TypeList.TotalNodes();

	TypeList.Start();
	for (int i=1; i <= TotalTypes; i++) {
		p = (TypeNode *)TypeList.NextNode();
		if ((strcmp(str, p->TypeName) == 0) | 
		    (strcmp(str, p->LongTypeName) == 0))
			return i;
	}
	return 0;
}


//-----------------------------------------------------------
// Returns index of built-in type which matches 'str'
//-----------------------------------------------------------
int GetBuiltinTypeIndex(char *str) {
	for (int i=1; i <= TOTAL_BUILTINS; i++)
		if (strcmp(str, BuiltinTypes[i]) == 0)
			return i;
	return 0;
}


//----------------------------------------------------------------
// Opens an Ada file and determines whether it contains a package
// which EXPORTS a PRIVATE TYPE.  Passes back PkgName and TypeName
// Returns: 1 if package exports a private type
//          0 otherwise
//----------------------------------------------------------------
int GetExportedType(char *Infile, char *PkgName, char *TypeName) {
	char *str;
	str = new char[81];
	str[0] = '\0';

	ifstream fin(Infile, ios::in);         // open input file
	if (!fin) {
		cerr << "can't open " << Infile << " for input\n";
		exit(1);
	}

	while (strcmp(str, "PACKAGE") != 0) {    // find the keyword `PACKAGE'
		// fin >> str;
		strcpy(str, get_token(fin));
		if (strncmp(str,"--",2)==0) // found a comment, skip to EOL
			fin.getline(str,80,'\n');
		else
			strupr(str);
		if ( fin.eof() )
			return 0;
	}

	// fin >> PkgName;                       // get package name
	strcpy(PkgName, get_token(fin));
	strupr(PkgName);

	while (strcmp(str, "TYPE") != 0) {       // find the keyword  TYPE
		// fin >> str;
		strcpy(str, get_token(fin));
		strupr(str);
		if (fin.eof() || strcmp(str, "PRIVATE") == 0)
			return 0;
	}

	// fin >> TypeName;              // get name of the EXPORTED TYPE
	strcpy(TypeName, get_token(fin));
	strupr(TypeName);
	fin.close();
	return 1;
}
