// --------------------------------------------------------------
// drgen.C
//
//  This is the main file for  `ADT INTERPRETER PROJECT'
//
//  Itmes included in this file:
//
//	main routine
//	GenerateDriver
//	Declarations
//	DeclareNestedProcedures
//	GenerateBody
//	Initialization
//	CaseStatement
//
// --------------------------------------------------------------

#include "drgen.h"

//--------------------------------
//     Function Prototypes
//--------------------------------
extern void Parse(char *filename, char *GenericInstFile);
extern void FindAncestors(char *Filename);
extern char *GetGenericFile(char *GenericInstFile);

//--------------------------------
//          Globals
//--------------------------------
char Keywords [][KEYWORD_LEN] = {"DUMMY", "TYPES", "TREE", "OPS", "OBJECTS",
                        "HISTORY", "HELP", "?", "NEW", "EXIT", "QUIT", "" };

char BuiltinTypes [][KEYWORD_LEN] = {"DUMMY", "INTEGER", "FLOAT", "BOOLEAN",
                        "CHARACTER", "NATURAL", "POSITIVE"};

//--------------------------------
//         Functions
//--------------------------------

int main(int argc, char *argv[]) {
	NoTypeNode *ntyp_ptr;

	if (argc < 2) {
		cout << "usage:  drgen <file>\n";
		exit(1);
	}
	// make sure the user has specified a "xxxx.ads" file
	char *proper_file;
	proper_file = strstr(argv[1], ".ads");
	if (proper_file == NULL) {
		cout << endl << "DRGEN assumes you have specified" 
			<< " a GNAT Ada package specification file," << endl
			<< "\tthat is, a 'xxxx.ads' file.  Running with any"
			<< " other file type" << endl << "\t (as you have"
			<< " specified), can cause errors within DRGEN."
			<< endl << endl;
	}

	int generic_check = 0;
	char *GenericInstFile = '\0';

	// a valid 3rd arg. means a generic check has been made
	if (argc > 2) {
		if (strcmp(argv[2], "NON_GENERIC") == 0)
			generic_check = 1;
		else {	// check for file containing generic instantiation
			ifstream fin(argv[2], ios::in);
			if (fin) {
				fin.close();
				generic_check = 1;
				GenericInstFile = new char[strlen(argv[2]) + 1];
				strcpy(GenericInstFile, argv[2]);
			}
		}
	}

	// internally check whether package is GENERIC or not
	if (!generic_check)
		GenericInstFile = GenericInstantiator(argv[1]);

	char DriverFile[81] = "driver.adb";   // determine name of driver file

	ofstream fout(DriverFile, ios::out);  // open driver file
	if (!fout) {
		cerr << "Can't open " << DriverFile << " for output\n";
		exit(1);
	}

	FindAncestors(argv[1]);		// find a list of ancestor files

	LinkedList TypeList;           // get a list of user-defined types
	GetUserTypes(TypeList);        // as well their parent types

	LinkedList OperationList;
	TypeNode *typ_ptr;                  // for all types in TypeList do
	int TotalTypes = TypeList.TotalNodes();

	TypeList.Start();
	if (TotalTypes > 0)
		for (int i=1; i <= TotalTypes; i++) {
			// generate LISA file for this TYPE
			typ_ptr = (TypeNode *)TypeList.NextNode();
			// get a list of operations and their params.
			Parse(typ_ptr->FileName, GenericInstFile);
			GetOperations("lisa.dat", OperationList,
					typ_ptr -> FileName);
		}
	else {
			// pick off xxxx part of "xxxx.ads" filename
		char temp_name[80];
		char *temp_ptr;
		strcpy(temp_name, argv[1]);
		temp_ptr = strstr(temp_name, ".ads");
		if (temp_ptr != NULL) *temp_ptr = '\0';
			// copy this to a permanent location (allocate space)
		char *no_type = new char[strlen(temp_name)+1];
		strcpy(no_type, temp_name);
			// print warning to user that no private type was found
			// construct our new "typenode" (using package name)
		ntyp_ptr = new NoTypeNode(no_type, argv[1]);
			// handle the rest (parsing, finding ops) as normal
		Parse(ntyp_ptr->FileName, GenericInstFile);
		GetOperations("lisa.dat", OperationList, ntyp_ptr->FileName);
	}

	// generate driver program
	GenerateDriver(fout, TypeList, OperationList, GenericInstFile, ntyp_ptr);
	fout.close();                                   // close driver file

	#ifdef UNIX
	  	system("rm -f ancestor.dat generic.dat lisa.dat filelist.dat with.dat");
	#endif
	return 0;
}



