DIRECTORY
  TreesDefs USING [TreeNode, FreeTree],
  PrintingDefs USING [OutCode, PrintComments],
  PrintDclsDefs USING [],
  PrintExprDefs USING [MakeExpression],
  String USING [EqualString],
  Storage USING [AppendString, CopyString, FreeString, Free],
  SymbolTableDefs USING [EnterSymbol, SymbolType];
  

PrintDclsImpl: PROGRAM IMPORTS PrintingDefs, PrintExprDefs, String,
  Storage, TreesDefs, SymbolTableDefs
  EXPORTS PrintDclsDefs = {
  
  -- Global variable (saved from call to call)
  structName: LONG STRING ← "StructA";
  
    
  PrintFunctionHead: PUBLIC PROCEDURE [name: LONG STRING,
  	functionAttributes: LONG POINTER TO TreesDefs.TreeNode,
	pointerTo: BOOLEAN, nameList: LONG POINTER TO TreesDefs.TreeNode,
	argList: LONG POINTER TO TreesDefs.TreeNode] = {
	
    dataType: LONG STRING;
    symType: SymbolTableDefs.SymbolType;
    dcl, itemHead, n: LONG POINTER TO TreesDefs.TreeNode;
    
    PrintingDefs.OutCode[name, 0];
    IF name # NIL THEN Storage.FreeString[name];
    PrintingDefs.OutCode[": PROCEDURE ["L, 0];
    
    FOR n ← nameList, n.right WHILE n # NIL DO
        [dcl, itemHead] ← InDclList[n, argList];
        IF itemHead = NIL THEN {
	    -- enter symbol with blockHeader=TRUE so that the symbol
	    -- will belong to the block about to be entered.
	    SymbolTableDefs.EnterSymbol[n.string,
	            long, long, "INT"L, 0, TRUE];
	    PrintingDefs.OutCode[n.string, 0];
	    PrintingDefs.OutCode[": INT"L, 0]; }
	ELSE PrintOneDeclaration[dcl, 0, ""L, itemHead];
	IF n.right # NIL THEN PrintingDefs.OutCode[", "L, 0];
	ENDLOOP;
	
    IF pointerTo THEN {
        PrintingDefs.OutCode["] RETURNS [LONG POINTER TO "L, 0];
	[symType, dataType] ← GetAttributes[functionAttributes, 0];
	SymbolTableDefs.EnterSymbol[name, pointer, symType, dataType, 1];
	PrintingDefs.OutCode[dataType, 0];
	Storage.FreeString[dataType]; }
    ELSE IF functionAttributes # NIL THEN {
        PrintingDefs.OutCode["] RETURNS ["L, 0];
	[symType, dataType] ← GetAttributes[functionAttributes, 0];
	SymbolTableDefs.EnterSymbol[name, symType, symType, dataType, 0];
	PrintingDefs.OutCode[dataType, 0];
	Storage.FreeString[dataType]; };
	
    PrintingDefs.OutCode["] =\n"L, 0];
    TreesDefs.FreeTree[functionAttributes];
    TreesDefs.FreeTree[argList];
    TreesDefs.FreeTree[nameList]; };
    
    
  InDclList: PROCEDURE [node, list: LONG POINTER TO TreesDefs.TreeNode]
  	RETURNS [dcl, item: LONG POINTER TO TreesDefs.TreeNode] = {
	
    n, dclItemList, dcltor: LONG POINTER TO TreesDefs.TreeNode;
    
    FOR n ← list, n.right WHILE n # NIL DO -- move along dclList
        IF n.left = NIL THEN LOOP;
        FOR dclItemList ← n.left.right, dclItemList.right
            WHILE dclItemList # NIL DO
	        IF dclItemList.left = NIL THEN LOOP;
	        dcltor ← dclItemList.left.left;
	        IF String.EqualString[dcltor.string, node.string] THEN
	            RETURN [n.left, dclItemList.left];
	ENDLOOP;
    ENDLOOP;
    RETURN [NIL, NIL]; };
    
    
  PrintDeclarations: PUBLIC PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode,
      indent: CARDINAL, separator: LONG STRING, terminateWithSeparator: BOOLEAN] = {
      
    n: LONG POINTER TO TreesDefs.TreeNode;
    
    FOR n ← node, n.right WHILE n # NIL DO
        IF n.nodeType # dclList THEN {
	    PrintingDefs.OutCode["*** No dclList in PrintDeclarations ***"L, 0];
	    PrintingDefs.OutCode[separator, 0];
	    RETURN; };
        PrintOneDeclaration[n.left, indent,
	    IF n.right = NIL AND NOT terminateWithSeparator
	    THEN ""L ELSE separator,
	    NIL];
    ENDLOOP; };
    
    
  GetAttributes: PUBLIC PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode,
  	    indent: CARDINAL]
	RETURNS [symType: SymbolTableDefs.SymbolType, typeString: LONG STRING] = {
	
    IF node = NIL THEN {
        symType ← none;
        typeString ← Storage.CopyString["*** NIL argument to GetAttributes ***"L];
	RETURN; }
    ELSE IF node.nodeType # attributes THEN {
        symType ← none;
    	typeString ← Storage.CopyString["*** No attributes in GetAttributes ***"L];
	RETURN; }
    ELSE IF node.structure THEN {
        symType ← structure;
        IF node.right = NIL THEN typeString ← Storage.CopyString[node.string]
	ELSE {
	    IF node.string = NIL THEN {
	        typeString ← Storage.CopyString[structName];
		-- move to next generated structure name
	        structName.text[6] ← structName.text[6] + 1; }
	    ELSE typeString ← Storage.CopyString[node.string];
	    PrintingDefs.OutCode[typeString, indent];
	    PrintingDefs.OutCode[": TYPE = RECORD [\n"L, 0];
	    PrintDeclarations[node.right, indent + 1, ",\n"L, FALSE];
	    PrintingDefs.OutCode["];\n"L, indent]; }; }
	    
    ELSE IF node.union THEN {
        symType ← union;
        typeString ← Storage.CopyString["UNION"L]  }
	
    ELSE IF node.enumeration THEN {
        symType ← enumeration;
        typeString ← Storage.CopyString["ENUMERATION"L]  }
	
    ELSE IF node.long THEN {
        symType ← long;
        IF node.unsigned THEN typeString ← Storage.CopyString["LONG CARDINAL"L]
	ELSE IF node.int THEN typeString ← Storage.CopyString["LONG INTEGER"L]
	ELSE IF node.float OR node.double THEN typeString ← Storage.CopyString["LONG REAL"L]
	ELSE typeString ← Storage.CopyString["INT"L]; }
	
    ELSE IF node.unsigned THEN {
        symType ← long;
        typeString ← Storage.CopyString["LONG CARDINAL"L]  }
    ELSE IF node.char THEN {
        symType ← short;
        typeString ← Storage.CopyString["INTEGER"L]  }
    ELSE IF node.short THEN {
        symType ← short;
        typeString ← Storage.CopyString["INTEGER"L]  }
    ELSE IF node.float THEN {
        symType ← real;
        typeString ← Storage.CopyString["REAL"L]  }
    ELSE IF node.double THEN {
        symType ← double;
        typeString ← Storage.CopyString["LONG REAL"L]  }
    ELSE {
        symType ← long;
        typeString ← Storage.CopyString["INT"L];  };
    IF node.class = extern THEN Storage.AppendString[@typeString, "--EXTERN--"L]
    ELSE IF node.class = static THEN Storage.AppendString[@typeString, "--STATIC--"L]; };
    
    
  PrintOneDeclaration: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode,
      indent: CARDINAL, separator: LONG STRING,
      oneOnly: LONG POINTER TO TreesDefs.TreeNode] = {
      
    temp: LONG STRING;
    basicTypeString: LONG STRING;
    symType: SymbolTableDefs.SymbolType;
    baseSymType: SymbolTableDefs.SymbolType;
    dclItem: LONG POINTER TO TreesDefs.TreeNode;
    m: LONG POINTER TO TreesDefs.TreeNode;
    dclItemHead: LONG POINTER TO TreesDefs.TreeNode;
    topLevelArray: BOOLEAN;
    nextLevelArray: BOOLEAN;
    pointerCount: CARDINAL;
    sawProcedure: BOOLEAN;
    inBlockHeader: BOOLEAN;
    
    IF node = NIL THEN RETURN;
    
    -- check for a slipup
    IF node.nodeType # declaration THEN {
	PrintingDefs.OutCode["*** No declaration in PrintOneDeclaration ***"L, 0];
	PrintingDefs.OutCode[separator, 0];
	RETURN; };
	
    -- ignore class for now --
    
    -- print any comments associated with this nodeType=declaration
    IF node.string # NIL AND node.string.length > 0 THEN
        PrintingDefs.PrintComments[node.string, indent];
	
    -- get the basic type for this declaration --
    [baseSymType, basicTypeString] ← GetAttributes[node.left, indent];
    
    -- traverse the dclItemList --
    FOR dclItem ← node.right, dclItem.right WHILE dclItem # NIL DO
    
        -- error checking --
        IF dclItem.nodeType # dclItemList THEN {
	    PrintingDefs.OutCode["*** No dclItemList in PrintOneDeclaration ***"L, 0];
	    PrintingDefs.OutCode[separator, 0];
	    RETURN; };
	    
	-- go down the tree and more error checking --
        dclItemHead ← dclItem.left;
        IF dclItemHead.nodeType # itemHead THEN {
	    PrintingDefs.OutCode["*** No itemHead in PrintOneDeclaration ***"L, 0];
	    PrintingDefs.OutCode[separator, 0];
	    RETURN; };
	    
	-- oneOnly # NIL => call from PrintFunctionHead and so only a
	-- single thing is being declared and this is not it
	IF oneOnly # NIL AND dclItemHead # oneOnly THEN LOOP;
	
	-- Now see if the outer level type is ARRAY --
	-- The outer level type is a the end of the declarator list --
	topLevelArray ← dclItemHead.left # NIL
	                AND dclItemHead.left.right # NIL
	                AND dclItemHead.left.right.declaratorType = arrayOf;
	nextLevelArray ← dclItemHead.left # NIL
	                AND dclItemHead.left.right # NIL
	                AND dclItemHead.left.right.right # NIL
			AND dclItemHead.left.right.right.declaratorType = arrayOf;
	    
	-- Now we print out the declaration
	-- First we write out the name of the variable and the ": "
        PrintingDefs.OutCode[dclItemHead.left.string, indent];
        PrintingDefs.OutCode[": "L, 0];
	
	-- Change typedefs to Mesa TYPE declarations --
	IF node.left = NIL THEN EXIT;
        IF node.left.class = typedef THEN PrintingDefs.OutCode["TYPE = "L, 0];
	
	-- Generate the "LONG POINTER TO" part of the type name and count how many indirections
	pointerCount ← 0;
	sawProcedure ← FALSE;
	-- get to and loop through the declarator node chain --
        FOR m ← dclItemHead.left.right, m.right WHILE m # NIL DO
            IF m.nodeType # declarator THEN { -- error checking
                PrintingDefs.OutCode["*** No declarator in PrintOneDeclaration ***"L, 0];
                PrintingDefs.OutCode[separator, 0];
                RETURN; };
    	    SELECT m.declaratorType FROM
    	        pointerTo, arrayOf => {
		    pointerCount ← pointerCount + 1;
		    PrintingDefs.OutCode["LONG POINTER TO "L, 0]; };
    	        functionOf => {
		    PrintingDefs.OutCode["PROCEDURE [] RETURNS ["L, 0];
		    sawProcedure ← TRUE; };
    	        ENDCASE;
    	    ENDLOOP;
	    
	-- Print out the basic type --
        PrintingDefs.OutCode[basicTypeString, 0];
	
	inBlockHeader ← oneOnly # NIL;
	IF topLevelArray AND NOT inBlockHeader THEN {
	    symType ← IF nextLevelArray
	              THEN arrayArray
		      ELSE array; }
	ELSE symType ← IF pointerCount > 0
	               THEN pointer
		       ELSE baseSymType;
	SymbolTableDefs.EnterSymbol[dclItemHead.left.string,
	    symType, baseSymType, basicTypeString, pointerCount, inBlockHeader];
	IF sawProcedure THEN PrintingDefs.OutCode["]"L, 0];
	
	-- If there was an array declaration in the list we have to
	-- now generate space for the array since we have changed its
	-- type to pointer.
	-- Note we don't do this for declaraions in procedure argument
	-- lists (onlyOne # NIL) since no space needs to be generated
	-- in these cases.
        IF NOT inBlockHeader
        AND (symType = array OR symType = arrayArray) THEN {
	    -- Set the array variable (whose type was changed to pointer)
	    -- to point to the first element in the array that allocates
	    -- the space for this variable's array.
    	    PrintingDefs.OutCode[" = @"L, 0];
            PrintingDefs.OutCode[dclItemHead.left.string, 0];
    	    PrintingDefs.OutCode["Array[0]"L, 0];
    	    PrintingDefs.OutCode[separator, 0]; -- includes CR
	    
	    -- now append "Array" to the name and allocate the array itself
            PrintingDefs.OutCode[dclItemHead.left.string, indent];
    	    PrintingDefs.OutCode["Array: "L, 0];
	    -- Go through the declarators again, this time actually allocating
	    -- space for the arrays.
	    m ← dclItemHead.left.right;
	    PrintingDefs.OutCode["ARRAY [0.."L, 0];
	    temp ← IF m.left = NIL THEN Storage.CopyString["0"L]
		   ELSE PrintExprDefs.MakeExpression[m.left, FALSE];
	    PrintingDefs.OutCode[temp, 0];
	    Storage.FreeString[temp];
	    PrintingDefs.OutCode[") OF "L, 0];
    	    FOR m ← dclItemHead.left.right.right, m.right WHILE m # NIL DO
                IF m.nodeType # declarator THEN {
                    PrintingDefs.OutCode[
		        "*** No declarator in PrintOneDeclaration ***"L, 0];
                    PrintingDefs.OutCode[separator, 0];
                    RETURN; };
    	        SELECT m.declaratorType FROM
    	            pointerTo, arrayOf =>
		        PrintingDefs.OutCode["LONG  POINTER TO "L, 0];
    	            functionOf =>
		        PrintingDefs.OutCode["PROCEDURE [] RETURNS [] "L, 0];
    	            ENDCASE;
    	        ENDLOOP;
            PrintingDefs.OutCode[basicTypeString, 0]; };
	
	-- Now handle the double array case
        IF NOT inBlockHeader AND symType = arrayArray THEN {
	    -- Note that these are not initialized correctly.
    	    PrintingDefs.OutCode[" = ALL[@"L, 0];
	    PrintingDefs.OutCode[dclItemHead.left.string, 0];
    	    PrintingDefs.OutCode["ArrayArray[i][0]]"L, 0];
    	    PrintingDefs.OutCode[separator, 0]; -- includes CR
	    
            PrintingDefs.OutCode[dclItemHead.left.string, indent];
    	    PrintingDefs.OutCode["ArrayArray: "L, 0];
    	    FOR m ← dclItemHead.left.right, m.right WHILE m # NIL DO
    	        SELECT m.declaratorType FROM
    	            pointerTo =>
		        PrintingDefs.OutCode["LONG  POINTER TO "L, 0];
    	            arrayOf => {
		        PrintingDefs.OutCode["ARRAY [0.."L, 0];
			temp ← IF m.left = NIL THEN Storage.CopyString["0"L]
			    ELSE PrintExprDefs.MakeExpression[m.left, FALSE];
			PrintingDefs.OutCode[temp, 0];
			Storage.FreeString[temp];
		        PrintingDefs.OutCode[") OF "L, 0]; };
    	            functionOf =>
		        PrintingDefs.OutCode["PROCEDURE [] RETURNS [] "L, 0];
    	            ENDCASE;
    	        ENDLOOP;
            PrintingDefs.OutCode[basicTypeString, 0]; };
	
	-- now see if there is an initialization  --
	IF dclItemHead.right # NIL THEN {	-- there is an initializer
	    SELECT dclItemHead.right.operationType FROM
	        eList => {
	            PrintingDefs.OutCode[" ← "L, 0];
	            PrintInitList[dclItemHead.right]; };
		ENDCASE => {
	            PrintingDefs.OutCode[" ← "L, 0];
                    temp ← PrintExprDefs.MakeExpression[dclItemHead.right, FALSE];
	            PrintingDefs.OutCode[temp, 0];
	            Storage.FreeString[temp]; }; };
	PrintingDefs.OutCode[separator, 0];
	ENDLOOP;
    Storage.FreeString[basicTypeString];
    };
    
    
  PrintInitList: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode] = {
  
    n: LONG POINTER TO TreesDefs.TreeNode;
		    temp: LONG STRING;
    
    PrintingDefs.OutCode["["L, 0];
    FOR n ← node, n.right WHILE n # NIL DO
	IF n.left = NIL THEN LOOP;
        SELECT n.left.operationType FROM
	    eList =>
	        PrintInitList[n.left];
	    ENDCASE => {
                temp ← PrintExprDefs.MakeExpression[n.left, FALSE];
	        PrintingDefs.OutCode[temp, 0];
	        Storage.FreeString[temp]; };
        IF n.right # NIL THEN PrintingDefs.OutCode[", "L, 0];
        ENDLOOP;
    PrintingDefs.OutCode["]"L, 0];
		    };
		
  MergeAttributes: PUBLIC PROCEDURE [n1: LONG POINTER TO TreesDefs.TreeNode,
  	n2: LONG POINTER TO TreesDefs.TreeNode]
	RETURNS [result: LONG POINTER TO TreesDefs.TreeNode] = {
	
        IF n2.structure OR n2.union OR n2.enumeration THEN {
	    IF n2.class = noClass THEN n2.class ← n1.class;
	    result ← n2;
	    Storage.Free[n1]; }
	ELSE IF n1.structure OR n1.union OR n1.enumeration THEN {
	    IF n1.class = noClass THEN n1.class ← n2.class;
	    result ← n1;
	    Storage.Free[n2]; }
		        ELSE {
            n1.char	← n1.char	OR n2.char;
            n1.short	← n1.short	OR n2.short;
            n1.int	← n1.int	OR n2.int;
            n1.long	← n1.long	OR n2.long;
            n1.unsigned	← n1.unsigned	OR n2.unsigned;
            n1.float	← n1.float	OR n2.float;
            n1.double	← n1.double	OR n2.double;
	    IF n1.class = noClass THEN n1.class ← n2.class;
            result ← n1;
	    Storage.Free[n2]; };
    };
      
  }.