
//------------------------------------------------------------------------
//   generics.C
// 
//   Used in `ADT INTERPRETER PROJECT'
//   Handles GENERIC PACKAGES.
//
//   Items included in this file:
//
//	GenericInstantiator
//	GetOrdinaryGenericParams
//	GetComplexGenericParams
//	GetGenericFile
//
//------------------------------------------------------------------------

#include "drgen.h"


void GetOrdinaryGenericParams(ofstream &fout, char *filename, int *first_par);
void GetComplexGenericParams(ofstream &fout, char *filename,
                                 int *first_par, LinkedList &GenericList);
char *GetGenericFile(char *GenericInstFile);

// #ifdef UNIX
// extern strupr(char *);
// #endif

//Used for debugging
//void print_string(char* s){
//
//	for (int i = 0; i <= strlen(s); i++)
//		cout << s[i];
//	cout << endl;
//}

char *get_token(ifstream &fin){
	char *token, *garbage;
	char *preamble_end;
	token = new char[101];
        garbage = new char[101];
	token[0] = '\0';
	fin >> token;
	while (strcmp(token,"--")==0) {
                        fin.getline(garbage, 100, '\n');
			fin >> token;
	}
	while ((strlen(token) >= 2) && (strstr(token,"--") != NULL)) {
		preamble_end = strstr(token,"--");
		if (preamble_end > 0){		//have token to return
                        fin.getline(garbage, 100, '\n');
			*preamble_end = '\0';    //nullify comment portion
			}
		}
	if (strstr(token,";") != NULL){
            preamble_end = strstr(token,";");
	    *preamble_end = '\0';
	  }
	// cout << "token is : " << token << endl;
	return token;
}




//---------------------------------------------------------------------
// If the package under test is a GENERIC, user is prompted for values
// of GENERIC PARAMETERS.
// Input: `filename' -- file containing package under test
// Output: Generic Instantiation -- written to file generic.dat
//---------------------------------------------------------------------
char *GenericInstantiator(char *filename) {

	ifstream fin(filename, ios::in);             // open input file
	if (!fin)
		return NULL;

	char *str;
	str = new char[101];
	str[0] = '\0';

	while (strcmp(str, "GENERIC") != 0) {        // locate keyword GENERIC
		str = get_token(fin);
		strupr(str);
		if ( fin.eof() )
			return NULL;
	}

	cout << "GENERIC" << endl;        // display code till keyword "PACKAGE"
	str[0] = '\0';
	while (1) {
		fin.getline(str, 100);
		cout << str << endl;
		strupr(str);
		if (strstr(str, "PACKAGE"))
			break;
		if ( fin.eof() )
			return NULL;
	}
	cout << endl;

	char *p;                                  // get package name
	p = strstr(str, "PACKAGE");
	p = p+7;
	sscanf(p, "%s", str);

	ofstream fout("generic.dat",ios::out);   // open output file
	if (!fout) {
		cerr << "unable to open output file generic.dat\n";
		exit(1);
	}

	// write name of generic instantiation
	fout << "  package " << str << "_inst is new\n       " << str << '(';
	fin.close();

	int first_par = 1;        // write ORDINARY parameters to file
	GetOrdinaryGenericParams(fout, filename, &first_par);

	LinkedList GenericList;   // write complex parameters to file
	GetComplexGenericParams(fout, filename, &first_par, GenericList);
	fout << ");\n  use " << str << "_inst;\n";

	// write additional TYPE info to file
	fout << endl << GENERIC_MARKER << endl << filename << endl;
	GenericList.Print(fout);

	fout.close();
	p = new char[strlen("generic.dat")+1];
	strcpy(p, "generic.dat");
	return p;
}


//---------------------------------------------------------------------
// Promts user for values of ORDINARY generic parameters.
// Writes the values (formal => actual) in the generic instantiation.
//---------------------------------------------------------------------
void GetOrdinaryGenericParams(ofstream &fout, char *filename, int *first_par) {
	ifstream fin(filename, ios::in);             // open input file
	if (!fin) return;

	char *str;
	str = new char[101];
	str[0] = '\0';
	while (strcmp(str, "GENERIC") != 0) {         // locate keyword GENERIC
		str = get_token(fin);
		strupr(str);
		if ( fin.eof() )
			return;
	}

	int terminate = 0, terminate_in;
	char *p1, *p2;
	char var[101], value[101];
	while (!terminate) {       // get values for ORDINARY generic parameters
		fin.getline(str, 100);
		strupr(str);
		for (char *p = str; *p != '\0'; p++)  // truncate off comments
			if (*p == '-' && *(p+1) == '-') {
				*p = '\0';
				break;
			}

		// terminate "file scan" on hitting keyword "PACKAGE"
		p1 = strstr(str, "PACKAGE");
		if (p1) {
			terminate = 1;
			*p1 = '\0';
		}

                // if ":" appears before "(" you've hit ORDINARY parameter(s)
		p1 = strstr(str, ":");
		if (p1) {
			p2 = strstr(str, "(");
			if (p2 > p1 || p2 == NULL)
                		// terminate "line scan" on hitting a colon
				for (terminate_in=0, p1=p2=str;
							terminate_in!=1; p2++) {
					if (*p2 == ':')
						terminate_in = 1;
					if (*p2 == ',' || *p2 == ':') {
						*p2 = ' ';
						sscanf(p1, "%s", var);
						cout << "Enter a value for "
								<< var << ": ";
						cin >> value;

						if (*first_par)
							*first_par = 0;
						else
							fout << ",\n\t\t\t";
						fout << var << "=>" << value;
						p1 = p2;
					}
				}
		}
	}
	fin.close();
}