//----------------------------------------------------------
// Writes out the complete Ada driver program to driver file
//----------------------------------------------------------
void GenerateDriver(ofstream &fout, LinkedList &TypeList,
		LinkedList &OperationList, char *GenericInstFile,
		NoTypeNode *ntyp_ptr) {
	char DriverName[70];

	fout << "with DRGEN;\n";

	// get name of file containing generic package (package under test)
	char *GenericFile = GetGenericFile(GenericInstFile);

	// use TypeList to include all PACKAGES which define PRIVATE TYPES
	TypeNode *typ_ptr;
	int TotalTypes = TypeList.TotalNodes();
	TypeList.Start();
	for (int i=1; i <= TotalTypes; i++) {
		typ_ptr = (TypeNode *)TypeList.NextNode();
		fout << "with " << typ_ptr->PkgName << ";";
		if (GenericFile == NULL)
			fout << "  use " << typ_ptr->PkgName << ";";
		else
			if (strcmp(typ_ptr -> FileName, GenericFile) != 0)
				fout << "  use " << typ_ptr->PkgName << ";";
		fout << endl;
	}
	if (TotalTypes == 0) {
		fout << "with " << ntyp_ptr->PkgName << ";";
		if (GenericFile == NULL)
			fout << "  use " << typ_ptr->PkgName << ";";
		else
			if (strcmp(typ_ptr -> FileName, GenericFile) != 0)
				fout << "  use " << typ_ptr->PkgName << ";";
		fout << endl;
	}
		
	delete GenericFile;

	// include SUBPROGRAMS or PACKAGES in case of generics
	if (GenericInstFile != NULL) {
		char str[GENERIC_LINE] = "";
		char value[101];
		char par_kind[15];
		char *p;
		ifstream fin(GenericInstFile, ios::in);

		while (!fin.eof() && strcmp(str, GENERIC_MARKER) !=0)
			strcpy(str, get_token(fin) );
			// fin >> str;
		// fin >> str;
		strcpy(str, get_token(fin) );

		while (1) {
			// fin >> str >> value >> par_kind;
			strcpy(str, get_token(fin));
			strcpy(value, get_token(fin));
			strcpy(par_kind, get_token(fin));
			if (fin.eof())
				break;
			if (strcmp(par_kind, "SUBPROGRAM") == 0) {
				p = strchr(value, '.');
				if (p) *p = '\0';
				fout << "with " << value << ";\n";
			}
			par_kind[0] = '\0';
		}
		fin.close();
      }

	// use the last PACKAGE name to write driver name.
	strcpy(DriverName, "DRIVER");
	fout << "\n\nProcedure " << DriverName << " is\n\n";

       // write variable decl.
	Declarations(fout, TypeList, OperationList, GenericInstFile);

	fout << "\nbegin\n";

	// write body of driver
	GenerateBody(fout, TypeList, OperationList);

	fout << "\nend " << DriverName << ";\n";
}


