ftp.nice.ch/pub/next/developer/languages/ada/Adaed.1.11.s.tar.gz#/Adaed-1.11.0a/expand.c

This is expand.c in view mode; [Download] [Up]

/*
 * Copyright (C) 1985-1992  New York University
 * 
 * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
 * warranty (none) and distribution info and also the GNU General Public
 * License for more details.

 */
#define GEN

#include "hdr.h"
#include "libhdr.h"
#include "vars.h"
#include "gvars.h"
#include "attr.h"
#include "slot.h"
#include "segment.h"
#include "setprots.h"
#include "langprots.h"
#include "initprots.h"
#include "initobjprots.h"
#include "dbxprots.h"
#include "miscprots.h"
#include "utilprots.h"
#include "glibprots.h"
#include "readprots.h"
#include "libprots.h"
#include "arithprots.h"
#include "librprots.h"
#include "gnodesprots.h"
#include "gmiscprots.h"
#include "gutilprots.h"
#include "aggrprots.h"
#include "chapprots.h"
#include "smiscprots.h"
#include "gmainprots.h"
#include "expandprots.h"

void expand(Node node)												/*;expand*/
{
	/*
	 * Expander
	 * Performs a set of semantic transformations on the tree
	 * in order to simplify the job for the code generator.
	 * Some semantic optimizations are performed too.
	 * IMPORTANT: 
	 *    expand must not be called twice on the same structure, as
	 *    for some kinds of nodes, the format before expand is
	 *    different from the format after expand. A special problem
	 *    arises for aggregates, where already expanded structures
	 *    (subaggregates) are part of a not yet expanded structure
	 *    (assignment to enclosing structure) that must be expanded.
	 *    a special node, as_expanded, is used to block double
	 *    expansion in that case.
	 */

	Fortup      ft1, ft2;
	Tuple       tup, tup1, tup2;
	Symbolmap   instance_map, type_map;
	Node        node1, node2, node3, node4;
	Symbol      sym1, sym2, sym3, sym4;
	int         nk, cboolean;
	Const       lv;
	Unitdecl    ud;

	/* TBSL remove the following declarations */
	Const       lbd_1, ubd_1, lbd_2, ubd_2;
	int         ubd_1_val, ubd_2_val, lbd_1_val, lbd_2_val;

	Tuple  instantiation_code, ntup ;
#ifdef TRACE
	if (debug_flag)
		gen_trace_node("EXPAND", node);
#endif

#ifdef DEBUG
	if (trapns>0 && N_SEQ(node)== trapns && N_UNIT(node) == trapnu) trapn(node);
#endif
	switch N_KIND(node) {

	case(as_insert):
		N_SIDE(node) = FALSE;
		FORTUP(node1 = (Node), N_LIST(node), ft1);
			expand(node1);
			N_SIDE(node) |= N_SIDE(node1);
		ENDFORTUP(ft1);
		node1 = N_AST1(node);
		expand(node1);
		N_SIDE(node) |= N_SIDE(node1);
		break;

	/* Chapter 3. Declarations and types*/
	/*
	 *-----------------
	 * 3.1 Declarations
	 */
	case(as_declarations):
		N_SIDE(node) = FALSE;
		if (N_LIST(node) == (Tuple)0)
			chaos("expand.c: as_declarations N_LIST null");
		FORTUP(node1 = (Node), N_LIST(node), ft1);
			expand(node1);
			N_SIDE(node) |= N_SIDE(node1);
		ENDFORTUP(ft1);
		break;

	/*
	 *------------------------------
	 * 3.2 Objects and named numbers
	 */

	case(as_obj_decl):
	case(as_const_decl):
		expand_decl(node);
		break;

	/*
	 *-----------------------
	 * 3.3 Types and subtypes
	 * 3.3.1
	 */
	case(as_type_decl):
		expand_type(node);
		break;

	/* 3.3.2 */
	case(as_subtype_decl):
	expand_subtype(node);
		break;

	case(as_delayed_type):
		sym1 = N_UNQ(N_AST1(node)); /* type name */
		sym2 = N_UNQ(N_AST2(node)); /* parent name */
		node1 = copy_node(node);    /* delayed node */
		if (NATURE(sym1) == na_subtype)
			N_KIND(node1) = as_subtype_decl;
		else
			N_KIND(node1) = as_type_decl;
		nk = emap_get(sym2); 
		tup = EMAP_VALUE;
		if (!nk)  /* emap_defined */
			tup = tup_new1((char *) node1);
		else
			tup = tup_with(tup, (char *)node1);
		/* EMAP(sym2) = (EMAP(sym2)?[]) with node1;*/
		emap_put(sym2, (char *) tup);
		delete_node(node);
		break;

	case(as_subtype_indic):
		sym1 = N_UNQ(N_AST1(node)); /* type name */
		N_SIDE(node) = (unsigned)CONTAINS_TASK(sym1);
		node2 = N_AST2(node); /* expression */
		expand(node2);
		N_SIDE(node) |= N_SIDE(node2);
		break;
	/*
	 *-----------------
	 * 3.5 Scalar types
	 */
	case(as_digits):
		expand(N_AST1(node)); /* precision node */
		node2 = N_AST2(node); /* range node */
		expand(node2);
		N_SIDE(node) = N_SIDE(node2);
		break;

	case(as_delta):
		expand(N_AST1(node)); /* precision node */
		node2 = N_AST2(node); /* range node */
		expand(node2);
		N_SIDE(node) = N_SIDE(node2);
		break;

	case(as_subtype):
		node2 = N_AST2(node);
		expand(node2);
		N_SIDE(node) = N_SIDE(node2);

		/* Transmit tasks_declared: */
		sym1 = N_UNQ(N_AST1(node)); /* type name */
		/* N_TYPE(node) is parent type */
		CONTAINS_TASK(sym1) = CONTAINS_TASK(N_TYPE(node));
		break;

	case(as_component_list):
		node1 = N_AST1(node); /* invariant node */
		FORTUP(node2 = (Node), N_LIST(node1), ft1);
			expand(node2);     /* field node */
		ENDFORTUP(ft1);
		expand(N_AST2(node)); /* variant node */
		N_SIDE(node) = FALSE;
		break;

	case(as_simple_choice):
		node1 = N_AST1(node); /* expression */
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		break;

	case(as_incomplete_decl):
		sym1 = N_UNQ(N_AST1(node)); /* type name */
		CONTAINS_TASK(sym1) = (char *) TRUE; /* May be. Future will tell */
		delete_node(node);
		break;

	/*
	 * Chapter 4. Names and expressions
	 *
	 *----------
	 * 4.1 Names
	 */
	case(as_range_choice):
		node1 = N_AST1(node);
		if (N_KIND(node1) == as_attribute) {
			/* must be range. */
			sym1 = N_TYPE(node1);
			nk = (int)attribute_kind(node1) - ATTR_RANGE;   /* 'T' or 'O'*/
			attribute_kind(node1) = (char *) (nk + ATTR_FIRST);
			N_AST2(node) = new_attribute_node(nk + ATTR_LAST,
			  N_AST2(node1), N_AST3(node1), sym1);
			N_KIND(node) = as_range;
			N_TYPE(node) = sym1;
			expand(node);
		}
		else {
			node2 = N_AST2(node1);
			expand(node2);
			N_SIDE(node) = N_SIDE(node2);
		}
		break;

	case(as_range):
		node1 = N_AST1(node); /* expression */
		node2 = N_AST2(node); /* expression */
		expand(node1);
		expand(node2);
		N_SIDE(node) = N_SIDE(node1) | N_SIDE(node2);
		break;

	case(as_constraint):
		N_SIDE(node) = FALSE;
		FORTUP(node1 = (Node), N_LIST(node), ft1);
			if (N_KIND(node1) == as_choice_list) {
				/* named discriminant constraints. Only need expression. */
				node1 = N_AST2(node1) ;
			}
			expand(node1);
			N_SIDE(node) |= N_SIDE(node1);
		ENDFORTUP(ft1);
		break;

	case(as_index):
		node1 = N_AST1(node) ; /* array node */
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		/* N_AST2(node) is a list of indices */
		FORTUP(node2 = (Node), N_LIST(N_AST2(node)), ft1);
			expand(node2); /* index */
			N_SIDE(node) |=  N_SIDE(node2);
		ENDFORTUP(ft1);
		break;

	/*
	 * 4.1.2
	 */
	case(as_slice):
		node2 = N_AST2(node) ; /* range node */

		if (N_KIND(node2) == as_subtype) {
			/* remove subtype */
			node1 = N_AST2(node2); /* id node */
			copy_attributes(node1, node2);
		}

		if (is_simple_name(node2)) {
			/* type name replaced by range attribute */
			/* SETL has OPT_NODE as third arg in next call. This is
	 		 * wrong - want to indicate first dimension.
	 		 *  ds	9-8-85
	 		 */
			node2 = new_attribute_node(ATTR_T_RANGE, node2,
			  new_ivalue_node(int_const(1), symbol_integer), N_UNQ(node2));
			N_AST2(node) = node2 ;
		}
		node1 = N_AST1(node) ; /* array node */
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		expand(node2);         /* range node */
		N_SIDE(node) |= N_SIDE(node2);
		break;

	case(as_field):
		node2 = N_AST2(node) ; /* expression */
		expand(node2);
		N_SIDE(node) = N_SIDE(node2);
		break;

	case(as_selector):
	case(as_all):
		node1 = N_AST1(node) ; /* expression */
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		break;

	/*
	 * 4.1.4
	 */
	case(as_attribute):
	case(as_range_attribute):
		expand_attr(node);
		break;

	/*
	 *-------------
	 * 4.2 Literals
	 */
	case(as_string_ivalue):
		expand_string(node);
		break;

	case(as_int_literal):
		/* TBSL(JC) This is a kludge */
		N_KIND(node) = as_ivalue;
		lv = adaval(symbol_integer, N_VAL(node));
		if (adaval_overflow)
			chaos("unable to convert integer literal");
		else
			N_VAL(node) = (char *) lv;
		N_SIDE(node) = FALSE;
		break;

	/*
	 *---------------
	 * 4.3 Aggregates
	 */
	case(as_array_aggregate):
#ifdef DEFER
		/* N_LIST assignmentnot needed in packed version  DS 3-86 */
		N_LIST(node) = (Tuple)0;    /* Useless information removed */
#endif
		expand_array_aggregate(node) ;
		N_SIDE(node) = N_KIND(node) != as_array_ivalue;
		/* TBSL better N_SIDE */
		break;

	case(as_row):
		node1 = N_AST1(node); /* expression */
		if (is_ivalue(node1) && root_type(N_TYPE(node1)) == symbol_character) {
			/* Transform into string litteral */
			/* Clear current AST_3 and AST_4 only if defined, thus preserving
	 		 * any N_UNQ and N_TYPE values if these are defined for the node.
	 		 */
			if (N_AST3_DEFINED(N_KIND(node))) N_AST3(node) = (Node) 0;
			if (N_AST4_DEFINED(N_KIND(node))) N_AST4(node) = (Node) 0;
			N_KIND(node) = as_string_ivalue;
			N_AST1(node) = (Node)0;
			N_AST2(node) = (Node)0;
			/* TBSL: check translation of following carefully */
			N_VAL(node) = (char *) tup_new1((char *) get_ivalue_int(node1));
		}
		else {
			/* Transform into an aggregate */
			N_KIND(node) = as_array_aggregate;
			/* positionnal */
			node3 = node_new(as_aggregate_list);
			node2         = node_new(as_list); /* positionnal */
			N_LIST(node2) = tup_new1((char *) node1);
			N_AST1(node3)  = node2 ;
			/* named */
			node2         = node_new(as_list); /* named */
			N_LIST(node2) = tup_new(0);
			N_AST2(node3)  = node2 ;
			N_AST1(node) = node3;

			N_AST2(node)  = OPT_NODE ;
			N_UNQ (node)  = new_unique_name("row");
		}
		expand(node);
		break;

	case(as_record_aggregate):
		expand_record_aggregate(node);
		N_SIDE(node) = N_KIND(node) != as_record_ivalue;
		/* TBSL better N_SIDE */
		break;

	/*
	 *----------------
	 * 4.4 Expressions
	 */

	/*
	 *----------------------------------------
 	* 4.5 Operators and expression evaluation
	 */
	case(as_op):
		expand_op(node);
		break;

	case(as_un_op):
		node2 = N_AST2(node) ; /* arguments */
		node1 = (Node) ((Tuple) N_LIST(node2)[1]);
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		break;

	/*
	 *---------------------
	 * 4.6 Type conversions
	 */
	case(as_qual_range):
	case(as_qual_discr):
	case(as_qual_sub):
		node1 = N_AST1(node) ; /* expression */
		expand(node1);

		/* Note: must expand before checking types, as actual subtype of */
		/* aggregates may be determined by expansion. */
		sym1 = N_TYPE(node); /* qualification type */
		if (sym1 == get_type(node1) || is_unconstrained(sym1)) {
			/* remove qual */
			copy_attributes(node1, node);
		}
		else {
			N_SIDE(node) = N_SIDE(node1);
		}
		break;

	case(as_qual_index):
		node1 = N_AST1(node); /* expression */
		expand(node1);
		sym1 = N_TYPE(node); /* qualification type */
		sym2 = get_type(node1);
		if (sym1 == sym2 || is_unconstrained(sym1)) {
			/* remove qual */
			copy_attributes(node1, node);
		}
		else {
			/* tup_copy needed since index_types tuple used here
	 		 * destructiely  ds 6-25-85
	 		 */
			/* TBSL (JC) no copy needed. use FORTUPI */
			tup1 = tup_copy(index_types(sym1));
			tup2 = tup_copy(index_types(sym2));
			cboolean = TRUE;
			while (tup_size(tup1)) {
				sym3 = (Symbol) tup_fromb(tup1);
				sym4 = (Symbol) tup_fromb(tup2);
				node2 = (Node) ((Tuple) SIGNATURE(sym3)[2]); /* lower bound */
				node3 = (Node) ((Tuple) SIGNATURE(sym3)[3]); /* upper bound */
				lbd_1 = get_ivalue(node2);
				ubd_1 = get_ivalue(node3);
				node2 = (Node) ((Tuple) SIGNATURE(sym4)[2]); /* lower bound */
				node3 = (Node) ((Tuple) SIGNATURE(sym4)[3]); /* upper bound */
				lbd_2 = get_ivalue(node2);
				ubd_2 = get_ivalue(node3);
				if (N_KIND(node1) != as_slice && !is_unconstrained(sym2)
				  && lbd_1->const_kind != CONST_OM
				  && ubd_1->const_kind != CONST_OM
				  && lbd_2->const_kind != CONST_OM
				  && ubd_2->const_kind != CONST_OM) {
					lbd_1_val = INTV(lbd_1); 
					ubd_1_val = INTV(ubd_1);
					lbd_2_val = INTV(lbd_2); 
					ubd_2_val = INTV(ubd_2);
					if ((ubd_1_val - lbd_1_val) != (ubd_2_val - lbd_2_val)) {
						make_raise_node(node, symbol_constraint_error);
						USER_WARNING("Evaluation of expression will raise",
						  " CONSTRAINT_ERROR");
						cboolean = FALSE;
						break;
					}
					if ((ubd_1_val != ubd_2_val) || (lbd_1_val != lbd_2_val)) {
						cboolean = FALSE;
						break;
					}
				}
				else { /* non static */
					cboolean = FALSE;
					break;
				}
			} /* end loop */
			if (cboolean) {
				/* qual_index can be removed */
				copy_attributes(node1, node);
				N_TYPE(node) = sym1;
				if (is_aggregate(node))  {
					node2 = N_AST2(node); /* object node */
					TYPE_OF(N_UNQ(node2)) = sym1;
				}
				else if (N_KIND(node)==as_insert && is_aggregate(N_AST1(node))){
					node2 = N_AST2(N_AST1(node)); /* object node */
					TYPE_OF(N_UNQ(node2)) = sym1;
				}
			}
			else {
				N_SIDE(node) = N_SIDE(node1);
			}
		}
		break;

	case(as_qual_aindex):
	case(as_qual_alength):
	case(as_qual_adiscr):
		node1 = N_AST1(node) ; /* expression */
		expand(node1);
		if (N_KIND(node1) == as_null) {
			/* remove qual */
			copy_attributes(node1, node);
		}
		else {
			N_SIDE(node) = N_SIDE(node1);
		}
		break;

	case(as_convert):
		/* The target type of the conversion is the type of the node */
		/* The source type is the type of the expression itself. */
		node2 = N_AST2(node) ; /* expression */

		/* Special case: convert of a fixed point * or / */
		if (N_KIND(node2) == as_op && (op_kind(node2) == symbol_mulfx
		  || op_kind(node2) == symbol_divfx)) {

			/* Bind result type to the operation and remove node */
			N_TYPE(node2) = N_TYPE(node);
			copy_attributes(node2, node);
			expand(node);
		}
		else {
			expand(node2);
			N_SIDE(node) = N_SIDE(node2);

			/* Remove unnecessary conversion */
			if ((base_type(get_type(node2)) == base_type(N_TYPE(node))
			  && !is_unconstrained(base_type(N_TYPE(node))))
			  || ((root_type(get_type(node2)) == root_type(N_TYPE(node)))
			  && (is_discrete_type (root_type (get_type (node2)))))) {
				/*copy_attributes(node2, node); */
				N_KIND (node) = as_qual_range;
				N_AST1 (node) = N_AST2 (node);
			}
		}
		break;

	case(as_arg_convert):
		/*    The target type of the conversion is the type of the node
		 *    The source type is the type of the expression itself.
		 *    src_type    = get_type(node2) ;
		 *    target_type = N_TYPE(node);
		 */
		node2 = N_AST2(node) ; /* expression */
		expand(node2);
		N_SIDE(node) = N_SIDE(node2);
		break;

	/*
	 *---------------
	 * 4.8 Allocators
	 */
	case(as_new):
		node1 = N_AST1(node) ; /* id node */
		node2 = N_AST2(node) ; /* expression */
		sym1  = N_UNQ(node1) ; /* allocated type */
		/* N_TYPE(node) is the type of the context */
		sym2 = (Symbol) designated_type(N_TYPE(node)); /* accessed type */

		if (is_task_type(sym2)) {
			node2 = new_create_task_node(sym2);
			N_AST2(node) = node2 ;
		}
		else if ( is_access_type(sym2) && node2 == OPT_NODE) {
			node2 = node_new(as_null);
			N_AST2(node) = node2 ;
		}

		expand(node2);

		if (!is_simple_name(node1)) {
			/* There is a subtype to emit */
			expand(node1);
			make_insert_node(node, tup_new1((char *) node1), copy_node(node));
			node = N_AST1(node);
		}
		else if ( is_unconstrained(sym1)) {
			/* Establish proper subtype */
			if (is_array_type(sym1)) {
				/* Take constraint from initial value (always present in */
				/* this case) */
				sym1 = get_type(node2);
				N_UNQ(node1) = sym1;
			}
			else if (node2 == OPT_NODE) {  /* record */
				/* Create a subtype, constrained by default values. (Default
				 * values always present in that case). 
				 */
				sym1 = new_unique_name("constrained_type");
				N_UNQ(node1) = sym1;
				tup1 = constraint_new(co_discr);
				tup = tup_new(0);
				FORTUP(sym4 = (Symbol), discriminant_list_get(sym2), ft1);
					/* An allocator is always constrained. Set the constrained
					* bit accordingly
					*/
					if (sym4 == symbol_constrained)
						tup = discr_map_put(tup, sym4, 
					      new_ivalue_node(int_const(TRUE), symbol_boolean));
					else
						tup = discr_map_put(tup, sym4, 
					      copy_tree((Node) default_expr(sym4)));
				ENDFORTUP(ft1);
				tup1[2] = (char *) tup;
				new_symbol(sym1, na_subtype, sym2, tup1,
				  root_type(sym2));
				node1 = new_subtype_decl_node(sym1);
				expand(node1);
				make_insert_node(node,tup_new1((char *)node1), copy_node(node));
				node = N_AST1(node);
			}
			else if ( !is_unconstrained(get_type(node2))) {
				/* Use expression subtype for allocated object */
				sym3 = get_type(node2);
				N_UNQ(node1) = sym3;
			}
			else {
				/* Worst case: new REC'(F), where REC is unconstrained, and F
				 * returns REC. The subtype must be elaborated from the value
				 * of discriminants of the expression.
				 */
				sym3 = get_type(node2);
				sym1 = new_unique_name("constrained_type");
				N_UNQ(node1) = sym1;
				/* tup1 = [co_discr, {} ];*/
				tup1 = constraint_new(co_discr);
				tup1[2] = (char *) tup_new(0);
				new_symbol(sym1, na_subtype, sym2, tup1,
				  root_type(sym2));
				CONTAINS_TASK(sym1) = CONTAINS_TASK(sym2);

				node3         = node_new(as_type_and_value);
				N_AST1(node3) = new_name_node(sym1) ;
				N_AST2(node3) = node2 ;
				N_TYPE(node3) = sym3;
				N_AST1(node)  = node1 ;
				N_AST2(node)  = node3 ;
				if (N_AST3_DEFINED(N_KIND(node))) N_AST3(node) = (Node) 0;
				if (N_AST4_DEFINED(N_KIND(node))) N_AST4(node) = (Node) 0;
			}
		}
		sym3 = INIT_PROC(base_type(sym2));
		if (node2 == OPT_NODE && sym3 != (Symbol)0) {
			node2 = build_init_call(OPT_NODE, sym3, sym1, OPT_NODE);
			expand(node2);
			N_AST1(node) = node1 ;
			N_AST2(node) = node2;
			if (N_AST3_DEFINED(N_KIND(node))) N_AST3(node) = (Node) 0;
			if (N_AST4_DEFINED(N_KIND(node))) N_AST4(node) = (Node) 0;
		}
		N_SIDE(node) = TRUE;
		break;

		/** Chapter 5. Statements */

	case(as_null_s):
		break;

	case(as_line_no):
		ada_line     = (int) N_VAL(node);
		N_SIDE(node) = FALSE;
#ifdef TRACE
		if (debug_line>0 && ada_line >= debug_line) {
			expand_line();
		}
#endif
		break;
	
	/*
	 *-----------------------------------
	 * 5.1 Simple and compound statements
	 */
	case(as_statement):
		/* This node is used only for labelled statements, in front */
		/* of which labels are emitted. */
		expand(N_AST2(node)) ;
		break;

	case(as_statements):
		node1 = N_AST1(node) ; /* statements node */
		/* Note that if cboolean is true, the statement is not reachable 
		 * and therefore can be removed. TBSL: remove it from the list.
		 */
		cboolean = FALSE; /* first statement is always reachable */
		FORTUP(node2 = (Node), N_LIST(node1), ft1);
			if (N_KIND(node2) == as_statement)
				cboolean = FALSE;
			if (cboolean)
				delete_node(node2);
			else
				expand(node2);
			if (  N_KIND(node2) == as_raise 
		      || N_KIND(node2) == as_goto
		      || N_KIND(node2) == as_return 
		      || N_KIND(node2) == as_end
		      || N_KIND(node2) == as_terminate)
			cboolean = TRUE;
		ENDFORTUP(ft1);
		break;

	/*
	 *-------------------------
	 * 5.2 Assignment statement
 	*/
	case(as_assignment):
		expand(N_AST1(node)) ; /* variable node */
		expand(N_AST2(node)) ; /* expression */
		break;

	/*
	 *------------------
	 *  5.3 If statement
	 */
	case(as_if):
		node1 = N_AST1(node) ; /* if list node */
		node2 = N_AST2(node) ; /* else part */

		/* Remove branches guarded by static expressions */
		/* (conditional compilation) */
		tup = tup_new(0);
		FORTUP(node3 = (Node), N_LIST(node1), ft1);
			node4 = N_AST1(node3) ; /* condition */
			expand(node4);

			if (is_ivalue(node4)) {
				if (get_ivalue_int(node4) == TRUE) {
					/* This branch is guarded by TRUE: becomes the else part.
	      			 * All others branches are no longer reachable and
	       			 * may therefore be discarded.
	       			 */
					node2 = N_AST2(node3);
					break;
				}
				/* else FALSE: skip this node */
			}
			else {
				expand(N_AST2(node3));
				tup = tup_with(tup, (char *) node3);
			}
		ENDFORTUP(ft1);

		expand(node2); /* else part */

		if (tup_size(tup) == 0) {
			if (node2 == OPT_NODE)
				delete_node(node);
			else
				copy_attributes(node2, node);
		}
		else {
			N_LIST(node1) = tup;
			N_AST1(node)  = node1 ;
			N_AST2(node)  = node2 ;
		}
		break;

	/*
	 *--------------------
	 * 5.4 Case statements
	 */

	case(as_case):
	case(as_variant_decl):
		expand(N_AST1(node)) ; /* expression */
		tup1 = tup_copy(N_LIST(N_AST2(node))) ;
		/* tup_copy needed since tup1 used destructively
		 * in tup_fromb below  ds 6-25-85 
		 */
		if (tup_size(tup1) == 1) {
			/* Only one case... suppress case statement */
			node1 = (Node) tup_fromb(tup1); /* case branch */
			/* N_AST2(node1) is the list of statements for that branch */
			copy_attributes(N_AST2(node1), node);
			expand(node);
		}
		else {
			FORTUP(node1 = (Node), tup1, ft1);
				/* node1 is case node */
				node2 = N_AST1(node1) ; /* list of choices */
				expand(N_AST2(node1)) ; /* statements node */
				FORTUP(node1 = (Node), N_LIST(node2), ft2);
					/* in the inner loop node1 is choice node */
					nk = N_KIND(node1);
					if (nk == as_range_choice) {
						node3 = N_AST1(node1); /* id node */
						node4 = N_AST2(node3); /* range node */
						N_AST1(node1) = N_AST1(node4);
						N_AST2(node1) = N_AST2(node4);
						N_AST3(node1) = N_AST3(node4);
						N_AST4(node1) = N_AST4(node4);
						N_KIND(node1) = as_range;
					}
					else if (nk == as_simple_name) {
						sym1 = N_UNQ(node1); /* type name */
						tup = (Tuple) get_constraint(sym1);
						N_AST1(node1) = (Node) tup[2] ; /* lower bound */
						N_AST2(node1) = (Node) tup[3] ; /* upper bound */
						N_KIND(node1) = as_range;
					}
					else if (nk == as_simple_choice) {
						node3 = N_AST1(node1); /* lower bound */
						N_AST1(node1) = node3 ;
						N_AST2(node1) = node3 ;
						N_KIND(node1) = as_range;
					}
					else if (nk == as_others_choice || nk == as_range) {
						;
					}
					else {
						compiler_error_k(
						  "Unexpected choice in case statement: ", node1);
					}
				ENDFORTUP(ft2);
			ENDFORTUP(ft1);
		}
		break;

	/*
	 *--------------------
	 * 5.5 Loop statements
	 */

	case(as_loop):
		node1 = N_AST1(node) ; /* id node */
		node2 = N_AST2(node) ; /* iteration scheme */
		if (node2 != OPT_NODE) {
			expand(node2) ;
			if (N_KIND(node2) == as_insert) {
				propagate_insert(node2, node);
				node = N_AST1(node);
			}
		}
		nk = N_KIND(node2);
		if (nk == as_deleted)
			delete_node(node);
		else if (nk == as_raise)
			copy_attributes(node2, node);
		else { /* normal case */
			if (node1 != OPT_NODE) {
				sym1 = N_UNQ(node1); /* loop name */
				SIGNATURE(sym1) = (Tuple) FALSE;
			}
			expand(N_AST3(node)); /* statements */
			if (node1 != OPT_NODE) {
				/* Remove id node if not used */
				sym1 = N_UNQ(node1);
				if (is_generated_label(sym1) &&
				    SIGNATURE(sym1) == (Tuple) FALSE) {
					N_AST1(node) = OPT_NODE ;
				}
			}
		}
		break;

	case(as_while):
		expand(N_AST1(node)); /* condition node */
		break;

	case(as_for):
	case(as_forrev):
		expand_for(node);
		break;
	
	/*
	 *---------------------
	 * 5.6 Block statements
	 */

	case(as_block):
		node1 = N_AST1(node) ; /* id node */
		/* N_AST2(node) declaration node */
		/* N_AST3(node) statements node */
		/* N_AST4(node) handler node */
		if (is_simple_name(node1) && (N_UNQ(node1) == symbol_task_block)) {
			node2 = node_new(as_terminate); /* terminal node */
			tup = tup_new(2); 
			tup[1] = 0; 
			tup[2] = 0;
			N_VAL(node2) = (char *) tup;
		}
		else {
			node2 = node_new(as_end);       /* terminal node */
		}
		expand_block(N_AST2(node), N_AST3(node), N_AST4(node), node2);
		break;

	case(as_end):
		break;

	/*
	 *--------------------
	 * 5.7 Exit statements
	 */

	case(as_exit):
		expand(N_AST2(node)); /* condition node */
		sym1 = N_UNQ(node); /* loop name */
		SIGNATURE(sym1) = (Tuple) TRUE;
		break;

	/*
	 *----------------------
	 * 5.8 Return statements
	 */

	case(as_return):
		node1 = N_AST1(node) ; /* expression */
		if (node1 != OPT_NODE)
			expand(node1);
		break;

	/*
	 *--------------------
	 * 5.9 Goto statements
 	*/
	case(as_goto):
		break;

	/* Chapter 6. Subprograms */
	/*
	 *---------------------------
	 * 6.0 Predefined subprograms
	 */

	case(as_predef):
		sym1 = N_UNQ(node);     /* procedure name */
		sym2 = N_TYPE(node);    /* type name */
		tup = tup_new(2);
		tup[1] = (char *) N_VAL(node);
		/* integer mapped to the marker name */
		tup[2] = (char *) sym2;
		MISC(sym1) = (char *) tup;
		N_SIDE(node) = FALSE;
		break;

	case(as_interfaced):
		sym1 = N_UNQ(node);     /* procedure name */
		node1 = N_AST1(node);
		tup = tup_new(2);
		tup[1] = (char *) interface_counter++;  /* integer mapped to the
		                                               interfaced subprogram */
		/* the tuple interfaced_procedures consists of unit numbers of
		 * interfaced procedures followed by a string which contains
		 * the call to this interfaced procedure
		 */
		interfaced_procedures = tup_with(interfaced_procedures,
		  (char *) unit_number_now);
		if (streq(N_VAL(node1), "C")) {
			interfaced_procedures = tup_with(interfaced_procedures,
			  c_interface(sym1, (int) tup[1]));
		}
		else {
			interfaced_procedures = tup_with(interfaced_procedures,
			  fortran_interface(sym1, (int) tup[1]));
		}
		MISC(sym1) = (char *) tup;
		N_SIDE(node) = FALSE;
		break;

	/*
	 *----------------------
	 * 6.3 Subprogram bodies
	 */

	case(as_subprogram_tr):
		/* N_AST1(node) statements */
		/* N_AST2(node) declarations */
		/* N_AST4(node) handler */
		/* unique name of subprogram is now in the N_UNQ field of node. */
		sym1 = N_UNQ(node) ; /* subprogram name */

		if (NATURE(sym1) == na_procedure || NATURE(sym1) == na_procedure_spec) {
			/* Terminal node = return; */
			node2 = node_new(as_return);
			N_AST1(node2) = OPT_NODE ;
			N_AST2(node2) = new_name_node(sym1) ;
			N_AST3(node2) = new_number_node(0); /* depth */
		}
		else if (NATURE(sym1) == na_function
		  || NATURE(sym1) == na_function_spec) {
			/* Terminal node = raise PROGRAM_ERROR */
			node2 = new_raise_node(symbol_program_error);
		}
		else {     /* Task */
			node2 = node_new(as_terminate);
			tup = tup_new(2); 
			tup[1] = 0; 
			tup[2] = 0;
			N_VAL(node2) = (char *) tup;
		}

		/* The statement node is now in the N_AST1 field of node instead
		 * of N_AST3 field as it was when the node was as_subprogram
		 */
		expand_block(N_AST2(node), N_AST1(node), N_AST4(node), node2) ;
		N_SIDE(node) = TRUE;
		break;

	/*
	 *---------------------
	 * 6.4 Subprogram calls
	 */

	case(as_call):
	case(as_init_call):
		node1 = N_AST1(node) ; /* procedure id */
		node2 = N_AST2(node) ; /* list of arguments */
		sym1  = N_UNQ(node1) ; /* prcedure name */
		/* The following if statement is not in SETL source but was added
		 * to C version to fix renaming problem	ds 7-9-85
		 */
		if (ALIAS(sym1) != (Symbol)0) {
			sym1 = ALIAS(sym1);
			N_UNQ(node1) = sym1;
		}
		if (in_bin_ops(sym1)) {
			N_KIND(node) = as_op;
			expand(node);
		}
		else if (in_un_ops(sym1)) {
			N_KIND(node) = as_un_op;
			expand(node);
		}
		else {
			FORTUP(node1 = (Node), N_LIST(node2), ft1);
			expand(node1);
			ENDFORTUP(ft1);
			N_SIDE(node) = TRUE;
		}
		break;

	/*
	 * Chapter 7. Packages
	 *--------------------------------------------
	 * 7.2 Package specifications and declarations
	 */

	case(as_package_spec):
		/*Swap in symbol table private declarations with full declarations */
		sym1  = N_UNQ(N_AST1(node)) ; /* package name */
		private_install(sym1);

		node2 = N_AST2(node) ; /* declarations node */
		node3 = N_AST3(node) ; /* private declarations */
		expand(node2);
		expand(node3);

		N_SIDE(node) = N_SIDE(node2) | N_SIDE(node3);
		break;

	/*
	 *-------------------
	 * 7.3 Package bodies
	 */

	case(as_package_body):
		/* N_AST2(node) declarations */
		/* N_AST3(node) statements */
		/* N_AST4(node) handler */
		sym1 = N_UNQ(N_AST1(node)); /* package name */

		ud = unit_decl_get(unit_name);
		sym2 = ud->ud_unam; /* unit package */
		if (sym2 == sym1) { /* library unit */

			node4 = node_new(as_return);
			N_AST1(node4) = OPT_NODE;
			N_AST2(node4) = N_AST1(node);
			N_AST3(node4) = new_number_node(0); /* depth */
		}
		else {
			node4 = node_new(as_end);
		}

		if (N_AST3(node) == OPT_NODE) { /* statements */
			N_AST3(node) = new_statements_node(tup_new(0));
		}

		expand_block(N_AST2(node), N_AST3(node), N_AST4(node), node4);
		N_SIDE(node) = N_SIDE(N_AST2(node));
		break;

	/*
	 *----------------------------------------------------
	 * 7.4 Private type and deferred constant declarations
	 */

	case(as_use):
		delete_node(node);
		break;

	/*
	 * Chapter 8. Visibility rules
	 *--------------------------
	 * 8.5 Renaming declarations
	 */
	case(as_rename_obj):
		node1 = N_AST3(node) ; /* object node */
		expand(node1);
		N_SIDE(node) = N_SIDE(node1);
		break;

	case(as_rename_sub_tr):
		node2 = N_AST2(node) ; /* definition node */
		sym1  = N_UNQ(node) ; /* procedure name */
		tup1  = tup_copy(SIGNATURE(sym1));
		/* tup_copy needed since tup1 used in tup_fromb below */

		nk = N_KIND(node2);
		if (nk == as_attribute) {
			node2 = copy_node(node2); /* attribute node */
			sym3 = (Symbol) tup_fromb(tup1);
			N_AST2(node2) = new_name_node(TYPE_OF(sym3)) ;
			N_AST3(node2) = new_name_node(sym3) ;
			N_TYPE(node2) = TYPE_OF(sym1);
			node3 = node_new(as_return); /* return node */
			N_AST1(node3) = node2 ;
			N_AST2(node3) = new_name_node(sym1) ;
			N_AST3(node3) = new_number_node(0); /* depth */
			make_subprog_node(node, sym1, OPT_NODE,
			  new_statements_node(tup_new1((char *)node3)), OPT_NODE);
			expand(node);
		}
		else if (nk == as_entry_name) {
			node3 = node_new(as_ecall);       /* entry call */
			N_AST1(node3) = copy_node(node2); /* entry node */
			node2 = node_new(as_list);        /* arguments node */
			tup = tup_new(tup_size(tup1));
			FORTUPI(sym4 = (Symbol), tup1, nk, ft1);
				tup[nk] = (char *) new_name_node(sym4);
			ENDFORTUP(ft1);
			N_LIST(node2) = tup;
			N_AST2(node3) = node2;
			make_subprog_node(node, sym1, OPT_NODE,
			  new_statements_node(tup_new1((char *)node3)), OPT_NODE);
			expand(node);
		}
		else if (nk == as_simple_name) {
			/* handled fully by front-end. */
			delete_node(node);
		}
		else {
			compiler_error_k("Unknown kind in subprogram renaming: ", node2);
		}
		break;

	/*
	 * Chapter 9. Tasks
	 *----------------------------------------
	 * 9.1 Task specifications and task bodies
	 */

	case(as_task_spec):
		/* Separate declaration of the object from declaration of the type */
		sym1 = N_TYPE(node);   /* task type */
		sym2 = N_UNQ(node);    /* task name */
		node1 = copy_node(node); /* id node */
		N_KIND(node1) = as_task_type_spec;
		make_insert_node(node, tup_new1((char *) node1),
		  new_var_node(sym2, sym1, OPT_NODE));
		new_symbol(sym2, na_obj, sym1, (Tuple)0, (Symbol)0);
		expand(node);
		break;

	case(as_task_type_spec):
		/* Add the subprogram spec declaration in front
		 * and transform into type node.
		 */
		node2 = N_AST2(node); /* entries node */
		sym1 = N_TYPE(node); /* task type */
		sym2 = new_unique_name("task_init_proc"); /* associated procedure */
		assoc_symbol_put(sym1, TASK_INIT_PROC, sym2);
		CONTAINS_TASK(sym1) = (char *) TRUE;
		FORTUP(node1 = (Node), N_LIST(node2), ft1);
			expand(node1); /* entry node */
		ENDFORTUP(ft1);
		NATURE   (sym2) = na_task_body;
		TYPE_OF  (sym2) = symbol_none;
		SIGNATURE(sym2) = tup_new(0);
		generate_object(sym2); /* associated procedure */
		SIGNATURE(sym1) = N_LIST(node2);

		node2 = node_new(as_subprogram_decl_tr); /* subprogram node */
		N_UNQ(node2) = sym2;
		expand(node2);
		N_KIND(node) = as_type_decl;
		N_AST1(node) = new_name_node(sym1);
		N_AST2(node) = N_AST3(node) = (Node) 0;
		if (N_AST4_DEFINED(as_type_decl)) N_AST4(node) = (Node)0;
		N_SIDE(node) = FALSE;
		make_insert_node(node, tup_new1((char *)node2), copy_node(node));
		break;

	/*
	 *--------------------------------
	 * 9.2 Task types and task objects
	 */
	case(as_task):
		/* Transform it to procedure with modified statements */
		node1 = N_AST1(node); /* id node */
		/* N_AST2(node) declarations */
		/* N_AST3(node) statements */
		/* N_AST4(node) handler */
		/* N_UNQ(node1) task name */
		/* TYPE_OF(N_UNQ(node1)) type name */
		/* get associated procedure name */
		N_UNQ(node1) = assoc_symbol_get(TYPE_OF(N_UNQ(node1)), TASK_INIT_PROC);

		tup = tup_new(2);
		tup[1] = (char *) N_AST2(node); /* declaration node */
		node3 = node_new(as_end_activation);
		N_VAL(node3) = (char *) 1;      /* end activation OK */
		tup[2] = (char *) node3;
		N_KIND(node) = as_subprogram_tr;

		N_AST1(node) = new_statements_node(tup_new1((char *) new_block_node(
		  new_name_node(symbol_task_block), tup, tup_new1((char *)N_AST3(node)),
		  N_AST4(node))));
		N_AST2(node) = OPT_NODE;
		N_UNQ(node) = N_UNQ(node1);
		node2 = node_new(as_terminate); /* terminate node */
		tup = tup_new(2);
		tup[1] = (char *) 0;
		tup[2] = (char *) 2;
		N_VAL(node2) = (char *) tup;
		tup = tup_new(2);
		tup[2] = (char *) node2;        /* terminate node */
		node2 = node_new(as_end_activation);
		N_VAL(node2) = (char *) 0;   /* activation failed */
		tup[1] = (char *) node2;
		N_AST4(node) = new_statements_node( tup );
		expand(node);
		break;

	/*
	 *------------------------------------------------
	 * 9.3 Task Execution - Task Activation
	 */

	case(as_activate_spec):
		break;

	case(as_end_activation):
	case(as_create_task):
		N_SIDE(node) = TRUE;
		break;

	case(as_current_task):
		sym1 = N_UNQ(node); /* task name */
		N_SIDE(node) = FALSE;
#ifdef SHORT
		/* enable this code when and if support short integers */
		N_TYPE(node) = symbol_short_integer;
		new_symbol(sym1, na_obj, symbol_short_integer, (Tuple)0, (Symbol)0);
		make_const_node(node, sym1, symbol_short_integer, copy_node(node));
#else
		N_TYPE(node) = symbol_integer;
		new_symbol(sym1, na_obj, symbol_integer, (Tuple)0, (Symbol)0);
		make_const_node(node, sym1, symbol_integer, copy_node(node));
#endif
		break;

	case(as_entry_name):
		expand(N_AST1(node)); /*  task node */
		/* N_AST2(node)          entry node */
		node1 = N_AST3(node); /* index node */
		if (node1 != OPT_NODE) {
			node2 = copy_node(node1);
			/* Since N_AST3 and N_UNQ overlaid, clear N_AST3 field if 
			 * currently defined.
			 */
			if (N_AST3_DEFINED(N_KIND(node1)))
				N_AST3(node1) = (Node)0;
			N_KIND(node1) = as_convert;
#ifdef SHORT
			N_AST1(node1) = new_name_node(symbol_short_integer);
#else
			N_AST1(node1) = new_name_node(symbol_integer);
#endif
			N_LIST(node1) = (Tuple)0;
			N_AST2(node1) = node2 ;
#ifdef SHORT
			N_TYPE(node1) = symbol_short_integer;
#else
			N_TYPE(node1) = symbol_integer;
#endif
			expand(node1);
		}
		break;

	/*
	 *------------------------------------------------
	 * 9.4 Task Dependance - Termination of Tasks
	 */
	case(as_terminate):
		break;

	case(as_terminate_alt):
		break;

	/*
	 *------------------------------------------------
	 * 9.5 Entries, entry calls, and accept statements
	 */
	case(as_ecall):
		expand(N_AST1(node)) ; /* object node */
		node2 = N_AST2(node) ; /* arguments list */
		FORTUP(node1 = (Node), N_LIST(node2), ft1);
			expand(node1); /* argument node */
		ENDFORTUP(ft1);
		break;

	case(as_conditional_entry_call):
		/* Transform into timed entry call with delay 0 */
		/* N_AST1(node) call statement node */
		/* N_AST2(node) statements node */
		/* N_AST3(node) else part */
		node1 = node_new(as_delay_alt); /* delay alternative */
		node2 = node_new(as_delay);     /* delay expression  */
		N_AST1(node2) = new_ivalue_node(
		  rat_const(rat_fri(int_fri(0), int_fri(1))), symbol_duration);
		N_AST1(node1) = node2 ;
		N_AST2(node1) = N_AST3(node) ; /* else part */
		N_KIND(node) = as_timed_entry_call;
		N_AST3(node) = node1 ;
		expand(node);
		break;

	case(as_timed_entry_call):
		expand(N_AST1(node)) ; /* call node */
		expand(N_AST2(node)) ; /* stmt node */
		node1 = N_AST3(node) ; /* delay alternative */
		expand(N_AST1(node1)); /* delay expression  */
		expand(N_AST2(node1)); /* else part */
		break;

	case(as_accept):
		/* Replace [id_node, index_node] by an entry_name node */
		node1 = node_new(as_entry_name); /* entry name */
		N_AST1(node1) = OPT_NODE ;
		N_AST2(node1) = N_AST1(node); /* id node */
		N_AST3(node1) = N_AST2(node); /* index node */
		N_AST1(node) = node1 ;        /* entry name */
		N_AST2(node) = N_AST3(node);
		N_AST3(node) = node2 = N_AST4(node);
		N_AST4(node) = (Node) 0;
		expand(node1);

		if (node2 != OPT_NODE) {      /* body node */
			node1 = new_block_node(OPT_NODE, tup_new(0), 
			  tup_new1((char *)node2), node_new(as_exception_accept));
			expand(node1);
			N_AST3(node) = node1 ;
		}
		break;

	case(as_accept_alt):
		expand(N_AST1(node)); /* accept statement node */
		expand(N_AST2(node)); /* statements node */
		break;

	/*
	 *----------------------------------------
	 * 9.6 Delay statements, duration and time
	 */
	case(as_delay):
		expand(N_AST1(node)); /* expression */
		break;

	/*
	 *----------------------
	 * 9.7 Select statements
 	*/

	case(as_selective_wait):
		node1 = N_AST1(node); /* list of alternatives */
		FORTUP(node2 = (Node), N_LIST(node1), ft1);
			expand(node2);      /* alternative */
		ENDFORTUP(ft1);
		node2 = N_AST2(node); /* else part */
		if (node2 != OPT_NODE) {
			expand(node2); /* else part */
			node3 = node_new(as_delay_alt) ; /* delay alternative */
			N_AST2(node3) = node2 ;          /* else part */
			node2 = node_new(as_delay);
			N_AST1(node2) = new_ivalue_node(
			  rat_const(rat_fri(int_fri(0), int_fri(1))), symbol_duration);
			N_AST1(node3) = node2 ;          /* delay expression */
			N_LIST(node1) = tup_with(N_LIST(node1), (char *) node3);
		}
		break;

	case(as_guard):
		expand(N_AST1(node)); /* condition node */
		expand(N_AST2(node)); /* alternative node */
		break;

	case(as_delay_alt):
		expand(N_AST1(node)); /* expression */
		expand(N_AST2(node)); /* statements */
		break;

	/*
	 *---------------------
	 * 9.9 Abort statements
 	*/

	case(as_abort):
		FORTUP(node1 = (Node), N_LIST(node), ft1);
			expand(node1); /* id of the task to be aborted */
		ENDFORTUP(ft1);
		break;

	/*
	 * Chapter 10. Program structure and compilation issues
	 *---------------------------------------
	 * 10.1 Compilation units - Library units
	 */

	case(as_unit):
		expand(N_AST2(node)); /* unit root node */
		break;

	/*
	 *------------------------------------
	 * 10.2 Subunits of compilations units
	 */
	case(as_subprogram_stub_tr):
	case(as_package_stub):
	case(as_task_stub):
		lib_stub_put(N_VAL(node), AISFILENAME); /* N_VAL(node) is stub_name */
		stub_parent_put(N_VAL(node), unit_name);
		/* generate a slot for a fake proper body which is considered obsolete.
		 * This is due to handling of generic stubs.
		 */
		pUnits[unit_number(N_VAL(node))]->libInfo.obsolete = string_ds;/*"$D$"*/
		N_SIDE(node) = FALSE;
		break;

	case(as_separate):
		expand(N_AST2(node)); /* unit root node */
		break;

	/*
	 * Chapter 11. Exceptions
	 */
	/*
	 *------------------------
	 * 11.2 Exception handlers
	 */

	case(as_handler):
		/* Transform the handler into a "elsif test_exception or
		 * test_exception ... then statements".
		 * when others is expanded as an "elsif TRUE then statements"
		 * Do not expand statements, as they will be expanded when the if
		 * statement is.
		 */
		node1 = N_AST1(node) ; /* list of exceptions */
		tup  = N_LIST(node1) ; /* list of exception nodes */
		node1 = (Node) tup[1]; /* name of first exception */
		if (N_KIND(node1) == as_others)
			node2 = new_ivalue_node(int_const(TRUE), symbol_boolean);
		else {
			node2 = node_new(as_test_exception);     /* root of if */
			N_AST1(node2) = node1;      /* name of first exception */
			N_TYPE(node2) = symbol_boolean;
			for (nk = 2; nk <= tup_size(tup); nk++) {
				node1 = node_new(as_test_exception); /* running condition */
				N_AST1(node1) = (Node) tup[nk];      /* name of exception */
				N_TYPE(node1) = symbol_boolean;
				node2 = new_binop_node(symbol_or, node2, node1, symbol_boolean);
			}
		}

		node1 = N_AST2(node) ; /* statements */
		node3 = N_AST1(node1); /* list of statements */
		/* N_AST3(node) terminal statements node */
		N_LIST(node3) = tup_with(N_LIST(node3), (char *) N_AST3(node));

		N_KIND(node) = as_cond_statements;
		N_AST1(node) = node2 ; /* if list */
		N_AST3(node) = N_AST4(node) = (Node) 0;
		break;

	case(as_exception):
		/* Transform the handler into an if statement.
		 * Add an else part to that if: else raise.
		 * Note: if the user has provided a "when others" clause, this will
		 *       be expanded as an "elsif TRUE" branch, and optimization of
		 *       the if statement will remove the (now superfluous) else.
		 */
		node1 = N_AST1(node); /* terminal statement */
		FORTUP(node2 = (Node), N_LIST(node), ft1);
			N_AST3(node2) = copy_tree(node1);
			expand(node2); /* handler node */
		ENDFORTUP(ft1);

		tup = N_LIST(node);
		make_if_node(node, tup, new_raise_node(OPT_NAME));
		expand(node);   /* other transformations possible in this new form */
		break;

	/*
	 *-------------------------------------------------
	 * 11.5 Exceptions raised during task communication
	 */

	case(as_exception_accept):
		break;

	/*
	 * Chapter 12. Generics units
	 */
    case(as_generic_package):
      /*
       * Added here to traverse decls list to catch presence of stubs.
       * This is necessary to allocate a unit number for it to enable
       *  subsequent unit numbers to be correct.
       */
#ifdef TBSL
       expand(N_AST2(node));
#endif
       N_SIDE(node) = FALSE;
       break;
	/*
	 *---------------------------
	 * 12.3 Generic instanciation
	 */
	case(as_package_instance):
		/* This  node  indicates  a late  instantiation, i.e.  a  package
		 * instantiation  that  precedes  the  compilation of the generic
		 * package body. If the package has been seen, the instantiation is
		 * now completed. If none is needed, an empty package is created.
		 * Otherwise the missing body is treated as a stub.
		 */
		sym1 = N_UNQ(N_AST1(node)) ; /* package name */
		sym2 = N_UNQ(N_AST2(node)) ; /* generic name */
		retrieve_generic_body(sym2);
		tup = (Tuple) N_VAL(N_AST4(node));
		instance_map = (Symbolmap) tup[1];
		cboolean = (int) tup[2];
		tup = SIGNATURE(sym2);
		/* (Node) tup[2] declarations */
		/* (Node) tup[3] private part */
		node1 = (Node) tup[4];       /* body node */
		tup2 = (Tuple) tup[5]; 	   /* must_constrain generic types */

		/* check to see if this is a case where the body is a stub. */
		if (node1 == OPT_NODE) {
			char	 *stub_nam;
			tup = stubs(unit_name);
			FORTUP(stub_nam = (char *), tup, ft1);
				if (streq(unit_name_name(stub_nam), ORIG_NAME(sym2))) {
					if (!read_ais(AISFILENAME, TRUE, stub_nam, 0, TRUE)) break;
					tup  = SIGNATURE(sym2);
					node1 = (Node) tup[4];     /* body node */
					tup2 = (Tuple) tup[5];     /* must_constrain generic types*/
					break;
				}
			ENDFORTUP(ft1);
		}
		/*$TBSL retrieve_old_tree(node1); */
		retrieve_generic_tree(node1, (Node)0);
		if (node1 != OPT_NODE) {	   /* Instantiate body. */
			/* Instantiate all entities local to  the package body.
			 * Instance_map marks the entities defined in the spec, 
			 * and already instantiated.
			 */
			tup = instantiate_symbtab(sym2, sym1, instance_map);
			instance_map = (Symbolmap) tup[1];
			/* instantiate the AST itself, and complete the 
			 * instantiation of the symbol table.
			 */
			node_map = nodemap_new() ;		/* global object. */

			node2 = instantiate_tree(node1, instance_map) ; /* new body */
			N_KIND(node2) = as_package_body ;
			copy_attributes(node2, node);
			/* Node references in the symbol table 
			 * must point to the instantiated tree.
			 */
			tup1 = (Tuple) tup[3];
			update_symbtab_nodes(instance_map, tup1) ;
			tup1 = (Tuple) tup[2];
			check_priv_instance(tup2, instance_map) ;
			/* The full declarations of private entities must be updated as
			 * well, for the generic package and all inner packages.
			 */
			/*  loop for sym3 in tup1 do
			 *      private_decls(instance_map(sym3)) =
			 *	     update_private_decls(sym3, instance_map) ;
			 *  end loop ;
			 */
			FORTUP(sym3 = (Symbol), tup1, ft1);
				sym4 = symbolmap_get(instance_map, sym3);
				private_decls(sym4) =
				  (Set)update_private_decls(sym3, instance_map);
			ENDFORTUP(ft1);
			N_KIND(node) = as_package_body ;
			mint(node);
			expand(node) ;
		}
		else if ( ! cboolean) {
			/* assume that none will be seen, and build empty package body.*/
			N_KIND(node) = as_package_body ;
			N_AST1(node) = new_name_node(sym1) ;
			N_AST2(node) = OPT_NODE;
			N_AST3(node) = OPT_NODE;
			N_AST4(node) = OPT_NODE;
			expand(node) ;
		}
		else
			user_error("Separately compiled generics not supported ") ;
		break;

	case(as_function_instance):
	case(as_procedure_instance):
		/* Same as previous one, for subrograms. Here the body is always
		 * needed.
		 */
		/* Unpack instantiation information, attached to N_VAL of node. */
		tup = (Tuple)N_VAL(N_AST4(node));
		type_map = (Symbolmap)tup[1];
		sym1 = N_UNQ(N_AST2(node)) ; /* generic name */
		retrieve_generic_body(sym1);
		tup  = SIGNATURE(sym1);
		node1 = (Node) tup[3];       /* body node */
		tup1 = (Tuple) tup[4];	   /* must_constrain */

		/* check to see if this is a case where the body is a stub. */
		if (node1 == OPT_NODE) {
			char	 *stub_nam;
			tup = stubs(unit_name);
			FORTUP(stub_nam = (char *), tup, ft1);
				if (streq(unit_name_name(stub_nam), ORIG_NAME(sym1))) {
					if (!read_ais(AISFILENAME, TRUE, stub_nam, 0, TRUE)) break;
					tup = SIGNATURE(sym1);
					node1 = (Node) tup[3];       /* body node */
					tup1 = (Tuple) tup[4];	     /* must_constrain */
					break;
				}
			ENDFORTUP(ft1);
		}

		if (node1 != OPT_NODE) {
			/*$TBSL retrieve_old_tree(node1); */
			retrieve_generic_tree(node1, (Node)0);
			instantiation_code = N_LIST(N_AST3(node)) ;
			instantiate_subprog_tree(node, type_map) ;
			/* Take the subprogram created by the instantiation and reformat
			 * the spec node to be of a form as_procedure_tr (as_function_tr) 
			 * with the formal part detached from the tree. Move up the id_node
			 * (subprogram name) info to the specfication node.
			 */
			node2 = N_AST1(node);
			node3 = N_AST1(node2);
			N_KIND(node) = as_subprogram_tr;
			N_AST1(node) = N_AST3(node);
			N_UNQ(node) = N_UNQ(node3);
			/* add instantiation code to declarative part of subprogram.
	  		 * this is not strictly correct, as bounds checks should be
	  		 * elaborated outside of the subprogram body. To be cleaned up
	  		 * later.
	  		 */
			ntup = tup_add(instantiation_code, N_LIST(N_AST2(node))) ;
			tup_free(instantiation_code) ;
			N_LIST(N_AST2(node)) = ntup ;

			check_priv_instance(tup1, instance_map) ;
			mint(node);
			expand(node) ;
		}
		else
			user_error("Separately compiled generics not supported ") ;
		break;

	case(as_check_bounds):
		sym1 = N_UNQ(N_AST1(node)) ; /* generic type */
		sym2 = N_UNQ(N_AST2(node)) ; /* actual type */
		if (is_discrete_type (sym2)) {
			node1 = new_attribute_node(ATTR_T_FIRST, new_name_node(sym1),
			  OPT_NODE, sym1);
			node2 = new_attribute_node(ATTR_T_LAST, new_name_node(sym1),
			  OPT_NODE, sym1);
			node3 = new_attribute_node(ATTR_T_FIRST, new_name_node(sym2),
			  OPT_NODE, sym2);
			node4 = new_attribute_node(ATTR_T_LAST, new_name_node(sym2),
			  OPT_NODE, sym2);
			/*$ TBSL: some constant folding. */
			make_if_node(node,
			  tup_new1((char *) new_cond_stmts_node(
			  new_binop_node(symbol_or,
			  new_binop_node(symbol_ne,
			  node1,
			  node3,
			  symbol_boolean),
			  new_binop_node(symbol_ne,
			  node2,
			  node4,
			  symbol_boolean),
			  symbol_boolean),
			  new_raise_node(symbol_constraint_error)  )
			  ),
			  OPT_NODE);
		}
		else if (is_fixed_type (sym2)) {

			/* conversion of fixed is possible if they have the same accuracy */
			if (rat_neq ( RATV (get_ivalue
			  (((Node) numeric_constraint_delta (get_constraint(sym1))))),
			  RATV (get_ivalue
			  (((Node) numeric_constraint_delta (get_constraint(sym2))))))) {
				make_raise_node(node, symbol_constraint_error);
				USER_WARNING(
	"Due to difference in fixed point accuracy, conversion of array will raise",
				  " CONSTRAINT_ERROR"); 
			}
		}
		else if (is_float_type (sym2)) {

			/* conversion of float is possible if they have the same floating
			 * point accuracy
			 */
			if ( INTV (get_ivalue (((Node) numeric_constraint_delta
			  (get_constraint(sym1))))) != INTV (get_ivalue
			  (((Node) numeric_constraint_delta (get_constraint(sym2)))))) {
				make_raise_node(node, symbol_constraint_error);
				USER_WARNING(
"Due to difference in floating point accuracy, conversion of array will raise",
				  " CONSTRAINT_ERROR"); 
			}
		}
		expand(node);
		N_SIDE(node) = FALSE;
		break;

	case(as_check_discr):
		node1 = N_AST1(node) ;
		sym1  = N_UNQ(N_AST2(node)) ; /* type name */
		sym2  = N_UNQ(N_AST3(node)) ; /* dscriminant name */
		make_if_node(node,
		  tup_new1((char *) new_cond_stmts_node(
		  new_binop_node(symbol_ne,
		  node1,
		  new_discr_ref_node(sym2, sym1),
		  symbol_boolean),
		  new_raise_node(symbol_constraint_error)  )
		  ),
		  OPT_NODE);
		expand(node);
		N_SIDE(node) = FALSE;
		break;

	case(as_expanded):
		/* This node removed, WITHOUT expanding its descendant! */
		node1 = N_AST1(node); /* son node */
		copy_attributes(node1, node);
		break;

	/*
	 * Chapter 13. Representation clauses
	 *--------------------
	 * 13.2 Length clauses
	 */

	case(as_length_clause):
	case(as_enum_rep_clause):
	case(as_rec_rep_clause):
		delete_node(node);
		N_SIDE(node) = FALSE;
		break;

	case(as_opt):
		break;

	case(as_pragma):
	case(as_arg):
	case(as_enum):
	case(as_num_decl):
	case(as_int_type):
	case(as_float_type):
	case(as_fixed_type):
	case(as_array_type):
	case(as_record):
	case(as_discr_ref):
	case(as_simple_name):
	case(as_labels):
	case(as_ivalue):
	case(as_null):
	case(as_subprogram_decl_tr):
	case(as_private_decl):
	case(as_rename_ex):
	case(as_rename_pack):
	case(as_entry):
	case(as_entry_family):
	case(as_except_decl):
	case(as_raise):
	case(as_test_exception):
	case(as_generic_function):
	case(as_generic_procedure):
	case(as_generic_formals):
		N_SIDE(node) = FALSE;
		break;

	default:
		compiler_error_k( "Illegal kind of node in expand: ", node);
	}
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.