//---------------------------------------------------------------------
// Promts user for values of TYPE and FUNCTION generic parameters.
// Writes the values (formal => actual) in the generic instantiation.
//---------------------------------------------------------------------
void GetComplexGenericParams(ofstream &fout, char *filename,
                               int *first_par, LinkedList &GenericList) {
	ifstream fin(filename, ios::in);             // open input file
	ofstream fout2("with.dat", ios::out);         // implicit withs file
        char tmp[FILENAME_LEN];
        char *tmp2;
        WithList *withs;
        WithList *last;
	WithList *current;
	withs = new WithList("    ");
	last = withs;
	if (!fin)
		return;
	char *str;
	str = new char[101];
	str[0] = '\0';
	while (strcmp(str, "GENERIC") != 0) {         // locate keyword GENERIC
		str = get_token(fin);		
		strupr(str);
		if ( fin.eof() )
			return;
	}

	// get actual values for generic TYPE and FUNCTION parameters
	char value[101];
	char *p;
	GenericNode *gptr;
	while (strcmp(str, "PACKAGE") != 0) {
		str = get_token(fin);
		strupr(str);
		if ( fin.eof() )
			return;
		if (strcmp(str, "TYPE") == 0) {
			str = get_token(fin);
			cout << "Enter a value for " << str << ": ";
			cin >> value;
			strupr(value);
			strcpy(tmp, value);
			tmp2 = strchr(tmp,'.');
 			if (tmp2 != NULL){
			  *tmp2 = '\0';
			  current = withs->next;
			  while (current != NULL){
			    if (strcmp(current->PkgName,tmp) == 0)
			      break;
			    current = current->next;
			  }
			  if (current == NULL){
			    last->next = new WithList(tmp);
			    last = last->next;
			  }
			}

			gptr = new GenericNode(str, value, "TYPE");
			GenericList.InsertAtTail(gptr);

			if (*first_par)
				*first_par = 0;
			else
				fout << ",\n\t\t\t";
			fout << str << "=>" << value;
		}
		else if (strcmp(str, "WITH") == 0) {
			str = get_token(fin);
			str = get_token(fin);
			if ((p = strstr(str, "(")) != NULL)
				*p = '\0';
			cout << "Enter a value for " << str << ": ";
			cin >> value;
			strupr(value);
			strcpy(tmp, value);
			tmp2 = strchr(tmp,'.');
 			if (tmp2 != NULL){
			  *tmp2 = '\0';
			  current = withs->next;
			  while (current != NULL){
			    if (strcmp(current->PkgName,tmp) == 0){
			      break;
			    }
			    current = current->next;
			  }
			  if (current == NULL){
			    last->next = new WithList(tmp);
			    last = last->next;
			  }
			}

			gptr = new GenericNode(str, value, "SUBPROGRAM");
			GenericList.InsertAtTail(gptr);

			if (*first_par)
				*first_par = 0;
			else
				fout << ",\n\t\t\t";
			fout << str << "=>" << value;
		}
	}

	current = withs->next;
	while (current != NULL ){
  	  fout2 << current->PkgName << endl;
	  current = current->next;
	}
	fin.close();
	fout2.close();
}


//---------------------------------------------------------------------
// Input: GenericInstFile - A file containing generic instantiation
//                          plus additional information
// Output: Original file containing the generic package under test
//---------------------------------------------------------------------
char *GetGenericFile(char *GenericInstFile) {
	ifstream fin(GenericInstFile, ios :: in);    // open input file
	if (!fin)
		return NULL;

	char str[GENERIC_LINE] = "";                 // goto the marker
	while (strcmp(str, GENERIC_MARKER) != 0  && !fin.eof())
		// fin >> str;
		strcpy(str, get_token(fin));

	// fin >> str;       // get filename
	strcpy(str, get_token(fin));
	if ( fin.eof() )
		return NULL;

	char *p = new char[strlen(str)+1];
	strcpy(p, str);
	return p;
}