//-----------------------------------------------------------
// Writes variable and procedure declarations to driver file
//-----------------------------------------------------------
void Declarations(ofstream &fout, LinkedList &TypeList,
                  LinkedList &OperationList, char *GenericInstFile) {
	int i;

	if (GenericInstFile != NULL) {  // write out GENERIC instantiation
		char str[GENERIC_LINE] = "";
		ifstream fin(GenericInstFile, ios::in);
		while (!fin.eof() && strcmp(str, GENERIC_MARKER) != 0) {
			fout << str << endl;
			fin.getline(str, GENERIC_LINE-1);
		}
		fout << endl;
		fin.close();
	}

	// write fixed declarations
	fout << "  in_command: string(1..200);\n";
	fout << "  in_name: string(1.." << OBJECTNAME_LEN << ");\n";
	fout << "  answer_str : string(1.." << OBJECTNAME_LEN << ");\n";
	fout << "  answer_size : integer;\n";
	fout << "  size, command_no, Index: natural;\n";
	fout << "  I: positive;\n";
	fout << "  TotalTypes, name_size: natural;\n";
	fout << "  NumTokens: integer;\n";
	fout << "  TotalBuiltinTypes: natural;\n\n";

	fout << "  type  TypeNode  is\n    record\n";
	fout << "      TypeName: string(1.." << TYPENAME_LEN << ");\n";
	fout << "      Size: natural;            -- tells  size of TypeName\n";
	fout << "    end record;\n\n";

	fout << "  type  StrNode  is\n    record\n";
	fout << "      str: string(1.." << STRING_LEN << ");\n";
	fout << "      size: natural;\n";
	fout << "    end record;\n\n";

	fout << "  TokenList: DRGEN.TokenArray(1.." << MAX_TOKENS << ");\n";
	fout << "  AToken: DRGEN.Token;\n\n";

	fout << "  BuiltinTypeList: array(1.." << TOTAL_BUILTINS
				<< ") of TypeNode;\n\n";

	// create object arrays equal to number of BUILT_IN types
	for (i=1; i <= TOTAL_BUILTINS; i++) {
		fout << "  BuiltinObjects" << i << ": array(1.." <<
			MAX_OBJECTS << ") of " << BuiltinTypes[i] << ";\n";
		fout << "  BuiltinObjectNames" << i << ": array(1.." <<
			MAX_OBJECTS << ") of StrNode;\n";
		fout << "  NumBuiltinObjects" << i << ": natural;\n\n";
	}

	// get name of file containing generic package (package under test)
	char *GenericFile = GetGenericFile(GenericInstFile);

	// write varying declarations
	int TotalTypes = TypeList.TotalNodes();
	fout << "  TypeList: array(1.." << TotalTypes;
	fout << ") of TypeNode;\n\n";

	TypeNode *p;
	TypeList.Start();     
	// create object arrays equal to number of `types'
	for (i=1; i <= TotalTypes; i++) {
		p = (TypeNode *)TypeList.NextNode();
		fout << "  Objects" << i << ": array(1.." <<
						MAX_OBJECTS << ") of ";
		fout << p->PkgName;

		if (GenericFile != NULL)
		if (strcmp(p -> FileName, GenericFile) == 0)
			fout << "_inst";

		fout << '.' << p->TypeName << ";\n";
		fout << "  ObjectNames" << i << ": array(1.." <<
			MAX_OBJECTS << ") of StrNode;\n";
		fout << "  ObjectHistory" << i << ": array(1.." <<
			MAX_OBJECTS << ") of DRGEN.HISTORY_LIST;\n";
		fout << "  NumObjects" << i << ": natural;\n\n";
	}

	delete GenericFile;
	delete GenericInstFile;

	// write procedure declarations
	DeclareNestedProcedures(fout, TypeList, OperationList);
}


