
//----------------------------------------------------------------------------
// 
// procs.C
// 
// Used in `ADT INTERPRETER PROJECT'
// Contains functions which declare nested procedures in the driver program
//
// Items contained in this file:
//
//	ProcedureGetTypeIndex
//	ProcedureGetBuiltinTypeIndex
//	ProcedureGetObjectIndex
//	ProcedureGetBuiltinObjectIndex
//	ProcedureDetermineParameter
//	ProcedureOPERATIONS
//	ProcedureOBJECTS
//	ProcedureHISTORY
//	ProcedureNEW
//	ProcedureTREE
//	DetermineUserOperation
//	GenerateUserOperation
//	NestedProcedureVariables
//	PreCallBodyPart
//	CallBodyPart
//	PostCallBodyPart
// 
//----------------------------------------------------------------------------


#include "drgen.h"



//---------------------------------------------------------------
// Generates the Ada function `GetTypeIndex()'. Given a type name
// this function returns its index in type list.
//---------------------------------------------------------------
void ProcedureGetTypeIndex(ofstream &fout) {
	fout << endl;
	fout << "  function GetTypeIndex(TypeName: in string; size: in natural)"
		<<  " return integer is\n";
	fout << "    TypeIndex, I: integer := 0;\n" << "  begin\n";
	fout << "    for I in 1..TotalTypes loop\n"
		<< "      if (TypeName(1..size) = "
		<<          "TypeList(I).TypeName(1..TypeList(I).size)) then\n"
		<< "        TypeIndex := I;\n"
		<< "        exit;\n"
		<< "      end if;\n"
		<< "    end loop;\n\n";

	fout << "    if TypeIndex = 0 then\n"
		<< "      DRGEN.put(\"      Type `\");\n"
		<< "      DRGEN.put(TypeName(1..size));\n"
		<< "      DRGEN.put_line(\"' does not exist!\");\n"
		<< "    end if;\n\n";

	fout << "    return(TypeIndex);\n"
		<< "  end GetTypeIndex;\n\n\n";
}


//---------------------------------------------------------------------
// Generates the Ada function `GetBuiltinTypeIndex()'. Given a built-in
// type name this function returns its index in type list.
//---------------------------------------------------------------------
void ProcedureGetBuiltinTypeIndex(ofstream &fout) {
	fout << endl;
	fout << "  function GetBuiltinTypeIndex(TypeName: in string; size: in natural)"
		<<  " return integer is\n";
	fout << "    TypeIndex, I: integer := 0;\n" << "  begin\n";
	fout << "    for I in 1..TotalBuiltinTypes loop\n"
		<< "      if (TypeName(1..size) = "
		<< "BuiltinTypeList(I).TypeName(1..BuiltinTypeList(I).size)) then\n"
		<< "        TypeIndex := I;\n"
		<< "        exit;\n"
		<< "      end if;\n"
		<< "    end loop;\n\n";

	fout << "    return(TypeIndex);\n"
		<< "  end GetBuiltinTypeIndex;\n\n\n";
}


//--------------------------------------------------------------------
// Generates the Ada function `GetObjectIndex()'. Given an object name
// and its type, this function returns its index in object list.
//--------------------------------------------------------------------
void ProcedureGetObjectIndex(ofstream &fout, LinkedList &TypeList) {
       // declare the function GetObjectIndex()
       // no. of. cases = no. of. types
	fout << endl;
	fout << "  function GetObjectIndex(ObjectName: in string; size: in natural;\n"
		<< "\t\t     TypeIndex, msg: in integer) return integer is\n";
	fout << "    ObjIndex, I: integer := 0;\n"
		<< "  begin              -- No. of. cases = No. of. types\n"
		<< "    case TypeIndex is\n";

	int TotalTypes = TypeList.TotalNodes();
	for (int i=1; i <= TotalTypes; i++) {
		fout << "      when " << i << " =>\n"
			<< "        for I in 1..NumObjects" << i << " loop\n"
			<< "          if (ObjectNames" << i << "(I).str"
			<< "(1..ObjectNames" << i << "(I).size) = \n"
			<< "                      ObjectName(1..size)) then\n"
			<< "            ObjIndex := I;\n"
			<< "          end if;\n"
			<< "        end loop;\n";
	}
	fout << "      when others => null;\n"
		<< "    end case;\n\n";

	fout << "    if (ObjIndex = 0) and (msg = 1) then\n"
		<< "      DRGEN.put(\"      OBJECT `\");\n"
		<< "      DRGEN.put(ObjectName(1..size));\n"
		<< "      DRGEN.put(\"' of type \");\n"
		<< "      DRGEN.put(TypeList(TypeIndex).TypeName(1.."
		<<              "TypeList(TypeIndex).size));\n"
		<< "      DRGEN.put_line(\" does not exist!\");\n"
		<< "    end if;\n"
		<< "    return(ObjIndex);\n"
		<< "  end GetObjectIndex;\n\n\n";
}


//----------------------------------------------------------------------
// Generates the Ada function `GetBuiltinObjectIndex()'. Given an object
// name and its type, this function returns its index in object list.
//----------------------------------------------------------------------
void ProcedureGetBuiltinObjectIndex(ofstream &fout) {
	// declare the function GetBuiltinObjectIndex()
	// no. of. cases = no. of. built-in types
	fout << endl;
	fout << "  function GetBuiltinObjectIndex(ObjectName: in string; size: in natural;\n"
		<< "\t\t     TypeIndex, msg: in integer) return integer is\n";
	fout << "    ObjIndex, I: integer := 0;\n"
		<< "  begin         -- No. of. cases = No. of. built-in types\n"
		<< "    case TypeIndex is\n";

	for (int i=1; i <= TOTAL_BUILTINS; i++) {
		fout << "      when " << i << " =>\n"
			<< "      for I in 1..NumBuiltinObjects" <<i<< " loop\n"
			<< "          if (BuiltinObjectNames" << i << "(I).str"
			<< "(1..BuiltinObjectNames" << i << "(I).size) = \n"
			<< "                      ObjectName(1..size)) then\n"
			<< "            ObjIndex := I;\n"
			<< "          end if;\n"
			<< "        end loop;\n";
	}

	fout << "      when others => null;\n"
		<< "    end case;\n\n";

	fout << "    if (ObjIndex = 0) and (msg = 1) then\n"
		<< "      DRGEN.put(\"      Variable `\");\n"
		<< "      DRGEN.put(ObjectName(1..size));\n"
		<< "      DRGEN.put(\"' of type \");\n"
		<< "      DRGEN.put(BuiltinTypeList(TypeIndex).TypeName(1.."
		<<            "BuiltinTypeList(TypeIndex).size));\n"
		<< "      DRGEN.put_line(\" does not exist!\");\n"
		<< "    end if;\n"
		<< "    return(ObjIndex);\n"
		<< "  end GetBuiltinObjectIndex;\n\n\n";
}


