DIRECTORY
  PrintingDefs USING [OutCode],
  PrintDclsDefs USING [GetAttributes],
  PrintExprDefs USING [],
  SymbolTableDefs USING [SymbolType, LookUpSymbol],
  TreesDefs USING [MakeNode, TreeNode],
  Storage USING [AppendString, CopyString, FreeString, Free];

PrintExprImpl: PROGRAM IMPORTS PrintDclsDefs, PrintingDefs, Storage,
        TreesDefs, SymbolTableDefs
    EXPORTS PrintExprDefs = {
  
  -- Look at the expression node and see if an integer value
  -- is used as a logical value (as is common in C).
  -- If so then change to a logical value by comparing
  -- the integer value (not equal) with 0.
  -- We need pointer to pointer to node since we might change
  -- the node itself.
  IntExpToRelation: PUBLIC PROCEDURE [e: LONG POINTER TO LONG POINTER TO TreesDefs.TreeNode] = {
  
      IF e = NIL OR e↑ = NIL THEN RETURN;
      IF e.nodeType # operation THEN 
          PrintingDefs.OutCode["*** no operation in IntExpToRelation ***", 0];
      FixPass1[e↑];	-- to get the type analysis information into the tree
      IF e.dataType # boolean THEN {
          temp: LONG POINTER TO TreesDefs.TreeNode;
	  s: LONG STRING ← Storage.CopyString["0"L];
          temp ← TreesDefs.MakeNode[left: NIL, right: NIL,
	      string: s, nodeType: operation];
	  temp.operationType ← iconValue;
	  temp ← TreesDefs.MakeNode[left: e↑, right: temp,
	      string: NIL, nodeType: operation];
	  temp.operationType ← notEquals;
	  e↑ ← temp;
          e.dataType ← boolean;
	  e.baseDataType ← boolean;
	  e.typeString ← "BOOLEAN"L;
	  e.pointerCount ← 0;  };
      };
      
   
   -- This looks through an expression tree and makes some changes
   -- so that code generation will work out better.
   -- It does the following things:
   --    (Pass 1) Does a type analysis of the expression.
   --    (Pass 2) (a) finds logical operations and makes sure their operands
   --        		are logical rather than integer values
   --             (b) changes preIncrement to plusAssign 1
   --		  (c) changes preDecement to minusAssign 1
   --		  (d) adds a simpleValue "1" to postIncrement and postDecrement
   --		  (e) changes arrayReferences with pointers to
   --			pointer arithmetic and dereferencing
   --		  (f) LOOPHOLEs pointers in relational expressions to INT
   --
   --    (Pass 3) Scales pointer arithmetic
    
  FixExpression: PROCEDURE [e: LONG POINTER TO LONG POINTER TO TreesDefs.TreeNode] = {
	
      FixPass1[e↑];  -- do type analysis
      FixPass2[e];
      FixPass3[e];
      };
      
      
  FixPass1: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode] = {
      -- Do a bottom up tree walk and propogate the type information
      -- throughout the tree

      IF node = NIL THEN RETURN;
      IF node.nodeType # operation AND node.nodeType # eList THEN {
          PrintingDefs.OutCode["FixPass1←Error;", 0];
          RETURN; };
	  
      -- Do a bottom up (postorder) tree traversal.
      IF node.operationType # sizeOf THEN FixPass1[node.left];
      IF node.operationType # castOp THEN FixPass1[node.right];
	  
      IF node.nodeType = eList THEN RETURN;
	  
      SELECT node.operationType FROM
      
          multiplyOp,
          assignOp,
          multiplyAssign,
          divideAssign,
          modulusAssign,
          shiftLeftAssign,
          shiftRightAssign,
          plusAssign,
	  postIncrement,
	  postDecrement,
	  preIncrement,
	  preDecrement,
          minusAssign,
          bitAndAssign,
          bitOrAssign,
          bitXorAssign => {
	      node.dataType ← node.left.dataType;
	      node.baseDataType ← node.left.baseDataType;
	      node.typeString ← node.left.typeString;
	      node.pointerCount ← node.left.pointerCount; };
	      
          divideOp,
          modulusOp,
          shiftLeft,
          shiftRight,
          plusOp,
          minusOp,
          bitAnd,
          bitOr,
          bitXor => {
	      l, r: LONG POINTER TO TreesDefs.TreeNode;
	      
	      l ← node.left;
	      r ← node.right;
	      -- The basic algorithm here is
	      -- (1) If either is pointer then result is pointer
	      -- (2) Else if either is long the result is long
	      -- (3) Else the result is that of the left hand
	      --       argument unless that is boolean, then
	      --       it is the right hand argument.
	      SELECT l.dataType FROM
	          pointer => NULL;
		  long => IF r.dataType = pointer THEN l ← r;
		  short => IF r.dataType = long
		           OR r.dataType = pointer THEN l ← r;
                  boolean => IF r.dataType # boolean THEN l ← r;
		  ENDCASE => NULL;
	      node.dataType ← l.dataType;
	      node.baseDataType ← l.baseDataType;
	      node.typeString ← l.typeString;
	      node.pointerCount ← l.pointerCount; };
	      
          bitNot,
	  unaryMinus => {
	      node.dataType ← node.left.dataType;
	      node.baseDataType ← node.left.baseDataType;
	      node.typeString ← node.left.typeString;
	      node.pointerCount ← node.left.pointerCount; };
	      
          sizeOf => {
	      node.dataType ← short;
	      node.baseDataType ← short;
	      node.typeString ← "INTEGER"L;
	      node.pointerCount ← 0; };
	      
	  ifExpression => { -- take the type of from the 'then' expression
	      node.dataType ← node.right.left.dataType;
	      node.baseDataType ← node.right.left.baseDataType;
	      node.typeString ← node.right.left.typeString;
	      node.pointerCount ← node.right.left.pointerCount; };
	  
          logicalOr,
          logicalAnd,
          logicalNot,
          equals,
          notEquals,
          lessThan,
          greaterThan,
          lessThanOrEqual,
          greaterThanOrEqual => {
	      node.dataType ← boolean;
	      node.baseDataType ← boolean;
	      node.typeString ← "BOOLEAN"L;
	      node.pointerCount ← 0;  };
	  
          dereference => {
	      node.pointerCount ← 
	          IF node.left. pointerCount > 0
	          THEN node.left.pointerCount - 1
		  ELSE 0;
	      node.baseDataType ← node.left.baseDataType;
	      node.typeString ← node.left.typeString;
	      node.dataType ← IF node.pointerCount > 0
	                      THEN pointer
	                      ELSE node.baseDataType;  };
          addressOf => {
	      node.dataType ← pointer;
	      node.baseDataType ← node.left.baseDataType;
	      node.typeString ← node.left.typeString;
	      node.pointerCount ← node.left.pointerCount + 1;  };
	  
          castOp => {
	      [node.typeString, node.dataType,
	          node.baseDataType, node.pointerCount]
		  ← GetCastType[node.right.left, node.right.right];
              };
	      
          arrayReference => {
	      node.typeString ← node.left.typeString;
	      node.baseDataType ← node.left.baseDataType;
              node.pointerCount ← IF node.left.pointerCount > 0
	                          THEN node.left.pointerCount - 1
			          ELSE 0;
	      node.dataType ← IF node.left.dataType = arrayArray
	                      THEN array
                              ELSE IF node.pointerCount > 0
			      THEN pointer
	                      ELSE node.baseDataType;  };
	      
          procedureCall,
	  nameValue => {
	      [node.dataType, node.baseDataType, node.typeString,
	          node.pointerCount] ←
	              SymbolTableDefs.LookUpSymbol[node.string];  };
	  
          iconValue => {
	      node.dataType ← long;
	      node.baseDataType ← long;
	      node.typeString ← "INT";
	      node.pointerCount ← 0;  };
	  
          fconValue => {
	      node.dataType ← double;
	      node.baseDataType ← double;
	      node.typeString ← "LONG REAL";
	      node.pointerCount ← 0;  };
	  
          stringValue => {
	      node.dataType ← pointer;
	      node.baseDataType ← short;
	      node.typeString ← "INTEGER";
	      node.pointerCount ← 1;  };
	  
	  structReference => {
	      [node.dataType, node.baseDataType, node.typeString,
	          node.pointerCount] ←
	              SymbolTableDefs.LookUpSymbol[node.right.string];  };
	  
          eList,
	  thenElseExpression => NULL;
	  
	  ENDCASE => ERROR;
	  
      };
     
     
  FixPass2: PROCEDURE [e: LONG POINTER TO LONG POINTER TO TreesDefs.TreeNode] = {
  
      temp2: LONG POINTER TO TreesDefs.TreeNode;
  
      IF e = NIL OR e↑ = NIL THEN RETURN;
      
      IF e.nodeType # eList THEN
      SELECT e.operationType FROM
          -- For logical operations, first do the rest of the tree
	  -- and then check the operands for logical type.
          logicalAnd,
	  logicalOr => {
	      IntExpToRelation[@e.left];
	      IntExpToRelation[@e.right]; };
	      
	  logicalNot => {
	      IntExpToRelation[@e.left]; };
	      
          lessThan,
          lessThanOrEqual,
          greaterThan,
	  greaterThanOrEqual => {
	      IF e.left.dataType = pointer
	      OR e.left.dataType = array
	      OR e.left.dataType = arrayArray THEN
	          e.left ← LoopholeToINT[e.left];
	      IF e.right.dataType = pointer
	      OR e.right.dataType = array
	      OR e.right.dataType = arrayArray THEN
	          e.right ← LoopholeToINT[e.right]; };
	      
	  ifExpression => {
	      IntExpToRelation[@e.left]; };
	      
	  postIncrement, postDecrement => {
	      temp: LONG STRING ← Storage.CopyString[s: "1"L, longer: 64];
	      e.right ← TreesDefs.MakeNode[left: NIL, right: NIL,
	          string: temp, nodeType: operation];
	      e.right.operationType ← iconValue;
	      e.right.pointerCount ← 0;
	      e.right.typeString ← e.left.typeString;
	      e.right.dataType ← e.left.baseDataType;
	      e.right.baseDataType ← e.left.baseDataType; };
	      
	  preIncrement => {
	      -- make a "1" node and change to plusAssign
	      temp: LONG STRING ← Storage.CopyString[s: "1"L, longer: 64];
	      e.operationType ← plusAssign;
	      temp2 ← TreesDefs.MakeNode[left: NIL, right: NIL,
	          string: temp, nodeType: operation];
	      temp2.operationType ← iconValue;
	      e.right ← temp2;
	      e.right.pointerCount ← 0;
	      e.right.typeString ← e.left.typeString;
	      e.right.dataType ← e.left.baseDataType;
	      e.right.baseDataType ← e.left.baseDataType; };
	      
	  preDecrement => {
	      -- make a "1" node and change to minusAssign
	      temp: LONG STRING ← Storage.CopyString[s: "1"L, longer: 64];
	      e.operationType ← minusAssign;
	      temp2 ← TreesDefs.MakeNode[left: NIL, right: NIL,
	          string: temp, nodeType: operation];
	      temp2.operationType ← iconValue;
	      e.right ← temp2;
	      e.right.pointerCount ← 0;
	      e.right.typeString ← e.left.typeString;
	      e.right.dataType ← e.left.baseDataType;
	      e.right.baseDataType ← e.left.baseDataType; };
	      
	  arrayReference => {
	      IF e.left.dataType = pointer THEN {
	          -- change to pointer arithmetic and dereferencing
	          e.operationType ← plusOp;
		  e.pointerCount ← e.left.pointerCount;
		  e.dataType ← e.left.dataType;
		  -- baseDataType and typeString values have already
		  -- been correctly set by FixPass1.
	          e↑ ← TreesDefs.MakeNode[left: e↑, right: NIL,
	              string: NIL, nodeType: operation];
	          e.operationType ← dereference;
		  e.baseDataType ← e.left.baseDataType;
		  e.typeString ← e.left.typeString;
		  e.pointerCount ← IF e.left.pointerCount > 0
		                   THEN e.left.pointerCount - 1
		                   ELSE 0;
		  e.dataType ← IF e.pointerCount > 0
		               THEN pointer
		               ELSE e.baseDataType; };  };
	      
          ENDCASE => NULL;
	  
	  IF e.operationType # sizeOf THEN FixPass2[@e.left];
	  IF e.operationType # castOp THEN FixPass2[@e.right];
      };
     
     
  FixPass3: PROCEDURE [e: LONG POINTER TO LONG POINTER TO TreesDefs.TreeNode] = {
  
      IF e = NIL OR e↑ = NIL THEN RETURN;
      
      -- Do a bottom up (postorder) tree traversal.
      IF e.operationType # sizeOf THEN FixPass3[@e.left];
      IF e.operationType # castOp THEN FixPass3[@e.right];

      IF e.nodeType = eList THEN RETURN;
	  
      SELECT e.operationType FROM
      
      plusOp,
      plusAssign,
      minusOp,
      minusAssign,
      postIncrement,
      postDecrement
      => {
          temp: LONG POINTER TO TreesDefs.TreeNode;
	  
          -- if pointer is on the right, exchange left and right
          IF e.left.dataType # pointer AND e.right.dataType = pointer THEN {
	      temp ← e.left;
	      e.left ← e.right;
	      e.right ← temp;  };
	  IF e.left.dataType = pointer AND e.right.dataType # pointer THEN {
	      IF e.right.operationType = iconValue
	      AND e.right.string.length = 1
	      AND e.right.string.text[0] = '0 THEN {
	          NULL;  }  -- leave the '0 as is
              ELSE IF e.right.operationType = iconValue
	      AND e.right.string.length = 1
	      AND e.right.string.text[0] = '1 THEN {
	          Storage.Free[e.right];
		  e.right ← GetPointerTypeNode[e.left.pointerCount,
		      e.left.typeString, FALSE]; }
	      ELSE {
	          temp ← GetPointerTypeNode[e.left.pointerCount,
		      e.left.typeString, TRUE];
	          temp.left ← e.right;
		  temp.dataType ← e.right.dataType;
		  temp.baseDataType ← e.right.baseDataType;
		  temp.typeString ← e.right.typeString;
		  temp.pointerCount ← e.right.pointerCount;
	          e.right ← temp; }; };
          IF e.operationType = minusOp
	  AND e.left.dataType = pointer
	  AND e.right.dataType = pointer THEN {
	      -- Fix up the minusOp node.
	      e.dataType ← long;
	      e.baseDataType ← long;
	      e.typeString ← "INT"L;
	      e.pointerCount ← 0;
	      temp ← GetPointerTypeNode[e.left.pointerCount,
		      e.left.typeString, TRUE];
	      temp.left ← e↑;
	      e↑ ← temp;
	      e.dataType ← long;
	      e.baseDataType ← long;
	      e.typeString ← "INT"L;
	      e.pointerCount ← 0;  };  };
	  
      ENDCASE => NULL;
      };
      
  LoopholeToINT: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode]
          RETURNS [resultNode: LONG POINTER TO TreesDefs.TreeNode] = {

      -- first make a node to be the second argument to LOOPHOLE
      resultNode ← TreesDefs.MakeNode[left: NIL, right: NIL,
          string: Storage.CopyString["INT"L], nodeType: operation];
      resultNode.operationType ← nameValue;
      resultNode.dataType ← long;
      resultNode.baseDataType ← long;
      resultNode.typeString ← "INT";
      resultNode.pointerCount ← 0;
      
      -- then make it into an expression list (second arg to proc)
      resultNode ← TreesDefs.MakeNode[left: resultNode, right: NIL,
          string: NIL, nodeType: eList];
	  
      -- then make it into an expression list (first arg to proc)
      resultNode ← TreesDefs.MakeNode[left: node, right: resultNode,
          string: NIL, nodeType: eList];
	  
      -- then make the procedure call node using this argument list
      resultNode ← TreesDefs.MakeNode[left: NIL, right: resultNode,
          string: Storage.CopyString["LOOPHOLE"L], nodeType: operation];
      resultNode.operationType ← procedureCall;
      resultNode.dataType ← long;
      resultNode.baseDataType ← long;
      resultNode.typeString ← "INT";
      resultNode.pointerCount ← 0;
      };
      
	      
  GetPointerTypeNode: PROCEDURE [pointerCount: CARDINAL,
      typeString: LONG STRING, multiplyNode: BOOLEAN]
          RETURNS [resultNode: LONG POINTER TO TreesDefs.TreeNode] = {

      tempTypeString: LONG STRING;
      
      -- first make the argument expression
      tempTypeString ← Storage.CopyString[s: ""L, longer: 64];
      THROUGH [1..pointerCount) DO
          Storage.AppendString[@tempTypeString, "LONG POINTER TO "L];
	  ENDLOOP;
      Storage.AppendString[@tempTypeString, typeString];
      resultNode ← TreesDefs.MakeNode[left: NIL, right: NIL,
          string: tempTypeString, nodeType: operation];
      resultNode.operationType ← nameValue;
      -- then make it into an expression list
      resultNode ← TreesDefs.MakeNode[left: resultNode, right: NIL,
          string: NIL, nodeType: eList];
      -- then make the procedure call node using this argument list
      resultNode ← TreesDefs.MakeNode[left: NIL, right: resultNode,
          string: Storage.CopyString["SIZE"L], nodeType: operation];
      resultNode.operationType ← procedureCall;
      resultNode.dataType ← short;
      resultNode.baseDataType ← short;
      resultNode.typeString ← "INTEGER";
      resultNode.pointerCount ← 0;
      IF NOT multiplyNode THEN RETURN;
      -- then make the multiply node
      resultNode ← TreesDefs.MakeNode[left: NIL, right: resultNode,
          string: NIL, nodeType: operation];
      resultNode.operationType ← multiplyOp;
      };
      
	      
  MakeExpression: PUBLIC PROCEDURE
      [node: LONG POINTER TO TreesDefs.TreeNode, withParens: BOOLEAN]
      RETURNS [result: LONG STRING] = {
    
    temp: LONG STRING;
	 
    MakeExpressionRec: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode,
        withParens: BOOLEAN] RETURNS [result: LONG STRING] = {
	 
	 
        InfixOperation: PROCEDURE [
	    left: LONG POINTER TO TreesDefs.TreeNode,
	    operationName: LONG STRING,
            right: LONG POINTER TO TreesDefs.TreeNode] = {
	    
          IF withParens THEN Storage.AppendString[@result, "("L];
          IF left # NIL THEN {
              temp ← MakeExpressionRec[left, TRUE];
    	      Storage.AppendString[@result, temp];
    	      Storage.FreeString[temp]; };
          Storage.AppendString[@result, operationName];
          IF right # NIL THEN {
              temp ← MakeExpressionRec[right, TRUE];
    	      Storage.AppendString[@result, temp];
    	      Storage.FreeString[temp]; };
          IF withParens THEN Storage.AppendString[@result, ")"L];
          };
	  
        
        FunctionOperation: PROCEDURE
	    [functionName: LONG STRING,
	    indirection: BOOLEAN,
	    left: LONG POINTER TO TreesDefs.TreeNode,
            right: LONG POINTER TO TreesDefs.TreeNode] = {
	    
          Storage.AppendString[@result, functionName];
          Storage.AppendString[@result, "["L];
	  IF indirection THEN Storage.AppendString[@result, "@"L];
          temp ← MakeExpressionRec[left, FALSE];
          Storage.AppendString[@result, temp];
          Storage.FreeString[temp];
          IF right # NIL THEN {
              Storage.AppendString[@result, ","L];
              temp ← MakeExpressionRec[right, FALSE];
    	      Storage.AppendString[@result, temp];
    	      Storage.FreeString[temp]; };
          Storage.AppendString[@result, "]"L];
          };
	  
	  
      result ← Storage.CopyString[s: ""L, longer: 64];
      IF node = NIL THEN RETURN;
      IF node.nodeType # operation THEN {
          Storage.AppendString[@result,
	      "*** no operation in MakeExpressionRec ***"L];
	  RETURN; };
	  
      SELECT node.operationType FROM
      
          assignOp => {
	      coerce: BOOLEAN ← FALSE;
	      
	      IF withParens THEN Storage.AppendString[@result, "("L];
              temp ← MakeExpressionRec[node.left, FALSE];
    	      Storage.AppendString[@result, temp];
    	      Storage.FreeString[temp];
              Storage.AppendString[@result, " ← "L];
	      IF node.left.dataType = long
	      AND node.right.dataType = short THEN {
	          coerce ← TRUE;
		  Storage.AppendString[@result, "LONG["L];  }
	      ELSE IF node.left.dataType = short
	      AND node.right.dataType = long THEN {
	          coerce ← TRUE;
		  Storage.AppendString[@result, "INTEGER["L];  };
              temp ← MakeExpressionRec[node.right, FALSE];
    	      Storage.AppendString[@result, temp];
	      IF coerce THEN Storage.AppendString[@result, "]"L];
	      IF withParens THEN Storage.AppendString[@result, ")"L];
    	      Storage.FreeString[temp]; };
	      

          multiplyAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["MultipyAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          divideAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["DivideAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          modulusAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["ModulusAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          plusAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
	      IF node.left.dataType = pointer
	      OR node.left.dataType = array THEN
	          FunctionOperation["PlusAssignPtr"L,
		      TRUE, node.left, node.right]
	      ELSE
	          FunctionOperation["PlusAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          minusAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
	      IF node.left.dataType = pointer
	      OR node.left.dataType = array THEN
	          FunctionOperation["MinusAssignPtr"L,
		      TRUE, node.left, node.right]
	      ELSE
	          FunctionOperation["MinusAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          shiftLeftAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["ShiftLeftAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          shiftRightAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["ShiftRightAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          bitAndAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["BitAndAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          bitOrAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["BitOrAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	  
          bitXorAssign => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
              FunctionOperation["BitXorAssign", TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	      
	  ifExpression => {
	      Storage.AppendString[@result, "IF "L];
	      temp ← MakeExpressionRec[node.left, TRUE];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      Storage.AppendString[@result, " THEN "L];
	      temp ← MakeExpressionRec[node.right.left, TRUE];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      Storage.AppendString[@result, " ELSE "L];
	      temp ← MakeExpressionRec[node.right.right, TRUE];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp]; };
	  
          logicalOr => {
	      InfixOperation[node.left, " OR "L, node.right];  };
	  
          logicalAnd => {
	      InfixOperation[node.left, " AND "L, node.right];  };
	  
          bitOr => {
	      FunctionOperation["BitOr"L, FALSE, node.left, node.right];  };
	  
          bitAnd => {
	      FunctionOperation["BitAnd"L, FALSE, node.left, node.right];  };
	  
          bitXor => {
	      FunctionOperation["BitXor"L, FALSE, node.left, node.right];  };
	  
          equals => {
	      InfixOperation[node.left, " = "L, node.right];  };
	  
	  notEquals => {
	      InfixOperation[node.left, " # "L, node.right];  };
	  
          lessThan => {
	      InfixOperation[node.left, " < "L, node.right];  };
	  
          greaterThan => {
	      InfixOperation[node.left, " > "L, node.right];  };
	  
          lessThanOrEqual => {
	      InfixOperation[node.left, " <= "L, node.right];  };
	  
          greaterThanOrEqual => {
	      InfixOperation[node.left, " >= "L, node.right];  };
	  
          shiftLeft => {
	      FunctionOperation["ShiftLeft"L, FALSE, node.left, node.right];  };
	  
          shiftRight => {
	      FunctionOperation["ShiftRight"L, FALSE, node.left, node.right];  };
	  
          plusOp => {
	      InfixOperation[node.left, " + "L, node.right];  };
	  
	  minusOp => {
	      InfixOperation[node.left, " - "L, node.right];  };
	  
          multiplyOp => {
	      InfixOperation[node.left, " * "L, node.right];  };
	  
          divideOp => {
	      InfixOperation[node.left, " / "L, node.right];  };
	  
          modulusOp => {
	      InfixOperation[node.left, " MOD "L, node.right];  };
	  
	  postIncrement => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
	      IF node.left.dataType = pointer
	      OR node.left.dataType = array THEN
		  FunctionOperation["PostIncPtr"L,
		      TRUE, node.left, node.right]
	      ELSE
	          FunctionOperation["PostInc",
	              TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	      
          postDecrement => {
	      IF withParens THEN Storage.AppendString[@result, "("L];
	      IF node.left.dataType = pointer
	      OR node.left.dataType = array THEN
		  FunctionOperation["PostDecPtr"L,
		      TRUE, node.left, node.right]
	      ELSE
	          FunctionOperation["PostDec",
	              TRUE, node.left, node.right];
	      IF withParens THEN Storage.AppendString[@result, ")"L]; };
	      
          dereference => {
	      IF node.left.pointerCount = 0 THEN
	          Storage.AppendString[@result,
		      "***dereference of non pointer***"L];
	      InfixOperation[node.left, "↑"L, NIL];  };
	  
          addressOf => {
	      InfixOperation[NIL, "@"L, node.left];  };
	  
	  unaryMinus => {
	      InfixOperation[NIL, "-"L, node.left];  };
	  
	  logicalNot => {
	      InfixOperation[NIL, "NOT "L, node.left];  };
	  
          bitNot => {
	      FunctionOperation["BitNot"L, FALSE, node.left, NIL];  };
	  
	  sizeOf => {
	      temp: LONG STRING ← GetSizeOfType[node.left];
	      
	      Storage.AppendString[@result, "SIZE["L];
	      Storage.AppendString[@result, temp];
	      Storage.AppendString[@result, "]"L];
	      Storage.FreeString[temp]; };
	      
          castOp => {
	      temp: LONG STRING;
	      
	      Storage.AppendString[@result, "LOOPHOLE["L];
	      temp ← MakeExpressionRec[node.left, FALSE];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      Storage.AppendString[@result, ", "L];
	      temp ← GetCastString[node.right.left, node.right.right];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      Storage.AppendString[@result, "]"L]; };
	      
          arrayReference => {
	      temp: LONG STRING ← MakeExpressionRec[node.left, TRUE];
	      
              Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      IF node.left.dataType = array
	      AND node.left.operationType = nameValue THEN
	          Storage.AppendString[@result, "Array"L]
	      ELSE IF node.left.dataType = arrayArray THEN
	          Storage.AppendString[@result, "ArrayArray"L];
	      Storage.AppendString[@result, "["L];
	      IF node.right.dataType # short THEN
	          Storage.AppendString[@result, "INTEGER["L];
	      temp ← MakeExpressionRec[node.right, FALSE];
	      Storage.AppendString[@result, temp];
	      Storage.FreeString[temp];
	      IF node.right.dataType # short THEN
	          Storage.AppendString[@result, "]"L];
	      Storage.AppendString[@result, "]"L]; };
	      
          procedureCall => {
	      n: LONG POINTER TO TreesDefs.TreeNode;
	      
	      Storage.AppendString[@result, node.string];
	      Storage.AppendString[@result, "["L];
	      FOR n ← node.right, n ← n.right WHILE n # NIL DO
	          temp ← MakeExpressionRec[n.left, FALSE];
	          Storage.AppendString[@result, temp];
	          Storage.FreeString[temp];
	          IF n.right # NIL THEN Storage.AppendString[@result, ", "L];
	          ENDLOOP;
	      Storage.AppendString[@result, "]"L]; };
	      
	  structReference => {
	      InfixOperation[node.left, "."L, node.right]; };
	  
	  nameValue => {
	      IF node.string.length = 4 AND node.string.text[0] = 'N
	      AND node.string.text[1] = 'U AND node.string.text[2] = 'L
	      AND node.string.text[3] = 'L THEN
	          Storage.AppendString[@result, "c"L];
	      Storage.AppendString[@result, node.string];  };
	  
	  iconValue,
	  fconValue,
	  stringValue => {
	      Storage.AppendString[@result, node.string];  };
	  
          ENDCASE => {
	      Storage.AppendString[@result,
	          "*** expression error in MakeExpression ***"L];  };
      };
     
     	--	main MakeExpression code	--
    FixExpression[@node];
    result ← IF node = NIL THEN Storage.CopyString[""L]
    	     ELSE MakeExpressionRec[node, FALSE];
    };
    
    
  GetCastType: PROCEDURE [type: LONG POINTER TO TreesDefs.TreeNode,
      declarator: LONG POINTER TO TreesDefs.TreeNode]
      RETURNS [baseType: LONG STRING, symType,
          baseSymType: SymbolTableDefs.SymbolType, pointerCount: CARDINAL] = {
      
	n: LONG POINTER TO TreesDefs.TreeNode;
	
	IF type = NIL OR declarator = NIL THEN
	    RETURN [Storage.CopyString["*** NIL argument to GetCastType ***"L],
	        none, none, 0];
	IF type.nodeType # attributes THEN
	    RETURN [Storage.CopyString["*** cast error in GetCastType ***"L],
	        none, none, 0];
	pointerCount ← 0;
	[symType: baseSymType, typeString: baseType]
	    ← PrintDclsDefs.GetAttributes[type, 0];
	FOR n ← declarator, n.right WHILE n # NIL DO
	    SELECT n.declaratorType FROM
		arrayOf,
	        pointerTo => pointerCount ← pointerCount + 1;
		ENDCASE => NULL;
	    ENDLOOP;
	symType ← IF pointerCount > 0 THEN pointer ELSE baseSymType;
    };
    
    
  GetCastString: PROCEDURE [type: LONG POINTER TO TreesDefs.TreeNode,
      declarator: LONG POINTER TO TreesDefs.TreeNode]
      RETURNS [castType: LONG STRING] = {
      
        temp, baseType: LONG STRING;
	n: LONG POINTER TO TreesDefs.TreeNode;
	
	IF type = NIL OR declarator = NIL THEN
	    RETURN [Storage.CopyString["*** NIL argument to GetCastType ***"L]];
	IF type.nodeType # attributes THEN
	    RETURN [Storage.CopyString["*** cast error in GetCastType ***"L]];
	[typeString: baseType]
	    ← PrintDclsDefs.GetAttributes[type, 0];
	castType ← Storage.CopyString[s: ""L, longer: 64];
	FOR n ← declarator, n.right WHILE n # NIL DO
	    SELECT n.declaratorType FROM
	        pointerTo => Storage.AppendString[@castType, "LONG POINTER TO "L];
		arrayOf => {
		    Storage.AppendString[@castType, "ARRAY [0.."L];
		    temp ← IF n.left # NIL THEN
		               MakeExpression[n.left, FALSE]
			   ELSE Storage.CopyString["0"L];
		    Storage.AppendString[@castType, temp];
		    Storage.FreeString[temp];
		    Storage.AppendString[@castType, ") OF "L]; };
		functionOf => Storage.AppendString[@castType, "PROCEDURE [] "L];
		simpleName => NULL;
		ENDCASE => ERROR;
	    ENDLOOP;
	Storage.AppendString[@castType, baseType];
    };
    
    
  GetSizeOfType: PROCEDURE [node: LONG POINTER TO TreesDefs.TreeNode]
      RETURNS [result: LONG STRING] = {
      
      IF node = NIL THEN
          RETURN["*** NIL argument to GetSizeOfType ***"L];
      IF node.nodeType # operation THEN {
          result ← GetCastString[node.left, node.right];
          RETURN;  };
      result ← Storage.CopyString[s: ""L, longer: 64];
      THROUGH [0..node.pointerCount) DO
          Storage.AppendString[@result, "LONG POINTER TO "L];
          ENDLOOP;
      Storage.AppendString[@result, node.typeString];
      };
    
}.