//-----------------------------------------------------------
// Writes a procedure body corresponding to every operation
// When an operation is executed, the corresponding procedure
// body will be called.
//-----------------------------------------------------------
void DeclareNestedProcedures(ofstream &fout, LinkedList &TypeList,
			LinkedList &OperationList) {
	int i;

	ProcedureGetObjectIndex(fout, TypeList);
	ProcedureGetBuiltinObjectIndex(fout);
	ProcedureDetermineParameter(fout);
	ProcedureGetTypeIndex(fout);
	ProcedureGetBuiltinTypeIndex(fout);

	ProcedureOPERATIONS(fout, OperationList);   // for  OPS <Type>
	ProcedureTREE(fout, TypeList);     // for TREE
	ProcedureOBJECTS(fout, TypeList);
	ProcedureHISTORY(fout, TypeList);  // for HISTORY [<Type>.] <Object>
	ProcedureNEW(fout, TypeList);      // for NEW <Type>

	// declare PROCEDURES corresponding to available OPERATIONS
	// one PROCEDURE for each unique OPERATION name

	// basic algorithm is as follows:
	//	process each item in operation list, for each item:
	//		1.  make sure we have not done this "name" before (it
	//		    is not an overloaded name)
	//		2.  if we have not processed this name, build it
	//				pre-procedure call stuff
	//				invoke the procedure
	//				post-procedure call stuff

	int TotalOprs = OperationList.TotalNodes();

	for (int loop_ctr=1; loop_ctr <= TotalOprs; loop_ctr++) {
		OprNode *opr_ptr;
		OperationList.Start();		

		for (i=1; i<=loop_ctr; i++)
			opr_ptr = (OprNode *)OperationList.NextNode();

		if ( opr_ptr->Processed() )	// have we done this proc name?
			continue;		// yes, exit loop
		else
			opr_ptr->SetProcessed(1); // no, build proc for "name"

		// find all other operations with this same "name"
		OprNode *overload_list[MAX_OVERLOAD];
		int num_overload = 0;
		OperationList.Start();

		for (int j=1; j <= TotalOprs; j++) {
			OprNode *temp;
			temp = (OprNode *) OperationList.NextNode();
			if ( (opr_ptr->Compare(temp))
					&& ( ! temp->Processed() ) ) {
				overload_list[num_overload++] = temp;
				temp->SetProcessed(2);
			}
		}

		// print out all operations with this "name"
		// cout << "package name is " << opr_ptr->PkgName << endl;
		// cout << "\toriginal had " << opr_ptr->ParameterCount
		// 	<< " parameters" << endl;
		// for (j=0; j<num_overload; j++)
		// 	cout << "\toverloading #" << j << " had "
		// 		<< overload[j]->ParameterCount
		// 		<< " parameters" << endl;

		// write procedure name
		if (num_overload > 0) {

			// first generate each of the individual procedures
			// that the user might call named "XXX"
			OprNode *nextone;
			char ending[3];
			strcpy(ending, "_0");
			GenerateUserOperation(fout, opr_ptr, ending, TypeList);
			for (int k=1; k <= num_overload; k++) {
				nextone = overload_list[k-1];
				sprintf(ending, "_%1d", k);
				GenerateUserOperation(fout, nextone, 
						ending, TypeList);
			}

			// next call a procedure that simply calls the
			// appropriate version of "XXX" (the one that
			// matches the parameters specified by the user
			DetermineUserOperation(fout, opr_ptr, num_overload,
						overload_list, TypeList);
		}
		else
			GenerateUserOperation(fout, opr_ptr, "", TypeList);
	}
}


//----------------------------------------------------------------
// Writes out body of the driver program. Body mainly contains the
// big `if statement' and `case statement'
//----------------------------------------------------------------
void GenerateBody(ofstream &fout, LinkedList &TypeList,
			LinkedList &OperationList) {
	int i, index;

	Initialization(fout, TypeList);

	fout << "\n\n  DRGEN.put_line(\"DRGEN: Version 1.5.  Contact "
             << "parrish@cs.ua.edu with suggestions and bugs\");\n";
	fout << "  DRGEN.new_line;\n";

	fout << "\n  loop                  -- Body\n";
	fout << "    DRGEN.put(\"> \");\n";    // get next command and parse it
	fout << "    DRGEN.get_line(in_command, size);\n";
	fout << "    DRGEN.uppercase(in_command, size);\n";
	fout << "    DRGEN.parse(in_command(1..size), size, TokenList(1..20), NumTokens);\n";

	// check whether first token matches a KEYWORD
	// if so, assign a command no.
	fout << "\n    command_no := 0;\n";
	fout << "    if (TokenList(1).str(1..TokenList(1).size) = \""
		<< Keywords[1] << "\") then\n        command_no := 1;\n";

	for (i=2; i <= TOTAL_KEYWORDS; i++)
		fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \""
			<< Keywords[i] << "\") then\n"
			<< "       command_no := " << i << ";\n";

	// check whether first TOKEN matches an OPERATION name
	// if so, assign `command_no' the appropriate number
	OprNode *opr_ptr;
	OperationList.Start();
	int TotalOprs = OperationList.TotalNodes();

	for (i=1, index=TOTAL_KEYWORDS+1; i <= TotalOprs; i++, index++) {

		opr_ptr = (OprNode *)OperationList.NextNode();

		if (opr_ptr->Processed() == 1) { 

			if (OverloadedOperator(opr_ptr->OprName)) {
				// overloaded built-in operators we will swap
				// the position of token one and token two, so
				// that the routine believes you entered
				// "+"(a,b) when in reality the user typed
				// 'a + b'.  (note 'a "+" b' is also legal)
				//
				// case where user enters 'a + b'
				fout << "    elsif (TokenList(2).str(1..TokenList(2).size) = \""
					<< opr_ptr->OprName << "\") then\n"
					<< "       command_no := " << index
					<< ";\n";

				fout << "       AToken := TokenList(1); \n";
				fout << "       TokenList(1) := TokenList(2);\n";
				fout << "       TokenList(2) := AToken; \n";

				// case where user enters 'a "+" b'
				fout << "    elsif (TokenList(2).str(1..TokenList(2).size) = \"\"\""
					<< opr_ptr->OprName << "\"\"\") then\n"
					<< "       command_no := " << index
					<< ";\n";

				fout << "       AToken := TokenList(1); \n";
				fout << "       TokenList(1) := TokenList(2);\n";
				fout << "       TokenList(2) := AToken; \n";

				// case where user enters "+"(a,b)
				fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \"\"\""
					<< opr_ptr->OprName << "\"\"\") then\n"
					<< "       command_no := " << index
					<< ";\n";

				// case where user enters +(a,b)
				fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \""
					<< opr_ptr->OprName << "\") then\n"
					<< "       command_no := " << index
					<< ";\n";

				// case where user enters Type.+(a,b)
					fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \""
						<< opr_ptr->PrivateType
						<< '.'<< opr_ptr->OprName
						<< "\") then\n"
						<< "       command_no := "
						<< index << ";\n";
			}
			else {
				// this branch is only for non-overloaded
				// built in operations.  In this case the
				// user can specify either the operation name
				// itself or a qualified operation
				//
				// output unqualified OPERATION name
				fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \""
					<< opr_ptr->OprName << "\") then\n"
					<< "       command_no := " << index
					<< ";\n";

				// only print out qualified if a data type
				// actually existed (not just a package of
				// related functions).  Check by determining
				// whether or not a private type was ever found
				// and the default name of "UNDEFINED" was
				// replaced by the real private type name
				if (strcmp(opr_ptr->PrivateType,"UNDEFINED")!=0)
					// qualified OPERATION name
					fout << "    elsif (TokenList(1).str(1..TokenList(1).size) = \""
						<< opr_ptr->PrivateType
						<< '.'<< opr_ptr->OprName
						<< "\") then\n"
						<< "       command_no := "
						<< index << ";\n";
			}
		}
	}

	fout << "    end if;\n";

	// take action according to command number
	CaseStatement(fout, OperationList);

	fout << "  end loop;\n";
}