//--------------------------------------------------------
// Generates the procedures `Param_is_{BASIC-TYPE}'. They is used by the
// driver when resolving an overloaded operation name (which instantiation
// should be invoked
//--------------------------------------------------------
void ProcedureDetermineParameter(ofstream &fout) {
	fout << "  -- returns TRUE if the token is a valid integer (either a\n";
	fout << "  -- constant or an integer variable), returns FALSE otherwise\n";
	fout << "  function param_is_integer(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_integer(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("INTEGER") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_integer;\n\n";

	fout << "  -- returns TRUE if the token is a valid float (either a\n";
	fout << "  -- constant or an float variable), returns FALSE otherwise\n";
	fout << "  function param_is_float(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_float(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("FLOAT") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_float;\n";

	fout << "  -- returns TRUE if the token is a valid boolean (either a\n";
	fout << "  -- constant or an boolean variable), returns FALSE otherwise\n";
	fout << "  function param_is_boolean(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_boolean(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("BOOLEAN") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_boolean;\n";

	fout << "  -- returns TRUE if the token is a valid character (either a\n";
	fout << "  -- constant or an character variable), returns FALSE otherwise\n";
	fout << "  function param_is_character(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_character(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("CHARACTER") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_character;\n";

	fout << "  -- returns TRUE if the token is a valid natural (either a\n";
	fout << "  -- constant or an natural variable), returns FALSE otherwise\n";
	fout << "  function param_is_natural(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_integer(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("NATURAL") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_natural;\n";

	fout << "  -- returns TRUE if the token is a valid positive (either a\n";
	fout << "  -- constant or an positive variable), returns FALSE otherwise\n";
	fout << "  function param_is_positive(in_str: in string; size: in natural)\n";
	fout << "	return boolean is\n";
	fout << "	val : integer;\n";
	fout << "  begin\n";
	fout << "	if DRGEN.is_integer(in_str(1..size), size) then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "	val := GetBuiltinObjectIndex(in_str(1..size), size, "
		<< GetBuiltinTypeIndex("POSITIVE") << ", 0);\n";
	fout << "	if val /= 0 then\n";
	fout << "		return TRUE;\n";
	fout << "	end if;\n";
	fout << "       return FALSE;\n";
	fout << "  end param_is_positive;\n";
}

//--------------------------------------------------------
// Generates the procedure `OPERATIONS'. It is used by the
// driver to show available operations for each TYPE.
//--------------------------------------------------------
void ProcedureOPERATIONS(ofstream &fout, LinkedList &OperationList) {
	OprNode *opr_ptr;
	ParamNode *par_ptr;
	int TotalOprs, TotalParams, i, j;
	char CurrentType[TYPENAME_LEN] = "";
	char CurrentPkg[PKGNAME_LEN] = "";

	// procedure to handle command  `OPS <Type name>'
	fout << "\n  Procedure OPERATIONS is\n"
		<< "    BuiltinIndex: integer := 0;\n"
		<< "  begin\n";
	fout << "    BuiltinIndex := GetBuiltinTypeIndex(TokenList(2).str(1..TokenList(2).size),\n"
		<< "                           TokenList(2).size);\n"
		<< "    if BuiltinIndex /= 0 then\n"
		<< "      return;\n"
		<< "    end if;\n\n";

	TotalOprs = OperationList.TotalNodes();

	if (TotalOprs > 0) {

		OperationList.Start();    // determine the TYPE involved,
					  // start the IF STATEMENT
		opr_ptr = (OprNode *)OperationList.NextNode();
		strcpy(CurrentType, opr_ptr->PrivateType);
		fout << "    if (TokenList(2).str(1..TokenList(2).size) = \""
			<< CurrentType << "\") then\n";

		OperationList.Start();
		for (i=1; i <=TotalOprs; i++) {
			opr_ptr = (OprNode *)OperationList.NextNode();
			if (strcmp(CurrentType, opr_ptr->PrivateType) !=0) {
				strcpy(CurrentType, opr_ptr->PrivateType);
				fout << "    elsif (TokenList(2).str(1..TokenList(2).size) = \""
					<< CurrentType << "\") then\n";
			}

			// write operation name
			fout << "      DRGEN.put_line(\"      "
					<< opr_ptr->OprName << " (";

			// write parameter modes & types
			opr_ptr -> ParamList.Start();
			TotalParams = opr_ptr -> ParamList.TotalNodes();
			for (j=1; j <= TotalParams; j++) {
				par_ptr = (ParamNode *)
						opr_ptr -> ParamList.NextNode();
				fout << par_ptr->Mode << ' ' << par_ptr->Type;

				if (j < TotalParams)
					fout << ", ";
				else
					fout << ')';
			}

			// if function, write return type
			if (opr_ptr->RetType[0] != '\0')
				fout << " returns " << opr_ptr->RetType;

			fout << ";\");\n";
		}


		// List operation names by packages

		OperationList.Start();    // determine the TYPE involved,
					  // start the IF STATEMENT
		opr_ptr = (OprNode *)OperationList.NextNode();
		strcpy(CurrentPkg, opr_ptr->PkgName);
		fout << "   elsif (TokenList(2).str(1..TokenList(2).size) = \""
			<< CurrentPkg << "\") then\n";

		OperationList.Start();
		for (i=1; i <=TotalOprs; i++) {
			opr_ptr = (OprNode *)OperationList.NextNode();
			if (strcmp(CurrentPkg, opr_ptr->PkgName) !=0) {
				strcpy(CurrentPkg, opr_ptr->PkgName);
				fout << "    elsif (TokenList(2).str(1..TokenList(2).size) = \""
					<< CurrentPkg << "\") then\n";
			}

			// write operation name
			fout << "      DRGEN.put_line(\"      "
					<< opr_ptr->OprName << " (";

			// write parameter modes & types
			opr_ptr -> ParamList.Start();
			TotalParams = opr_ptr -> ParamList.TotalNodes();
			for (j=1; j <= TotalParams; j++) {
				par_ptr = (ParamNode *)
						opr_ptr -> ParamList.NextNode();
				fout << par_ptr->Mode << ' ' << par_ptr->Type;

				if (j < TotalParams)
					fout << ", ";
				else
					fout << ')';
			}

			// if function, write return type
			if (opr_ptr->RetType[0] != '\0')
				fout << " returns " << opr_ptr->RetType;

			fout << ";\");\n";
		}


		fout << "    else\n"                  // end if statement
			<< "      DRGEN.put(\"      Type `\");\n"
			<< "      DRGEN.put(TokenList(2).str(1..TokenList(2).size));\n"
			<< "      DRGEN.put_line(\"' does not exist!\");\n"
			<< "    end if;\n";
	}


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


//----------------------------------------------------------
// Generates the procedure `OBJECTS'. It displays OBJECTS
// of the specified TYPE
//----------------------------------------------------------
void ProcedureOBJECTS(ofstream &fout, LinkedList &TypeList) {
	int i;
	// procedure to handle command  `OBJECTS <Type name>'
	fout << "\n  Procedure OBJECTS is\n";
	fout << "    Index: integer := 0;\n"
		<< "    BuiltinIndex: integer := 0;\n";

	fout << "  begin\n";
	// find index in either BuiltinTypeList or TypeList
	fout << "    BuiltinIndex := GetBuiltinTypeIndex(TokenList(2).str(1..TokenList(2).size),\n"
		<< "                           TokenList(2).size);\n"
		<< "    if BuiltinIndex = 0 then\n"
		<< "      Index := GetTypeIndex(TokenList(2).str(1..TokenList(2).size),\n"
		<< "                           TokenList(2).size);\n"
		<< "    end if;\n\n";

	// show a list of all available OBJECTS of this TYPE
	fout << "    case BuiltinIndex is\n";
	for (i=1; i <= TOTAL_BUILTINS; i++) {
		fout << "      when " << i << " =>\n"
			<< "         for I in 1..NumBuiltinObjects" << i << " loop\n"
			<< "           DRGEN.put(\"      \");\n"
			<< "           DRGEN.put_line(BuiltinObjectNames"<< i <<"(I).str"
			<< "(1..BuiltinObjectNames" << i << "(I).size));\n"
			<< "         end loop;\n";
	}

	fout << "      when others => null;\n";
	fout << "    end case;\n\n";

	fout << "    case Index is\n";
	int TotalTypes = TypeList.TotalNodes();
	for (i=1; i <= TotalTypes; i++) {
		fout << "      when " << i << " =>\n"
			<< "         for I in 1..NumObjects" << i << " loop\n"
			<< "           DRGEN.put(\"      \");\n"
			<< "           DRGEN.put_line(ObjectNames"<< i <<"(I).str"
			<< "(1..ObjectNames" << i << "(I).size));\n"
			<< "         end loop;\n";
	}

	fout << "      when others => null;\n";
	fout << "    end case;\n\n";
	fout << "  end OBJECTS;\n\n\n";
}


//------------------------------------------------------------
// Generates the procedure `HISTORY'. It displays history list
// of the specified OBJECT
//------------------------------------------------------------
void ProcedureHISTORY(ofstream &fout, LinkedList &TypeList) {
	// procedure to handle command  `OPS <Type name>'
	fout << "\n  Procedure HISTORY is\n";
	fout << "    Qualified: Boolean;\n"
		<< "    TypeName, ObjName: string(1..40);\n"
		<< "    TypeIndex: integer := 0;\n"
		<< "    BuiltinTypeIndex: integer := 0;\n"
		<< "    ObjIndex: integer := 0;\n"
		<< "    BuiltinObjIndex: integer := 0;\n"
		<< "    ObjSize, TypeSize: natural;\n";

	fout << "  begin\n";

	// find out if object name is qualified or not
	fout << "    Qualified := FALSE;   -- find out if object is qualified\n"
		<< "    for I in 1..TokenList(2).size loop\n"
		<< "      if (TokenList(2).str(I) = '.') then\n"
		<< "        TypeSize := I-1;\n"
		<< "        TypeName(1..TypeSize) := TokenList(2).str(1..TypeSize);\n"
		<< "        ObjSize := TokenList(2).size - I;\n"
		<< "        ObjName(1..ObjSize) := "
		<<                 "TokenList(2).str(I+1..TokenList(2).size);\n"
		<< "        Qualified := TRUE;\n"
		<< "        exit;\n"
		<< "      end if;\n"
		<< "    end loop;\n\n";

	// find out type index and object index corresponding to object name
	fout << "    if Qualified then        -- get type and object indices\n"
		<< "      BuiltinTypeIndex := GetBuiltinTypeIndex("
		<<                       "TypeName(1..TypeSize), TypeSize);\n"
		<< "      if BuiltinTypeIndex /= 0 then\n"
		<< "        DRGEN.put_line(\"      History of built-in types is not maintained\");\n"
		<< "        return;\n"
		<< "      end if;\n\n"
		<< "      TypeIndex := GetTypeIndex(TypeName(1..TypeSize), TypeSize);\n"
		<< "      ObjIndex := GetObjectIndex(ObjName(1..ObjSize), ObjSize, "
		<<                                      "TypeIndex, 0);\n"
		<< "    else     -- else get the first available object index\n"
		<< "      for I in 1..TotalBuiltinTypes loop\n"
		<< "        BuiltinObjIndex := GetBuiltinObjectIndex(TokenList(2).str"
		<<                                  "(1..TokenList(2).size),\n"
		<< "                                    TokenList(2).size, I, 0);\n"
		<< "        if (BuiltinObjIndex /= 0) then\n"
		<< "          DRGEN.put_line(\"      History of built-in types is not maintained\");\n"
		<< "          return;\n"
		<< "        end if;\n"
		<< "      end loop;\n\n"

		<< "      for I in 1..TotalTypes loop\n"
		<< "        ObjIndex := GetObjectIndex(TokenList(2).str"
		<<                                   "(1..TokenList(2).size),\n"
		<< "                            TokenList(2).size, I, 0);\n"
		<< "        if (ObjIndex /= 0) then\n"
		<< "          TypeIndex := I;\n"
		<< "          exit;\n"
		<< "        end if;\n"
		<< "      end loop;\n"
		<< "    end if;\n\n";

	// this check takes care of `type index' also
	fout << "    if ObjIndex = 0 then\n"
		<< "      DRGEN.put(\"      Object `\");\n"
		<< "      DRGEN.put(TokenList(2).str(1..TokenList(2).size));\n"
		<< "      DRGEN.put_line(\"' does not exist!\");\n"
		<< "      return;\n"
		<< "    end if;\n\n";

	// use `type index' and `object index' to display required history list
	fout << "    case TypeIndex is\n";

	int TotalTypes = TypeList.TotalNodes();
	for (int i=1; i <= TotalTypes; i++)
		fout << "      when " << i << "  =>\n"
			<< "          DRGEN.DISPLAY(ObjectHistory"
			<< i << "(ObjIndex));\n";

	fout << "      when others  => null;\n"
		<< "    end case;\n";
	fout << "  end HISTORY;\n\n\n";
}


//-------------------------------------------------------------
// Generates the procedure `NEW'. It instantiates a NEW object
//-------------------------------------------------------------
void ProcedureNEW(ofstream &fout, LinkedList &TypeList) {
	int i;
	int TotalTypes = TypeList.TotalNodes();

	fout << "\n  Procedure NEW_OBJECT is\n"
		<< "    TypeIndex, ObjIndex: integer;\n"
		<< "    BuiltinTypeIndex: integer;\n"
		<< "    in_name: string(1..40);\n"
		<< "    name_size: natural;\n"
		<< "  begin\n";

	// find index of <Type> in either BuiltinTypeList or TypeList
	fout << "    BuiltinTypeIndex := GetBuiltinTypeIndex("
		<<               "TokenList(2).str(1..TokenList(2).size),\n"
		<< "                                        TokenList(2).size);\n"
		<< "    if BuiltinTypeIndex = 0 then\n"
		<< "      TypeIndex := GetTypeIndex("
		<<                  "TokenList(2).str(1..TokenList(2).size),\n"
		<< "                                        TokenList(2).size);\n"
		<< "    end if;\n\n";

	fout << "    if BuiltinTypeIndex =0 and TypeIndex = 0 then   -- Type does not exist\n"
		<< "      DRGEN.put_line(\"          (or is not supported"
		<<                  " in the case of built-in types)\");\n"
		<< "      return;\n"
		<< "    end if;\n\n";

	// if specified TYPE exists, get a name for OBJECT
	fout << "    DRGEN.put(\"      Enter a name: \");  -- get OBJECT name\n"
		<< "    DRGEN.get_line(in_name, name_size);\n"
		<< "    DRGEN.uppercase(in_name, name_size);\n\n";

	// prompt user if OBJECT already exists
	fout << "         -- check all object arrays to see if OBJECT exists\n"
		<< "         -- prompt if OBJECT exists\n";
	fout << "    for I in 1..TotalTypes loop\n"
		<< "      ObjIndex := GetObjectIndex(in_name, name_size, I, 0);\n"
		<< "      if (ObjIndex /= 0) then\n"
		<< "         DRGEN.put(\"      Object already exists!"
		<<                " (defined as a \");\n"
		<< "         DRGEN.put(TypeList(I).TypeName(1..TypeList(I).size));\n"
		<< "         DRGEN.put_line(\")\");\n"
		<< "        return;\n"
		<< "      end if;\n"
		<< "    end loop;\n\n";

	fout << "    for I in 1..TotalBuiltinTypes loop\n"
		<< "      ObjIndex := GetBuiltinObjectIndex(in_name, name_size, I, 0);\n"
		<< "      if (ObjIndex /= 0) then\n"
		<< "        DRGEN.put_line(\"      Object already exists!"
		<<                " (defined as a \");\n"
		<< "         DRGEN.put(BuiltinTypeList(I).TypeName("
		<<                "1..BuiltinTypeList(I).size));\n"
		<< "         DRGEN.put_line(\")\");\n"
		<< "        return;\n"
		<< "      end if;\n"
		<< "    end loop;\n\n";

	// if OBJECT doesn't exist add to relevant array and update NumObjects
	fout << "    case BuiltinTypeIndex is    -- OBJECT doesn't exist, add to list\n";
	for (i=1; i <= TOTAL_BUILTINS; i++) {
		fout << "      when " << i << " =>\n"
			<< "        NumBuiltinObjects" << i 
			<< " := NumBuiltinObjects" << i << " + 1;\n"
			<< "        BuiltinObjectNames" << i 
			<< "(NumBuiltinObjects" << i << ").str"
			<< "(1..name_size)\n"
			<< "\t\t    := in_name(1..name_size);\n"
			<< "        BuiltinObjectNames" << i 
			<< "(NumBuiltinObjects" << i << ").size"
			<< " := name_size;\n";
	}
	fout << "      when others =>  null;\n"
		<< "    end case;\n\n";

	fout << "    case TypeIndex is    -- OBJECT doesn't exist, add to list\n";
	for (i=1; i <= TotalTypes; i++) {
		fout << "      when " << i << " =>\n"
			<< "        NumObjects" << i << " := NumObjects" 
			<< i << " + 1;\n"
			<< "        ObjectNames" << i << "(NumObjects" 
			<< i << ").str"
			<< "(1..name_size)\n"
			<< "\t\t    := in_name(1..name_size);\n"
			<< "        ObjectNames" << i << "(NumObjects" 
			<< i << ").size"
			<< " := name_size;\n";
	}
	fout << "      when others =>  null;\n"
		<< "    end case;\n";

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


//----------------------------------------------------------------
// Generates the procedure `TREE'. It displays the dependency tree
// of the available TYPES.
//----------------------------------------------------------------
void ProcedureTREE(ofstream &fout, LinkedList &TypeList) {
	// procedure to handle command  `TREE'
	fout << "\n  Procedure TREE is\n";
	fout << "  begin\n";

	TypeNode *typ_ptr;
	ParentNode *prt_ptr;
	int j, TotalParents;
	int no_parent = 1;

	// for all available TYPES
	int TotalTypes = TypeList.TotalNodes();
	TypeList.Start();
	for (int i=1; i <= TotalTypes; i++) {
		typ_ptr = (TypeNode *)TypeList.NextNode();

		typ_ptr -> ParentList.Start();   // write down all parent TYPES
		TotalParents = typ_ptr -> ParentList.TotalNodes();
		for (j=1; j <= TotalParents; j++) {
			no_parent = 0;
			prt_ptr = (ParentNode *)typ_ptr->ParentList.NextNode();
			fout << "    DRGEN.put_line(\"      " << typ_ptr -> TypeName
				<< "   depends on   "  << prt_ptr -> TypeName
				<< "\");\n";
		}
	}

	if (no_parent) fout << "    null;\n";
	fout << "  end TREE;\n\n\n";
}



//--------------------------------------------------------------
// The operation has been overloaded (multiple definitions of it exist).
// This procedure uses the number of parameters passed to it (plus the types
// of each parameter to determine which instantiation of the operation
// the user wishes to invoke.
//--------------------------------------------------------------
void DetermineUserOperation(ofstream &fout, OprNode *opr_ptr, int num_overload,
			OprNode *overload_list[], LinkedList &TypeList) {

	int i, j;
	OprNode *next;
	char name[OPRNAME_LEN+2];
	int param_histogram[MAX_TOKENS];

	// for each number of parameters, determine the number of operation
	// instantiations that take that number of parameters
	for (j=0; j<MAX_TOKENS; j++)
		param_histogram[j] = 0;
	for (j=0; j<=num_overload; j++) {
		if (j==0)
			param_histogram[opr_ptr->ParameterCount]++;
		else {
			next = overload_list[j-1];
			param_histogram[next->ParameterCount]++;
		}
	}
	// output our results (for debugging purposes only)
	// for (j=0; j<MAX_TOKENS; j++)
	// 	if (param_histogram[j] != 0) 
	// 		cout << "\t" << param_histogram[j]
	// 		 	<< " versions of " << opr_ptr->OprName
	// 		 	<< " with " << j << " parameters." << endl;
	// cout << endl;

	// determine base operation name
	strcpy(name, opr_ptr->OprName);

	// general procedure header
	fout << "  Procedure " << opr_ptr->PkgName << "_"
		<< FixOverloadedName(name) << " is\n"
		<< "        val : integer := 0;\n"
		<< "        Param_Match : boolean := true;\n"
		<< "        Processed : boolean := true;\n"
		<< "  begin\n";

	// for each version of the operation, build an if statement,
	// the number of tokens in the parsed test command will be equal to
	// the number of parameters required by the operation plus one (for the
	// operation name itself)
	for (i=0; i<MAX_TOKENS; i++) {
		if (param_histogram[i] == 1) {
			// only one operation defined with I params

			// print out all but the tail end of the operation name
			fout << "    if NumTokens = " << i+1 << " then\n"
				<< "       " << opr_ptr->PkgName << "_"
				<< FixOverloadedName(name) << "_";
			// find out what ending to put on this operation call
			//	   0 implies the original operation
			//	1..N implies one of the overloaded copies found
			//		later in the specification

			if (opr_ptr->ParameterCount == i)
				fout << "0;\n";
			else
				for (int j=1; j<=num_overload; j++) {
					next = overload_list[j-1];
					if ( next->ParameterCount == i )
						fout << j << ";\n";
				}

			// end the if statement
			fout << "    end if;\n\n";
		}

		if (param_histogram[i] > 1) {
			// more than operation defined with I params
			// cout << "\tmultiple versions exist with "
			// 	<< i << "parameters" << endl;

			// print out all but the tail end of the operation name
			fout << "    if NumTokens = " << i+1 << " then\n";
			fout << "       Processed := FALSE;\n";

			// find out what ending to put on this operation call
			//	   0 implies the original operation
			//	1..N implies one of the overloaded copies found
			//		later in the specification

			OprNode *tmp_ptr;
			ParamNode *p_ptr;
			for (int j=0; j<= num_overload; j++) {

				// find the next candidate operation
				if (j==0)
					tmp_ptr = opr_ptr;
				else
					tmp_ptr = overload_list[j-1];

				// first make sure that the version we grabbed
				// has the correct number of parameters (i)
				if (tmp_ptr->ParameterCount != i)
					continue;

				// check all parameters for this version of
				// the operation, we will initially assume
				// that this is the right one
				tmp_ptr->ParamList.Start();
				fout << "       Param_Match := not Processed;\n";

				for (int k=1; k<=i; k++) {
					p_ptr = (ParamNode *)
						tmp_ptr->ParamList.NextNode();
			
					if (BasicType(p_ptr->Type)) {
						fout << "       if Param_Match then\n"
							<< "          Param_Match := ";

						// match the specific
						// built-in type
						if (strcmp(p_ptr->Type,"INTEGER")==0)
							fout << "Param_Is_Integer(";
						else if (strcmp(p_ptr->Type,"FLOAT")==0)
							fout << "Param_Is_Float(";
						else if (strcmp(p_ptr->Type,"BOOLEAN")==0)
							fout << "Param_Is_Boolean(";
						else if (strcmp(p_ptr->Type,"NATURAL")==0)
							fout << "Param_Is_Natural(";
						else if (strcmp(p_ptr->Type,"POSITIVE")==0)
							fout << "Param_Is_Postive(";
						else
							fout << "Param_Is_Character(";

						// finish the IF statement
						fout << "TokenList(" << k+1
							<< ").str(1..TokenList("
							<< k+1 << ").size)"
							<< ",\n              "
							<< "TokenList(" << k+1
							<< ").size);\n"
							<< "       end if;\n";
					}
					else {  // this is a "user-defined" type
						fout << "       val := GetObjectIndex("
							<< "TokenList(" << k+1
							<< ").str(1..TokenList("
							<< k+1 << ").size)"
							<< ",\n              "
							<< "TokenList(" << k+1
							<< ").size, "
							<< GetTypeIndex(p_ptr->Type, TypeList)
							<< ", 0);\n";
						fout << "       if val = 0 then\n"
							<< "          "
							<< "Param_Match := FALSE;\n"
							<< "       end if;\n";
					}
				}
				// if this is still valid, then it is
				// the version that matched all parameters
				fout << "       if Param_Match then\n"
					<< "          "
					<< opr_ptr->PkgName << "_" 
					<< FixOverloadedName(name)
					<< "_" << j << ";\n"
					<< "          "
					<< "Processed := TRUE;\n"
					<< "       end if;\n\n";
			}
		// end the if statement
		fout << "    end if;\n\n";
		}
	}

	// general procedure footer
	fout << "  end " << opr_ptr->PkgName << "_"
		<< FixOverloadedName(name) << ";\n\n\n\n";

}



//--------------------------------------------------------------
// Generates a procedure for a user-defined operation on the data type
// Uses the operation name and the parameters
//--------------------------------------------------------------
void GenerateUserOperation(ofstream &fout, OprNode *opr_ptr, char *ending,
				LinkedList &TypeList) {

	// generate procedure header
	fout << "  Procedure " << opr_ptr->PkgName << '_'
			<< FixOverloadedName(opr_ptr->OprName)
			<< ending << " is\n";

	// write the reqd. variables
	NestedProcedureVariables(fout, opr_ptr);

       	fout << "  begin\n";

	// generate the body in three stages
	PreCallBodyPart(fout, opr_ptr, TypeList); // before OP call
	CallBodyPart(fout, opr_ptr, TypeList);    // OPERATION call
	PostCallBodyPart(fout, opr_ptr,TypeList); // after OP call

	// generate procedure footer
	fout << "  end " << opr_ptr->PkgName << '_'
		<< FixOverloadedName(opr_ptr->OprName)
		<< ending << ";\n\n\n\n";
}


//--------------------------------------------------------------
// Declares variables of a nested procedure.
// Uses names of formal parameters (of corresponding operation)
// to declare variables of BASIC TYPE.
// For user defined types, declares integer indexes -- I?
//--------------------------------------------------------------
void NestedProcedureVariables(ofstream &fout, OprNode *opr_ptr) {
	int TotalParams = opr_ptr -> ParamList.TotalNodes();
	ParamNode *par_ptr;

	opr_ptr -> ParamList.Start();
	for (int i=1; i <= TotalParams; i++) {
		par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();
		fout << "    I" << i << ": integer;\n";
		if (BasicType(par_ptr->Type) && strcmp(par_ptr->Mode, "IN")==0)
			fout << "    " << par_ptr->ParamName << ": "
				<< par_ptr->Type <<";\n";
	}

	// if function, get object for return value
	if (opr_ptr->RetType[0] != '\0')
		fout << "    IRet: integer;\n"
			<< "    in_name: string(1..40);\n"
			<< "    in_size: natural;\n";
}


//-----------------------------------------------------------------------
// Writes code to preprocess parameters before the actual OPERATION call.
// for e.g.  > PUSH(S1, 56);
//         a) the string "56" will be converted to an INTEGER and
//            assigned to the corresponding actual parameter.
//         b) Index of the object associated with "S1", will be found
//-----------------------------------------------------------------------
void PreCallBodyPart(ofstream &fout, OprNode *opr_ptr, LinkedList &TypeList) {
	int TotalParams = opr_ptr -> ParamList.TotalNodes();
	ParamNode *par_ptr;
	int TypeIndex, BasicTypeIndex;

	fout << "\t\t\t\t -- Pre call body part\n";

	opr_ptr -> ParamList.Start();
	for (int i=1; i <= TotalParams; i++) {
		par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();

		// if param is IN mode BUILT-IN type, then it may be a CONSTANT
		// if a CONSTANT, value is calculated & assigned to dummy var
		if (BasicType(par_ptr->Type) && strcmp(par_ptr->Mode,"IN")==0) {
			fout << "                        --BUILT-IN, IN parameter\n";
			if (strcmp(par_ptr->Type, "INTEGER") == 0 ||
				strcmp(par_ptr->Type, "NATURAL") == 0 ||
				strcmp(par_ptr->Type, "POSITIVE") == 0)
				fout << "    if DRGEN.is_integer(TokenList(" << i+1
					<< ").str(1..TokenList("
					<< i+1 << ").size), TokenList(" << i+1
					<< ").size) then\n" << "      "
					<< par_ptr->ParamName << " := "
					<< "DRGEN.atoi(TokenList(" << i+1
					<< ").str(1..TokenList("
					<< i+1 << ").size) , TokenList("
					<< i+1 << ").size);\n";
			else if (strcmp(par_ptr->Type, "BOOLEAN") == 0)
				fout << "    if DRGEN.is_boolean(TokenList("
					<< i+1
					<< ").str(1..TokenList("
					<< i+1 << ").size), TokenList(" << i+1
					<< ").size) then\n" << "      " <<
					par_ptr->ParamName << " := "
					<< "DRGEN.atob(TokenList(" << i+1
					<< ").str(1..TokenList(" << i+1
					<< ").size), TokenList(" << i+1
					<< ").size);\n";
			else if (strcmp(par_ptr->Type, "CHARACTER") == 0)
				fout << "    if DRGEN.is_character(TokenList("
					<< i+1
					<< ").str(1..TokenList("
					<< i+1 << ").size), TokenList(" << i+1
					<< ").size) then\n" << "      "
					<< par_ptr->ParamName << " := "
					<< "DRGEN.atoc(TokenList(" << i+1
					<< ").str(1..TokenList(" << i+1
					<< ").size), TokenList(" << i+1
					<< ").size);\n";
			else if (strcmp(par_ptr->Type, "FLOAT") == 0)
				fout << "    if DRGEN.is_float(TokenList("
					<< i+1
					<< ").str(1..TokenList(" << i+1
					<< ").size), TokenList(" << i+1
					<< ").size) then\n" << "      "
					<< par_ptr->ParamName << " := "
					<< "DRGEN.atof(TokenList(" << i+1
					<< ").str(1..TokenList(" << i+1
					<< ").size) , TokenList(" << i+1
					<< ").size);\n";
			fout << "    else\n";
		}

		// for IN, OUT, and IN-OUT mode BUILT-IN type parameters,
		// INDEX of OBJECT specified at command-line is calculated
		if (BasicType(par_ptr->Type)) {
			fout << "               --Index for BUILT-IN TYPE, parameter\n";
			BasicTypeIndex = GetBuiltinTypeIndex(par_ptr->Type);
			fout << "      I" << i
				<< " := GetBuiltinObjectIndex(TokenList("
				<<         i+1 << ").str(1..TokenList(" << i+1
				<< ").size),\n" <<            "\t\tTokenList("
				<< i+1 << ").size, "
				<<                          BasicTypeIndex
				<< ", 1);\n\n";

			fout << "      if (I" << i << " = 0) then\n"
				<< "        return;\n"
				<< "      end if;\n\n";
		}

		// if parameter is IN mode BUILT-IN type, ELSE branch is closed
		if (BasicType(par_ptr->Type) && strcmp(par_ptr->Mode,"IN")==0) {
			fout << "      " << par_ptr->ParamName
				<< " := BuiltinObjects"
				<<        BasicTypeIndex << "(I" << i << ");\n"
				<< "    end if;\n\n";
		}

		// for IN, OUT, and IN-OUT mode USER-DEFINED type parameters,
		// INDEX of OBJECT specified at command-line is calculated
		if (!BasicType(par_ptr->Type)) {
			fout << "            --Index of USER-DEFINED TYPE, parameter\n";
			TypeIndex = GetTypeIndex(par_ptr->Type, TypeList);

			fout << "    I" << i
				<< " := GetObjectIndex(TokenList(" << i+1
				<< ").str(1..TokenList(" << i+1
				<< ").size),\n           "
				<< "\t\tTokenList(" << i+1 << ").size, "
				<< TypeIndex << ", 1);\n\n";

			fout << "    if (I" << i << " = 0) then\n"
				<< "      return;\n"
				<< "    end if;\n\n";
		}
	}
}


//-------------------------------------------------------------------------
// Writes the actual call to an OPERATION, along with its actual parameters
//-------------------------------------------------------------------------
void CallBodyPart(ofstream &fout, OprNode *opr_ptr, LinkedList &TypeList) {
	int TotalParams = opr_ptr -> ParamList.TotalNodes();
	ParamNode *par_ptr;
	int TypeIndex, BuiltinTypeIndex;

	if (opr_ptr->RetType[0] != '\0') {  // if function, capture return value
		fout << "    DRGEN.put(\"      For return value, enter a name: \");\n"
			<< "    DRGEN.get_line(in_name, in_size);\n"
			<< "    DRGEN.uppercase(in_name, in_size);\n";

		if (BasicType(opr_ptr->RetType)) {  // basic return types
			BuiltinTypeIndex =
					GetBuiltinTypeIndex(opr_ptr->RetType);
			fout << "    IRet := GetBuiltinObjectIndex(in_name, in_size, "
				<<               BuiltinTypeIndex << ", 0);\n";
			fout << "    if IRet = 0 then\n"
				<< "      DRGEN.put(\"      Object specified "
				<< "does not exist, do you want to create it"
				<< " ? \");\n"
				<< "      DRGEN.get_line(answer_str,"
				<<                     " answer_size);\n"
				<< "      DRGEN.uppercase(answer_str,"
				<<                     " answer_size);\n"
				<< "      if answer_str(1) = 'Y' then\n"
				<< "         NumBuiltinObjects"
				<<               BuiltinTypeIndex
				<<               " := NumBuiltinObjects"
				<<               BuiltinTypeIndex << " + 1;\n"
				<< "         BuiltinObjectNames"
				<<               BuiltinTypeIndex
				<<               "(NumBuiltinObjects"
				<<                BuiltinTypeIndex
				<<                ").str(1..in_size)\n"
				<< "                := in_name(1..in_size);\n"
				<< "         BuiltinObjectNames"
				<<                BuiltinTypeIndex
				<<                "(NumBuiltinObjects"
				<<                BuiltinTypeIndex
				<<                ").size := in_size;\n"
				<< "         IRet := NumBuiltinObjects"
				<<                BuiltinTypeIndex << ";\n"
				<< "      else\n"
				<< "         return;\n"
				<< "      end if;\n"
				<< "    end if;\n";
			fout << "    BuiltinObjects" << BuiltinTypeIndex
				<< "(IRet) := ";
		}
		else {    // non-basic return types
			TypeIndex = GetTypeIndex(opr_ptr->RetType, TypeList);
			fout << "    IRet := GetObjectIndex(in_name, in_size, "
				<<                      TypeIndex << ", 0);\n";
			fout << "    if IRet = 0 then\n"
				<< "      DRGEN.put(\"     Object specified "
				<< "does not exist, do you want to create it"
				<< " ? \");\n"
				<< "      DRGEN.get_line(answer_str,"
				<<                     " answer_size);\n"
				<< "      DRGEN.uppercase(answer_str,"
				<<                     " answer_size);\n"
				<< "      if answer_str(1) = 'Y' then\n"
				<< "         NumObjects" << TypeIndex
				<<               " := NumObjects"
				<<               TypeIndex << " + 1;\n"
				<< "         ObjectNames" << TypeIndex
				<<               "(NumObjects" << TypeIndex
				<<                ").str(1..in_size)\n"
				<< "                := in_name(1..in_size);\n"
				<< "         ObjectNames" << TypeIndex
				<<                "(NumObjects" << TypeIndex
				<<                ").size := in_size;\n"
				<< "         IRet := NumObjects"
				<<                TypeIndex << ";\n"
				<< "      else\n"
				<< "         return;\n"
				<< "      end if;\n"
				<< "    end if;\n";
			fout << "    Objects" << TypeIndex << "(IRet) := ";
		}
	}

	if (OverloadedOperator(opr_ptr->OprName)) {
		// must generate operation call in form of "a + b"
		// or in the form of "+a" in the case of unary operators +,-

		// if unary operation, do the following
		if (TotalParams == 1) {
			// output operation name
			fout << "    " << opr_ptr->OprName;
			// get information on the one parameter
			opr_ptr -> ParamList.Start();
			par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();
			// write out the one parameter, 3 possible methods
			// for BUILT-IN TYPE, IN mode parameters, just put
			// name of the formal parameter
			if (BasicType(par_ptr->Type) &&
					strcmp(par_ptr->Mode, "IN")==0)
				fout << par_ptr->ParamName;

			// for BUILT-IN TYPE, OUT and IN-OUT mode
			// parameters, put the array name and index
			else if (BasicType(par_ptr->Type)) {
				BuiltinTypeIndex =
					GetBuiltinTypeIndex(par_ptr->Type);
				fout << "BuiltinObjects" << BuiltinTypeIndex
					<< "(I" << 1 << ')';
			}
			// for USER-DEFINED TYPE params, put array name/index
			else {
				TypeIndex=GetTypeIndex(par_ptr->Type,TypeList);
				fout << "Objects" << TypeIndex << "(I" << 1
					<< ')';
			}
		}
		else {
		//  binary operation, generate in the form of "a+b"
			// write first parameter
			opr_ptr -> ParamList.Start();
			par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();

			// for BUILT-IN TYPE, IN mode parameters, just put
			// name of the formal parameter
			if (BasicType(par_ptr->Type) &&
					strcmp(par_ptr->Mode, "IN")==0)
				fout << par_ptr->ParamName;

			// for BUILT-IN TYPE, OUT and IN-OUT mode
			// parameters, put the array name and index
			else if (BasicType(par_ptr->Type)) {
				BuiltinTypeIndex = GetBuiltinTypeIndex
								(par_ptr->Type);
				fout << "BuiltinObjects" << BuiltinTypeIndex
					<< "(I" << 1 << ')';
			}
			// for USER-DEFINED TYPE params, put array name/index
			else {
				TypeIndex=GetTypeIndex(par_ptr->Type,TypeList);
				fout << "Objects" << TypeIndex << "(I" << 1
					<< ')';
			}

			// write operation name
			fout << "    " << opr_ptr->OprName;

			// write second parameter
			par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();

			// for BUILT-IN TYPE, IN mode parameters, just put
			// name of the formal parameter
			if (BasicType(par_ptr->Type) &&
					strcmp(par_ptr->Mode, "IN")==0)
				fout << par_ptr->ParamName;

			// for BUILT-IN TYPE, OUT and IN-OUT mode
			// parameters, put the array name and index
			else if (BasicType(par_ptr->Type)) {
				BuiltinTypeIndex =
					GetBuiltinTypeIndex(par_ptr->Type);
				fout << "BuiltinObjects" << BuiltinTypeIndex
					<< "(I" << 2 << ')';
			}
			// for USER-DEFINED TYPE params, put array name & index
			else {
				TypeIndex=GetTypeIndex(par_ptr->Type,TypeList);
				fout << "Objects" << TypeIndex << "(I" << 2
					<< ')';
			}
		}
		fout << " ;           -- OPERATION CALL\n\n";
	}

	else {
		// must generate operation call in form of "op(p1, p2, .. pn)"

		// write operation name
		fout << "    " << opr_ptr->OprName;

		opr_ptr -> ParamList.Start();
		// only put the "(" in (p1,p2,...pn) if arguments exist
		if (TotalParams > 0) 
			fout << '(';
		for (int i=1; i <= TotalParams; i++) {
			par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();

			// for BUILT-IN TYPE, IN mode parameters, just put
			// name of the formal parameter
			if (BasicType(par_ptr->Type)
					&& strcmp(par_ptr->Mode, "IN")==0)
				fout << par_ptr->ParamName;

			// for BUILT-IN TYPE, OUT and IN-OUT mode
			// parameters, put the array name  and index
			else if (BasicType(par_ptr->Type)) {
				BuiltinTypeIndex =
					GetBuiltinTypeIndex(par_ptr->Type);
				fout << "BuiltinObjects" << BuiltinTypeIndex
					<< "(I" << i << ')';
			}
			// for USER-DEFINED TYPE parameters, put array
			// name and index
			else {
				TypeIndex=GetTypeIndex(par_ptr->Type,TypeList);
				fout << "Objects" << TypeIndex << "(I"
					<< i << ')';
			}

			// if not the last param, put a comma before next param
			if (i < TotalParams) fout << ", ";
		}
		if (TotalParams > 0) 
			fout << " );           -- OPERATION CALL\n\n";
		else
			fout << " ;           -- OPERATION CALL\n\n";
	}
}


//-----------------------------------------------------------------------
// Writes the cleanup chores required after an operation call
// i.e., displaying OUT mode basic parameter, updating history lists etc.
//-----------------------------------------------------------------------
void PostCallBodyPart(ofstream &fout, OprNode *opr_ptr, LinkedList &TypeList) {
	int TotalParams = opr_ptr -> ParamList.TotalNodes();
	ParamNode *par_ptr;
	int TypeIndex, BasicTypeIndex;

	fout << "\t\t\t\t -- Post call body part\n";

	opr_ptr -> ParamList.Start();
	for (int i=1; i <= TotalParams; i++) {
		par_ptr = (ParamNode *)opr_ptr -> ParamList.NextNode();

		// display `OUT' or `IN-OUT' BASIC TYPE parameters
		if (BasicType(par_ptr->Type) && strcmp(par_ptr->Mode,"IN")!=0) {

			BasicTypeIndex = GetBuiltinTypeIndex(par_ptr->Type);
			fout << "    DRGEN.put(\"      \");\n"
				<< "    DRGEN.put(TokenList(" << i+1
				<< ").str(1..TokenList("
				<< i+1 << ").size));\n"
				<< "    DRGEN.put(\" = \");\n";

			if (strcmp(par_ptr->Type, "BOOLEAN") != 0)
				fout << "    DRGEN.put_line(BuiltinObjects"
					<< BasicTypeIndex
					<< "(I" << i << "));\n";
			else
				// take care of BOOLEAN  `OUT' mode parameters
				fout << "\n    if BuiltinObjects"
					<< BasicTypeIndex << "(I"
					<<   i << ") then\n"
					<<   "      DRGEN.put_line(\"TRUE\");\n"
					<<   "    else\n"
					<<   "      DRGEN.put_line(\"FALSE\");\n"
					<<   "    end if;\n\n";
		}

		// update HISTORY lists for non-basic types. Insert the invoked
		// operation in the HISTORY LIST of every non-basic object.
		if (!BasicType(par_ptr->Type)) {
			TypeIndex = GetTypeIndex(par_ptr->Type, TypeList);

			fout << "    DRGEN.INSERT(ObjectHistory" << TypeIndex
				<< "(I" << i << "), in_command, size);\n";
		}
	}

	// if function and basic return type, display return val.
	if (opr_ptr->RetType[0] != '\0'  &&  BasicType(opr_ptr->RetType)) {
		BasicTypeIndex = GetBuiltinTypeIndex(opr_ptr->RetType);

		fout << "    DRGEN.put(\"      \");\n"
			<< "    DRGEN.put(in_name(1..in_size));\n"
			<< "    DRGEN.put(\" = \");\n";

		if (strcmp(opr_ptr->RetType, "BOOLEAN") == 0)
			fout << "    if BuiltinObjects" << BasicTypeIndex
				<< "(IRet) then \n"
				<< "      DRGEN.put_line(\"TRUE\");\n"
				<< "    else DRGEN.put_line(\"FALSE\");\n"
				<< "    end if;\n";
		else
			fout << "    DRGEN.put_line(BuiltinObjects"
				<< BasicTypeIndex << "(IRet));\n";
	}
}