//---------------------------------------------------
// Writes out variable initializations to driver file
//---------------------------------------------------
void Initialization(ofstream &fout, LinkedList &TypeList) {
	int i;

	fout << "\t\t\t-- Initialization\n";
	// initialize BUILT-IN type list
	fout << "  TotalBuiltinTypes := " << TOTAL_BUILTINS << ";\n";
	for (i=1; i <= TOTAL_BUILTINS; i++) {
		fout << "  BuiltinTypeList(" << i << ").Size := "
			<< strlen(BuiltinTypes[i]) << ";\n";
		fout << "  BuiltinTypeList(" << i << ").TypeName(1.."
			<< strlen(BuiltinTypes[i]) << ") := \"" <<
			BuiltinTypes[i] << "\";\n";
	}

	fout << endl;
	for (i=1; i <= TOTAL_BUILTINS; i++)  // init `NumBuiltinObjects?'
		fout << "  NumBuiltinObjects" << i << " := 0;\n";

	int TotalTypes = TypeList.TotalNodes(); // initialize `TotalTypes'
	fout << "\n  TotalTypes := " << TotalTypes << ";\n";

	TypeNode *p;
	TypeList.Start();                            // initialize `TypeList'
	for (i=1; i <= TotalTypes; i++) {
		p = (TypeNode *)TypeList.NextNode();
		fout << "  TypeList(" << i << ").Size := " <<
			strlen(p->TypeName) << ";\n";
		fout << "  TypeList(" << i << ").TypeName(1.."
			<< strlen(p->TypeName) << ") := \"" << p->TypeName
			<< "\";\n";
	}

	fout << endl;
	fout << "BuiltInObjects1(1) := 0;\n";
	fout << "BuiltInObjects2(1) := 0.0;\n";
	fout << "BuiltInObjects3(1) := true;\n";
	fout << "BuiltInObjects4(1) := ' ';\n";
	fout << "BuiltInObjects5(1) := 0;\n";
	fout << "BuiltInObjects6(1) := 1;\n";

	fout << endl;
	fout << "in_name(1) := ' ';" << endl;
	fout << "index := 0;" << endl;
	fout << "name_size := 0;" << endl;
	fout << "I := 1;" << endl;
	fout << "AToken.size := 0;" << endl;
	
	fout << endl;
	for (i=1; i <= TotalTypes; i++) {     // initialize `NumObjects?'
		fout << "  NumObjects" << i << " := 0;\n";
	}


	
	if (TotalTypes > 0) {			// initialize HISTORY LISTS
		fout << "\n  for I in 1.." << MAX_OBJECTS << " loop\n";
		for (int i=1; i <= TotalTypes; i++)
			fout << "    DRGEN.INIT_LIST (ObjectHistory"
				<< i << "(I));\n";
		fout << "  end loop;\n\n";
	}
}


//------------------------------------------------------------------------
// Writes out the case statement to driver file. This statement determines
// the actions to be taken.
//------------------------------------------------------------------------
void CaseStatement(ofstream &fout, LinkedList &OperationList) {

	fout << "\n    case command_no is\n";

	// case 1: TYPES
	// show all available private TYPES
	fout << "      when 1  =>                 -- keyword TYPES\n";
	fout << "          begin\n";
	fout << "            for I in 1..TotalTypes loop\n";
	fout << "              DRGEN.put(\"      \");\n";
	fout << "              DRGEN.put_line(TypeList(I).TypeName(1..TypeList(I).size));\n";
	fout << "            end loop;\n";
	fout << "          end;\n\n";

	// case 2: TREE.     show the TYPE tree
	fout << "      when 2  =>  TREE;               -- keyword TREE\n\n";

	// case 3: OPS <Type name>
	// show all available operations of specified Type
	fout << "      when 3  =>  OPERATIONS;             -- keyword OPS\n\n";

	// case 4: OBJECTS <Type name>
	// show all available OBJECT names for the specified TYPE
	fout << "      when 4  =>  OBJECTS;         -- OBJECTS <Type name> \n";

	// case 5: HISTORY
	fout << "      when 5  =>  HISTORY;             -- keyword HISTORY\n\n";

	// case 6 and 7: HELP or ?
	fout << "      when 6 | 7  =>                 -- keyword HELP or ?\n"
		<< "          DRGEN.put_line(\"      INTERPRETER  COMMANDS\");\n"
		<< "          DRGEN.put_line(\"      -----------  --------\");\n"
		<< "          DRGEN.put_line(\"      types\");\n"
		<< "          DRGEN.put_line(\"      tree\");\n"
		<< "          DRGEN.put_line(\"      ops <Type>\");\n"
		<< "          DRGEN.put_line(\"      objects <Type>\");\n"
		<< "          DRGEN.put_line(\"      history [<Type>.]<Object>\");\n"
		<< "          DRGEN.put_line(\"      help | ?\");\n"
		<< "          DRGEN.put_line(\"      new <Type>\");\n"
		<< "          DRGEN.put_line(\"      exit | quit\");\n"
		<< "          DRGEN.new_line;\n\n";

	// case 6 and 7: HELP or ?
	fout << "      when 8  =>  NEW_OBJECT;            -- new <Type>\n";

	// case 9 and 10 : EXIT
	fout << "      when 9 | 10  =>  EXIT;             -- EXIT the loop\n";

	// case 11 : blank line (hit an enter only)
	fout << "      when 11  =>  null;            -- ignore an <ENTER>\n\n";


	// cases for actual OPERATIONS
	// execute the corresponding nested PROCEDURES
	OprNode *opr_ptr;
	OperationList.Start();
	int TotalOprs = OperationList.TotalNodes();
	for (int i=1, index=TOTAL_KEYWORDS+1; i <= TotalOprs; i++, index++) {
		opr_ptr = (OprNode *)OperationList.NextNode();
		if (opr_ptr->Processed() == 1)
			if (OverloadedOperator(opr_ptr->OprName))
				fout << "      when " << index << " =>  "
					<< opr_ptr->PkgName << '_'
					<< FixOverloadedName(opr_ptr->OprName)
					<< ";\n";
			else
				fout << "      when " << index << " =>  "
					<< opr_ptr->PkgName << '_'
					<< opr_ptr->OprName << ";\n";
	}

	fout << "      when others =>     \n"
		<< "          DRGEN.put_line(\"      unrecognized command!\");\n";
	fout << "    end case;\n";
}


































