CHAPTER 22


				EXPRs, STATEMENTs, QUANTIFIERs

				   And DECLARATIONs In ICL



	  This chapter documents in detail all of ICL excluding its type-
	  constructors and type-specific EXPR forms.  Those matters are dealt
	  with in chapter 23.

	  We begin with general EXPR forms, which are all EXPR notations except
	  for type-specific notations.  We will encounter the parts-of-speech
	  BOP, UOP, and RHUOP in the formation of EXPRs.  We then explore
	  STATEMENTs, QUANTIFIERs, and finally DECLARATIONs.



22.1
General EXPR Forms

22.1.1
Operators

    EXPR  BOP  EXPR	->	  EXPR

	  This rule supports the ~infix notation for combining EXPRs via BOPs
	  (Binary OPerators).  An example BOP is "+".  This BOP is an ~infix
	  operator because it sits ~in ~between its operands.	 The two operands
	  for any BOP are the two EXPRs that appear to the left and right of the
	  BOP, as our rule indicates.

	  Example:
		    Since "+" is a BOP and each of "1" and "2" are EXPRs, our rule
		    supports the familiar expression:

				1 + 2

		    as in:

				1	  +	    2
			    EXPR	 BOP	  EXPR

	  Example:
		    The expression

				1 + 2 * 3

		    is an EXPR because:

				1  is an EXPR
				+  is a BOP, and
				2*3 is an EXPR.

		    "2*3" is an EXPR because:

				2  is an EXPR,
				*  is a BOP, and
				3  is an EXPR

		    Notice how we bind together the "2*3" prior to binding the "+"
		    with "1" and "2*3".

	  A note about "Binding Order" or "Operator Precedence":

		    The fact that "*" binds before "+" is based on the notation of
		    "binding order" or "operator precedence".  That is, the EXPR

				1 * 2 + 3 * 4		is interpreted as:

				(1*2) + (3*4)

		    because the operator "*" binds before the operator "+".

		    You will see that "*" binds before "+" when you look at the
		    rules for the BOPs "+" and "*":	 (They will be introduced more
		    completely later):

				*	  ->	    BOP[3]
				+	  ->	    BOP[4]

		    The 3 associated with the "*" is lower than the 4 associated
		    with the "+".	 Therefore, the "*" (3) will bind before the
		    "+" (r).

		    You can enclose any EXPR within parentheses to override our
		    default binding orders.

		    The notation of operator precedence allows a minimal use of
		    parentheses, and has been used in arithmetic and mathematics
		    for years.

		    An implementation of operator precedence appears in Chapter 3.

	  NOTE:   We generally do NOT guarantee order of evaluation, e.g., the
		    left EXPR might be evaluated AFTER the right EXPR.

		    For example, our EXPR-BOP-EXPR rule in Chapter 8 in fact
		    evaluates the righthand operand before the lefthand one.


    UOP  EXPR		->	  EXPR

	  This rule supports ~prefix ~unary operators.	A ~unary operator, like
	  the "-" in "-5", takes in only one value, the "5" in "-5".  "-" is a
	  ~prefix operator because it appears ~before its input (5).

	  UOPs (Unary OPerators) have "binding orders" like BOPs (Binary
	  OPerators) do.

	  ICL presently has only one UOP syntactically:

		    -		->	  UOP[1]

	  Its binding order is 1 (which is enclosed here in square brackets).
	  This is lower than the binding orders of all BOPs.	Thus, our unary
	  minus "-" binds first, before any BOPs.

	  For example:

		    -1	is	  -1

		    -1+2	is	  (-1)+2  because the unary "-" binds before the
						    "+" BOP.

		    -(1+2)	is	  is -3, because EXPRs in parentheses always bind
					  first.


    EXPR  RHUOP		->	  EXPR

	  The rule supports ~postfix ~unary operators (RHUOPs, short for
	  RightHand Unary OPerators).	 Examples of RHUOPs will appear shortly.

	  RHUOPs have what we call ~indefinite binding order.	 We will introduce
	  this notion shortly as we present ICL's BOPs.  RHUOPs, like BOPs of
	indefinite binding order, tend to bind ~last.



    ( EXPR )		->	EXPR

	This rule allows you to override ICL's default binding orders.  EXPRs
	  enclosed in parentheses always bind first.

	  Examples:
		    1 + 2 * 3	  is 7, or 1+(2*3) by ICL's default binding
				orders.

		(1+2) * 3	is 9.  Here, "+" binds before "*" because the
				EXPR involving "+" is enclosed in parentheses.


22.1.2
BOPs

	The BOPs following are presented in order from the tightest (lowest)
	binding order to the weakest (highest) binding.

	For each BOP, we will specify its binding order, enclosed in square
	brackets, like we did in Chapter 3.  We will also specify the ~types
	of data on which it can apply.  Recall that INTs (integers) are whole
	numbers, and that REALs include numbers with fractions.  A POINT is a
	two-dimensional vector, or complex number.  BOOLeans are binary values,
	TRUE or FALSE.  The type TEXT is any chunk of text enclosed in single
	quotes, e.g., 'Monday'.


    ^		->	BOP[2]

	Exponentiation.  It works on the following types:

		~INT   ^   ~INT		->	~INT
		~REAL  ^   ~INT		->	~REAL
		~REAL  ^   ~REAL	->	~REAL

	One can also write "~INT ^ ~REAL" because the INT can be coerced to
	a REAL.

    *		->	BOP[3]

	Multiplication.  It works on types as follows:

		~INT   *  ~INT		->	~INT	(integer multiply)
		~REAL  *  ~REAL		->	~REAL	(floating multiply)
		~POINT *  ~POINT	->	~POINT	(complex multiply)

		~REAL  *  ~POINT	->	~POINT	(scalar multiply)
		~POINT *  ~REAL		->	~POINT	(scalar multiply)

	Multiplication of points acts by interpreting POINTs as complex
	numbers.  Multiplication does not occur independently for each
	coordinate.

	The final two rules multiply each coordinate of the POINT by the same
	REAL value.


    /		->	BOP[3]

	Division.  It works on types as follows:

		~INT   /  ~INT		->	~INT	(integer divide)
		~REAL  /  ~REAL		->	~REAL	(floating divide)
		~POINT /  ~POINT	->	~POINT	(complex division)

		~POINT /  ~REAL		->	~POINT	(scalar divide)

	Division on points acts by interpreting POINTs as complex numbers.
	Division does not occur independently for each coordinate.

	For INTegers, division is like that for REALs, except that the
	fractional part is lost.

	The final rule divides each coordinate of the POINT by the same REAL.


    +		->	BOP[4]

	Addition.  It operates on types as follows:

		~INT   +  ~INT		->	~INT	(integer add)
		~REAL  +  ~REAL		->	~REAL	(floating add)
		~POINT +  ~POINT	->	~POINT	(coordinate-wise)

	Addition on points operates independently on each coordinate.  You can
	still think of POINTs as complex numbers, as this is complex addition.


    -		->	BOP[4]

	Subtraction.  It operates on types as follows:

		~INT   -  ~INT		->	~INT	(integer subtract)
		~REAL  -  ~REAL		->	~REAL	(floating subtract)
		~POINT -  ~POINT	->	~POINT	(coordinate-wise)

	Subtraction on points operates independently on each coordinate.  You
	can still think of POINTs as complex numbers, as this is complex
	subtraction.


    &		->	BOP[5]

	ANDing.  It operates on types as follows:

		~BOOL  &  ~BOOL		->	~BOOL
		~INT   &  ~INT		->	~INT

	ANDing on BOOLeans yields TRUE exactly when both of the given BOOLs are
	TRUE.

	ANDing on INTegers occurs bitwise.  The high-order (leftmost) bit of
	the two INTs are ANDed so as to produce the
	high-order bit of the resulting INTeger.  A 1 ~and a 1 yields 1, and
	all other combinations yield 0.  This occurs not only for the
	high-order bit, but for other corresponding bits as well.

	Examples:

		Each of the EXPRs "A<B" and "C<D" are BOOLeans.  Each
		represents a TRUE or FALSE.  The AND of these two EXPRs:

			A < B  &  C < D

		is TRUE precisely when both A is less than B and C is less than
		D.

		Two integers, shown with their binary equivalents, ~and as
		follows:

			6  &  3		is 2
			110   011	is 010

			The leftmost bit in each are ANDed together, a 1 and a
			0 in this example, yielding a 0.
			The middle bits are both on, so their AND is a 1.  The
			rightmost bits AND together to form a 0.  Thus, the
			resulting binary number is 010, which is 2 in base 10.


    !		->	BOP[6]

	ORing.  It operates on types as follows:

		~BOOL  !  ~BOOL		->	~BOOL
		~INT   !  ~INT		->	~INT

	OR on BOOLeans is FALSE exactly when both of the given BOOLeans are
	both FALSE.  The result is TRUE if either of the given BOOLeans (or
	both) are TRUE.

	INTeger ORing occurs bitwise, like ANDing does.


    xor		->	BOP[7]

	XORing.  It works on types just like & and ! do:

		~BOOL  xor  ~BOOL	->	~BOOL
		~INT   xor  ~INT	->	~INT

	XOR on BOOLeans yields TRUE exactly when the two BOOLean values differ.
	INTeger XOR occurs bitwise.


    bit		->	BOP[7]

	Extract a single bit from an integer:

		~INT  bit  ~INT		->	~BOOL

	This extracts a single bit from within the lefthand integer.  We number
	bits from 0 to 31, right-to-left (i.e., by the natural powers of 2).
	The righthand integer selects which bit to look at, within the lefthand
	integer.  The resulting BOOLean EXPR
	yields TRUE if the selected bit is on, and FALSE otherwise.


    shiftl	->	BOP[7]

	Shift left:

		~INT  shiftl  ~INT	->	~INT

	The lefthand integer is shifted leftward by some number of bits.  That
	shifted lefthand integer is the result.  The
	righthand INT tells how many bits to shift by.  (A negative value in
	the righthand INT causes rightward shifting).

	Bits of value 0 are shifted in to take the place of bits that have
	moved from the far right (or left).


    shiftr	->	BOP[8]

	Shift right:

		~INT  shiftr  ~INT	->	~INT

	The lefthand INT is shifted rightward by some number of bits.  The
	righthand INT specifies how many bits to shift by.  A negative value
	in the righthand INT causes leftward shifting.


    min		->	BOP[8]

	Minimum.  It operates on types as follows:

		~INT   min  ~INT	->	~INT
		~REAL  min  ~REAL	->	~REAL
		~POINT min  ~POINT	->	~POINT

	For INTs and REALs, yield the operand having the lowest value.

	For POINTs, yield a new point each of whose coordinates is the MIN of
	the corresponding coordinates of the two given POINTs.  That is, the X-
	coordinate of the result is the MINimum of the two X-coordinates in the
	two given POINTs.  Similarly, the Y-coordinate in the result is the
	MIN of the the two given POINTs' Y-coordinates.

	  Example:
		    (1#2)  MIN  (2#0)	    ->	1#0

		    (The "#" is used to form POINTs, as we will see shortly, given
		    the X and Y-coordinates on the left and right side of the "#").


    max	    ->	BOP[8]

	  Maximum.	It operates on types as follows:

		    ~INT   max  ~INT	    ->	~INT
		    ~REAL  max  ~REAL	    ->	~REAL
		    ~POINT max  ~POINT	    ->	~POINT

	  This is exactly like MIN, except that the larger of the two numbers is
	  used instead of the smaller of the two numbers.

	  Example:
		    (1#2)  MAX  (2#0)	    is	2#2


22.1.3
More BOPs:	Those Having ~Indefinite Binding Order

	  The following BOPs have what we call ~indefinite binding order.	 They
	  will bind any possible way, but they tend to bind after all other BOPs
	  (shown up to now) have bound.

	  We can therefore think of the indefinite binding order as being
	  higher than the binding order of other BOPs.

	  BOPs of indefinite binding order are flexible in that this natural
	  binding order will be violated so as to maintain "type consistency".
	  That is, if type consistency can be achieved only by having an
	  indefinite BOP bind ~before a regular BOP, such will occur.

	  Also, if a strictly left-to-right binding would force a loss of type
	  consistency, then another binding order will be chosen.  We can say
	  simply that indefinite BOPs bind after other BOPs as much as possible,
	  and as left-to-right among themselves as possible, governed by type
	  consistency.

	  For example, the BOP "#" has indefinite binding order.  In the
	  following example, the "*" binds before the "#", following the natural
	  tendency:

		    1 * 2 # 3	  will bind as

		    (1*2) # 3

	  In contrast, the following example violates the natural binding
	  order.  The "#" binds before the "*":

		    1 # 2 * 3 # 4	     will bind as

		    (1#2) * (3#4)

	  Notice how in the first case that "*" binds before "#", but in the
	  second example, the "#"s bind before the "*"

	  The latter example exposes a violation of the natural binding order.
	  The natural binding order would bind the "*" first, and would render
	  our expression as:

		    1 # (2*3) # 4

	  One of the two "#"s would be forced to take in a POINT, which is not
	  possible.	 ("#" takes in only REALs).

	  Also, a left-to-right binding:

		    ( 1 # 2 * 3 ) # 4

	  would violate type consistency, as the final "#" would be
	  forced to combine the impossible, a POINT and a REAL.

	  Following are ICL's BOPs of indefinite binding order.


    #		->	BOP[indefinite]

	Point synthesis.  It operates on types as follows:

		~REAL  #  ~REAL		->	~POINT

	This forms a POINT from an X- and Y-coordinate, X#Y.

	This BOP has the unusual property that it also has meaning on the
	lefthand side of an assignment statement.  It unloads both coordinates
	into variables.

	Example:
		1 # 2	is the point whose X-coordinate is 1 and whose Y-
			coordinate is 2.

	Example:
		U # V  :=  a point ;

		sets the variable U to the given point's X-coordinate, and sets
		    V to the point's Y-coordinate.


    <$		->	BOP[indefinite]

	Left append.  It operates on lists (Section 23.3).

	Assume that "LIST" is a type defined by:

		TYPE  LIST = { ELEMENT }  ;

	That is, LIST is a list (or set) of ELEMENTs.  This BOP can be used
	as follows:

		~ELEMENT  <$  ~LIST	->	~LIST

	This resulting list has ~element as its first element, and all of the
	given list as its tail.  The resulting list has one more element than
	the given list.  (The result's second element is the given
	  list's first element, and so on).

	This BOP has the unusual property that it also has meaning on the
	lefthand side of an assignment statement.

	Example:
		If X is a list of INTegers, say

			{ 10 ; 20 ; 30 ; 40 ; 50 }
		then
			0  <$  X

		is the list:

			{ 0 ; 10 ; 20 ; 30 ; 40 ; 50 }

		and the list

			-10  <$  0  <$  X

		is the list:

			{ -10 ; 0 ; 10 ; 20 ; 30 ; 40 ; 50 }

	Example:
		If X is a list of INTegers, and I is an INTeger variable, then
		the assignment:

			I  <$  X   :=   X ;

		sets I to the first element of X, and resets X itself to be
		the tail of the given list X.  If X starts out as:

			{ 10 ; 20 ; 30 ; 40 ; 50 }

		then the assignment sets I to 10, and sets X to the list:

			{ 20 ; 30 ; 40 ; 50 }



    $>		->	BOP[indefinite]

	Right append.  Like "<$", this BOP deals with lists.  Assume LIST is
	declared by:

		TYPE  LIST = { ELEMENT }  ;

	The right-append operator works on types as follows:

		~LIST  $>  ~ELEMENT	->	~LIST

	The resulting list is the given list but with one element appended to
	its right end.

	Example:
		If X is a list of INTegers, say

			{ 10 ; 20 ; 30 ; 40 ; 50 }
		then
			X  $>  60

		is the list:

			{ 10 ; 20 ; 30 ; 40 ; 50 ; 60 }


    $$		->	BOP[indefinite]

	List concatenation.  Assume that LIST is a type declared by:

		TYPE  LIST = { ELEMENT }  ;

	This concatenate operator works on types as follows:

		~LIST  $$  ~LIST	->	~LIST

	The resulting list consists of all elements of the first list (in
	order) followed by all elements of the second list (in order).

	Example:
		If X is a list of INTegers, say

			{ 10 ; 20 ; 30 ; 40 }
		then
			X $$ X

		is the list:

			{ 10 ; 20 ; 30 ; 40 ; 10 ; 20 ; 30 ; 40 }


    =		->	BOP[indefinite]
    <>		->	BOP[indefinite]

	Equals and not-equals.  These BOPs compare entities and yield a BOOLean
	value indicating the truth of the comparison.  They operate on types
	as follows:

		~INT   =  ~INT		->	~BOOL
		~REAL  =  ~REAL		->	~BOOL
		~POINT =  ~POINT	->	~BOOL	(equal coordinatewise)

		~BOOL  =  ~BOOL		->	~BOOL
		~TEXT  =  ~TEXT		->	~BOOL

	These same capabilities exist for "<>" in place of "=".  "<>" is
	exactly NOT "=".

	Each of these two BOPs operate also on scalar-types and disk-types
	(Sections 23.8 and 23.9).


    <		->	BOP[indefinite]
    =<		->	BOP[indefinite]
    >		->	BOP[indefinite]
    >=		->	BOP[indefinite]

	These operators are respectively "less than", "less than or equal",
	"greater than", and "greater than or equal".

	An easy way to remember the "... or equal" operators, which involve the
	"=" character, is that they ~avoid forming arrows.

	These BOPs operate on types as follows:

		~INT   <  ~INT		->	~BOOL
		~REAL  <  ~REAL		->	~BOOL
		~POINT <  ~POINT	->	~BOOL

	Although we don't list them here, these same rules apply for the other
	  three comparator BOPs: "=<", ">", and ">=".

	  POINTs are compared by comparing each coordinate independently.
	  Both have to be true for the same to be said of the point.  For
	  example:

		    A < B

	  implies that

		    A.X < B.X   and   A.Y < B.Y

	  In other words, "A<B" implies that the point A resides to the ~left of
	  and ~below the point B.  This "<" ordering on POINTs is a ~partial
	  ~order:  It is possible that all of the following are simultaneously
	  false:

		    A = B
		    A < B
		    A > B

	  This interpretation for comparisons is consistent with the MIN and
	  MAX operators on POINTs shown earlier.	That is, the following are
	  always true:

		    A MIN B	  =<	A
		    A MIN B	  =<	B
	  and
		    A	 =<  A MAX B
		    B	 =<  A MAX B



    \	 ID	    ->	BOP[indefinite]

	  This notation provides a way to call functions in an ~infix manner.
	  This BOP calls the binary, value-returning function whose name is given
	  by the ID.  That is, the EXPR

		    param1	\function_name  param2

	  acts exactly as does:

		    function_name( param1 , param2 )

	  For example, we can call the function named PAINTED via either:

		    picture	 \PAINTED  red
	  or
		    PAINTED( picture , red )

	  This infix notation for calling functions is very helpful for clarity.
	  It is used profusely in practice.

	  For example, Section 9.8 introduced the \OFF_OF function,
	  used in expressions like:

		    1	 \OFF_OF  "register" 3

	  Expressions like this appeared in instructions, such as:

		    LOAD( 2 , 1 \OFF_OF 3 );


22.1.4
UOPs and RHUOPs

	  UOPs and RHUOPs are distinct in that a UOP precedes its operand whereas
	  an RHUOP follows its operand.  UOPs are ~prefix unary operators, and
	  RHUOPs are ~postfix unary operators.



    -		    ->	UOP[1]

	  Negation.	 This UOP operates on types as follows:

		    - ~INT		  ->	    ~INT
		    - ~REAL		  ->	    ~REAL
		    - ~POINT	  ->	    ~POINT
		    - ~BOOL		  ->	    ~BOOL

	  For INTegers and REALs, "-" performs arithmetic negation, turning a
	  positive number into a negative number or vice versa.  For POINTs, "-"
	  negates each coordinate independently.	Thus:

		    -(1#2)		  is the point	-1 # -2

	  For BOOLeans, it performs logical negation:  A TRUE becomes FALSE and a
	  FALSE becomes TRUE.


    \ ID	    ->	RHUOP

	  This rule provides a way for calling a unary, value-returning function
	  in a postfix manner.	For example, the EXPR

		    param1	\function_name

	  means the same as

		    function_name( param1 )

	  Sometimes, calling a unary function in a postfix manner lends clarity
	  to the program listing.  In the mathematical discipline of group
	  theory, postfix notation is generally used for the application of
	  operators.

	  For example, suppose we have two unary functions that manipulate
	  pictures, ROT_CW (rotate clockwise) and MIRROR_X (mirror about the
	  X-axis).	The EXPR:

		    picture	 \ROT_CW  \MIRROR_X

	  reads like what it does.  It first applies ROT_CW and then applies
	  MIRROR_X.

	  In the standard prefix notation, this reads as:

		    MIRROR_X( ROT_CW( picture ) )

	  The order of application is ~not left-to-right, and therefore may be
	  less clear.


    sorted_by  ID : EXPR  increasing    ->	RHUOP
    sorted_by  ID : EXPR  decreasing    ->	RHUOP
    sorted_by  ID : EXPR  non_increasing	->	RHUOP
    sorted_by  ID : EXPR  non_decreasing	->	RHUOP

	  These RHUOPs sort elements in a list.  These will be described in
	  Section 23.3.

	  These SORTED_BY constructs are cast as RHUOPs for generality.  To
	  understand them, imagine always an EXPR appearing to the left of this
	  notation, as in:

		    ~EXPR	sorted_by ID: EXPR increasing

	  This is itself an EXPR (due to our rule:

		    EXPR  RHUOP	  ->	    EXPR.

	  Any RHUOP preceded by an EXPR is always an EXPR).

	  For example, given a set of PEOPLE, we acquire the same sorted by
	  increasing age via:

		    PEOPLE	 SORTED_BY P: P.AGE  INCREASING



22.1.5
Cumulative Application Of BOPs

    BOP  EXPR  QUANTIFIER	  ->	    EXPR

	  Apply the BOP repeatedly so as to combine all the values yielded by
	  the EXPR's evaluation upon each iteration cuased by the QUANTIFIER.

	That is, if the QUANTIFIER causes N iterations, we denote the values
	yielded by the EXPR on each iteration as:

		EXPR(1) , EXPR(2) , ... , EXPR(n)

	This rule yields the value:

		EXPR(1)  bop  EXPR(2)  bop  ...  bop  EXPR(n)

	or more precisely, the grouping is always left-to-right, as in

		(   (  ( EXPR(1)  bop  EXPR(2) ) ...  )  bop  EXPR(n) )

      ---------------- Parentheses in previous paragraph around "1", "2"
      ----------------  and "n" mean subscripting! ----------------------------

	This usage of a BOP is called the ~cummulative application of the BOP.

	In case the QUANTIFIER causes only one iteration, yield simply the
	EXPR's value attained on that first iteration.

	  In case the QUANTIFIER causes zero iterations, yield NIL, 0, or FALSE.

	  The type requirements of this rule may be stated as follows:

		    It must be possible to declare a temporary variable, say T,
		    such that both of the following are legal:

			1)	T :=	EXPR	;		and

			2)	T :=	T  BOP  EXPR  ;

	  Generally, if the BOP maps two instances of the same type back to an
	  instance of that same type, these requirements are certainly met.

	  Example:
		    The EXPR:

				+    I     FOR I FROM 1 TO 10;

			     BOP  EXPR	    QUANTIFIER

		    represents the sum of integers from  1 to 10.  (See Section
		    22.3.1 for the QUANTIFIER	 "FOR I FROM 1 TO 10;").  When the
		    BOP is a "+", as in this example, this entire rule denotes the
		    mathematician's sigma notation for forming sums over sets.
		This example is equivalent to:

			1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10

		The EXPR

			*  I  FOR I FROM 1 TO 10;

		forms the produce of the integers from 1 to 10.

		If PS is a list of POINTs, and P is a variable of type POINT,
		the following EXPR sums up all the POINTs in PS:

			+  P  FOR P $E PS;

		The QUANTIFIER "FOR P $E PS;" reads as ~for ~each ~P ~in ~PS.

		The following EXPR yields the number of points in PS:

			+  1  FOR P $E PS;

		The "average" over the set of POINTs PS can be specified as:

			( +  P  FOR P $E PS; )   /   ( +  1  FOR P $E PS; )

	Example:
		Since any binary function can be called as though it were a
		BOP, due to the rule:

			\ ID		->	BOP		,

		you can actually use this "cummulative" construct for operators
		of your own making.

		For example, suppose we have a type PICTURE, and an operator
		SUPERIMPOSE which maps two PICTUREs to one PICTURE.  We
		can form the superimposed union over a ~set of PICTUREs with:

			\SUPERIMPOSE   PICTURE   FOR PICTURE $E PICTURES;


	A variation on this cummulative operator syntax is offered by the
	semantically identical rule:

    QUANTIFIER  BOP  EXPR	->	EXPR

	This rule puts the QUANTIFIER first, which can be used to place
	emphasis on the QUANTIFIER.  (Use one or the other rule so as to stress
	the BOP or the QUANTIFIER).

	This second rules chooses as its EXPR the largest possible
	amount of text, so that:

		QUANTIFIER  +  A + B

	groups as:

		QUANTIFIER  +  (A+B)

	and not as

		( QUANTIFIER  +  A )  +  B,

	which yields a different result.


22.1.6
General EXPR Forms Beyond BOPs, UOPs, and RHUOPs

    do  STATEMENT  give  EXPR		->	EXPR

	Peform the STATEMENT immediately before evaluating the EXPR.

	Example:
		The EXPR

			DO	R:= SQRT( X*X + Y*Y ) ;

			GIVE	R*COS(THETA) # R*SIN(THETA)

		assigns a value into R (the DO part) and then yields a value
		that is computed by referencing R twice.

		This entire EXPR not only yields a value (the GIVE), but it has
		the side-effect of setting the variable R (the DO).

	This construct is most helpful when context demands an EXPR
	but you want to perform some STATEMENT prior to delivering the
	EXPR.

	For example, a function that returns a value must have an EXPR for its
	body (Section 22.4.3).  That is, we might declare a function
	as follows:

		DEFINE	F( X,Y,THETA: REAL ) = REAL:
		   some EXPR
		ENDDEFN

	The EXPR that makes up the body may be rendered with the DO...GIVE
	construct as in:

		DEFINE	F( X,Y,THETA: REAL ) = REAL:
		   DO    R:= SQRT( X*X + Y*Y ) ;
		   GIVE  R*COS(THETA) # R*SIN(THETA)
		ENDDEFN

	NOTE about binding order:

		This rule takes as its EXPR (following the GIVE) as much as
		possible:  Therefore:

			DO  STATEMENT  GIVE  I + J

		binds as

			DO  STATEMENT  GIVE  (I+J)

		as opposed to:

			( DO  STATEMENT  GIVE  I )  + J


    giving  EXPR  do  STATEMENT  end	->	EXPR

	Perform the STATEMENT immediately after evaluating the EXPR.  The
	STATEMENT does not affect the value of the EXPR.

	Example:
		The EXPR:

			GIVING  TIME  DO  TIME:= TIME+1;  END

		yields the value presently in TIME, but leaves that variable
		holding a value one greater.


    begin  DECLARATION  EXPR  end	->	EXPR

	This rule supplies new local variables for use within the EXPR between
	the BEGIN and the END.  The DECLARATION specifies the new local
	variables.

	We will see shortly the rules that form DECLARATIONs.  Only the
	declaration of variables is allowed here (the VAR declaration).

	For example, let's use the EXPR

		    DO	R:= SQRT( X*X + Y*Y ) ;

		    GIVE	R*COS(THETA) # R*SIN(THETA)

	  This EXPR presumes the existence of a variable R.  Let's declare R
	to be local for this EXPR.  We surround this EXPR and the declaration
	of R by a BEGIN...END:

		BEGIN

		    VAR  R = REAL;

			DO	R:= SQRT( X*X + Y*Y ) ;

			GIVE	R*COS(THETA) # R*SIN(THETA)
		END


	Most function bodies are formed this way.  A BEGIN...END surrounds
	a DO...GIVE, as in.

	    DEFINE  F( X,Y,THETA: REAL ) = REAL:

		BEGIN   VAR  R = REAL;

			DO	R:= SQRT( X*X + Y*Y ) ;

			GIVE	R*COS(THETA) # R*SIN(THETA)
		END

	    ENDDEFN

	There is also a similar BEGIN...END for STATEMENTs.


    ( EXPR := EXPR ; )		->	EXPR

	This shorthand notation performs an assignment statement and yields as
	its value the value assigned.  That is:

		(EXPR1 := EXPR2;)

	is equivalent to

		DO	EXPR1 := EXPR2 ;

		GIVE	EXPR1

	ICL supports other kinds of assignment statements besides the ":="
	(see Section 22.2.1).  Any of the various assignment
	statements can appear between the parentheses.


    nil		->	EXPR

	The value NIL is meaningful for all types except INT, REAL, BOOL, and
	CHAR.  It means "no value".  A NIL list has no elements.  A NIL record
	has no components, etc.


    defined( EXPR )		->	EXPR

	The given EXPR can be of any type except INT, REAL, BOOL, and CHAR.
	The resulting EXPR is of type BOOLean.

	Yields TRUE if the EXPR is ~not NIL.  In practice, this
	is used to test for NIL.


    ID :: EXPR			->	EXPR

	This syntactic construct has two distinct meanings, one for the
	synthesis of ~variants, and the other for ~type ~disambiguation.
	For the synthesis of variants, refer to Section 23.5.1.
	We now present the type-disambiguation meaning.

	Due to ICL's polymorphism and coercions, any given EXPR may in fact be
	  interpretable as an instance of ~several distinct types.	For example,
	  "5" is interpretable as both an INT and a REAL.  This construct enables
	  you to specify which of the possible interpretations you desire.

	  The ID must be the name of a declared type, and the first EXPR must
	  be interpretable as an instance of that type.	 The result is the
	  given EXPR interpreted as an instance of that type.

	  Example:
		    Suppose we have a coercion from type INTeger to REAL, (like
		    FORTRAN has).

		    Suppose also that we have two WRITE procedures, one of which
		    takes in an INTeger and the other of which takes in a REAL.

		    If we specify:

				WRITE( 5 ) ;

		    we will see a "5" printed on the terminal.

		    We will see the same thing if we specify:

				WRITE( INT :: 5 );

		    However, we will see "5.0" if we specify:

				WRITE( REAL :: 5 );

	  In consideration of polymorphism and coercion, ICL always chooses an
	  interpretation that minimizes the total number of coercions.  You may
	  override such choices by using this "::" construction.

	  For example, the first WRITE statement shown above prints the INT 5
	  because "5" is an INT and there exists a WRITE that accepts directly
	  INTs.  This interpretation requires the use of zero coercions, and
	  hence is chosen.

	  The final example WRITE statement, the one that prints "5.0", chooses
	  also an interpretation that minimizes the number of coercions.
	  However, in this case that minimal number of coercions is one and not
	  zero.  The "REAL::" specifies that the "5" must be interpreted as a
	  REAL along the way.  This requirement can be met with no fewer than one
	  coercion, the coercion that maps the INT 5 into the REAL 5.0.

	  NOTE about binding order:

		    The "ID::" binds with the smallest EXPR, just like a unary
		    operator of binding order 1, (like unary "-").  For example:

				POINT :: 1#0

		    will group as:

				(POINT::1) # 0

		    regardless of type consistency.	 In this case, type consitency
		    may be lost.	In contrast, the following makes sense:

				POINT :: (1#0)




22.1.7
Decision Making

   if	 EXPR	 then	 EXPR	 else	 EXPR	 fi ->	EXPR

   if	 EXPR	 then	 EXPR
    ef  EXPR  then  EXPR
    ef  EXPR  then  EXPR
    ...
    ef  EXPR  then  EXPR
   else  EXPR  fi				    ->	EXPR

	  This is known as the IF-THEN-ELSE construct for EXPRs.

	  The EXPRs following the words IF and EF must be of type BOOLean, which
	  of course evaluate always to TRUE or FALSE.

	  The first rule yields the then-EXPR if the if-EXPR yields
	  TRUE, otherwise it yields the else-EXPR.

	  The second rule evaluates each if-EXPR and ef-EXPR, in order, until
	  one yields TRUE, at which point, it yields the corresponding then-EXPR
	  (the one on the same line as shown here).  If none of the if-EXPRs
	  yields TRUE, then it yields the else-EXPR.

	  The keyword "EF" is short for "Else If".

	  All of the then-EXPRs and the else-EXPR must be of the same type.
	  That type is the type of the resulting EXPR.

	  A similar looking IF-THEN-ELSE exists for STATEMENTS (Section 22.2.3).
	  There, the ELSE clause is optional.  Here, it is mandatory, as
	  always some value must be presented, e.g.,

		    ...  ELSE  NIL  FI


	  Example:
		    The following IF-THEN-ELSE yields the absolute value of X:

				IF  X < 0  THEN  -X  ELSE  X	FI

		    The following tells how long you might wait in your car at an
		    intersection for a green light:

				IF  LIGHT = GREEN	 THEN	 0
				EF  LIGHT = RED	 THEN	 60
				ELSE	"(Light is yellow)"   70   FI

	  The trailing FI exists to disambiguate between two possible
	  interpretations.  Consider the following IF-THEN-ELSE, shown without a
	  FI:

		    IF  A < B  THEN  10+20  ELSE  3+4

	  Suppose A<B is true, so that the THEN clause will be taken.  Is the
	  result 30 or 34?  The appearence of the mandatory FI disambiguates
	  these two interpretations:

		    IF  A < B  THEN  10+20  ELSE  3+4  FI		    is 30
										    (with A<B true)
		    IF  A < B  THEN  10+20  ELSE  3 FI  + 4	    is 34


    goto  EXPR
	NUMBER  =>	EXPR
	NUMBER  =>	EXPR
	...
	NUMBER  =>	EXPR
    endgoto					    ->	EXPR

	  The first EXPR (following the "GOTO") must be of type INTeger.

	  This acts exactly like a big IF-THEN-ELSE construction.  It choses
	  the EXPR that follows the literal NUMBER matching the value
	  yielded by the GOTO EXPR.

	  All the EXPRs except the GOTO EXPR must be of the same type, and that
	  type is the type of the result.

	  If the GOTO EXPR has a value that matches none of the NUMBERs, then
	  NIL, 0, or FALSE (depending on the result type) is the resulting value.

	  A similar GOTO construct exists for STATEMENTs as well.

   In addition:
	  You may substitute one occurence of "NUMBER" with the keyword
	  "ELSE", to capture all values not covered by the NUMBERs.	 If you
	  include the ELSE, some EXPR will always be chosen.

	  NOTE:   The NUMBERs must be all non-negative.

	  NOTE:   Given many clauses, this construct may be more efficient than
		    a corresponding IF-THEN-ELSE construct.

	  Example:
		    The following writes a non-negative number (N) in the "ordinal"
		    English:

				WRITE(  GOTO  N
					     1 => 'first'
					     2 => 'second'
					     3 => 'third'
					     4 => 'fourth'
					     5 => 'fifth'
					     ELSE =>  N  $$  '''th'

					  ENDGOTO				    );

		    (The EXPR:

				N  $$	 '''th'

		    turns the number N into TEXT, a list of characters, and appends
		    on the right the text "'th").


    case  ID  of
	ID :	EXPR
	ID :	EXPR
	...
	ID :	EXPR
    endcase							->	  EXPR

	  This is the ~variant CASE construct.  It is described along with
	  variant datatypes in Section 23.5.2


    case  EXPR  of
	ID :	EXPR
	ID :	EXPR
	...
	ID :	EXPR
    endcase							->	  EXPR

	  This is the ~scalar CASE construct.  It is described along with the
	  SCALAR datatype in Section 23.8.

22.1.8
Universal And Existential Quantification

    always	EXPR	QUANTIFIER				->	  EXPR

	  This rule implements universal quantification, as in the
	  mathematician's ~for ~all.

	The given EXPR, and the resulting EXPR are of type BOOLean.

	Yield TRUE if the given EXPR yields TRUE for every iteration caused
	by the QUANTIFIER.

	Example:
		If PS is a list of POINTs, we determine that all their X-
		coordinates are positive by writing:

			ALWAYS   P.X > 0   FOR P $E PS;

		(The quantifier "FOR P $E PS" sets P to each element in PS).

		We can use this EXPR in an IF-THEN-ELSE as follows:

			IF   ALWAYS  P.X > 0  FOR P $E PS;

			THEN	WRITE('All points have positive x-values');

			ELSE	WRITE('The point');  WRITE(P);
				WRITE(' has a non-positive x-value');	FI

	NOTE:	In case the condition fails, the very first iteration in which
		it fails is left intact.  The variable(s) are left holding
		the value(s) which cause the first violation.


    never  EXPR  QUANTIFIER			->	EXPR

	NEVER yields TRUE if the given EXPR yields FALSE on every iteration
	caused by the QUANTIFIER.

	NOTE:	In case NEVER yields FALSE, the very first iteration for which
		the EXPR yields TRUE is left intact.


    there_is  EXPR  QUANTIFIER			->	EXPR

	THERE_IS yields TRUE if the given EXPR yields TRUE on some iteration
	caused by the QUANTIFIER.

	NOTE:	In case THERE_IS yields TRUE, the first iteration upon which
		this becomes known is left intact.  That is, the very first
		iteration in which the EXPR yields TRUE is left intact.

  NOTE:		In case the QUANTIFIER causes zero iterations:

			ALWAYS		yields TRUE,
			NEVER		yields TRUE, and
			THERE_IS	yields FALSE.

  In addition:
	All three of these constructs, ALWAYS, NEVER, and THERE_IS can be cast
	in the following semantically identical syntax, where the QUANTIFIER
	appears first:

		QUANTIFIER  always  EXPR	->	EXPR
		QUANTIFIER  never  EXPR		->	EXPR
		QUANTIFIER  there_is  EXPR	->	EXPR

	Example:
		The following two uses of ALWAYS are equivalent:

			IF  ALWAYS  P.X > 0  FOR P $E PS;
			THEN  ...  ELSE  ...  FI

		and

			IF  FOR P $E PS;  ALWAYS  P.X > 0
			THEN  ...  ELSE  ...  FI

		This choice of notations allows you to stress either the EXPR
		or the QUANTIFIER.

	These rules' EXPRs consume as must text as possible to the right
	  (even disregarding type consistency).  Thus, for example:

		    QUANTIFIER   ALWAYS	  A < B  !	B < C

	  groups as

		    QUANTIFIER   ALWAYS	  (A < B  !	 B < C)

	  and not as:

		    ( QUANTIFIER	ALWAYS  A < B )	!  B < C



22.1.9
Minimizing Functions

    pick  EXPR  minimizing  EXPR  QUANTIFIER	->	  EXPR

	  The first EXPR may be of any type, and that is the type of the result.

	  The second EXPR must be either of type INT or type REAL.

	  The result is one of the values taken on by the first EXPR during the
	  iterations caused by the QUANTIFIER.  The chosen value is taken from
	  the particular iteration which causes the second EXPR to take on a
	  ~minimal value.

	  If the QUANTIFIER causes zero iterations, the result is 0, NIL, or
	  FALSE.

	  Example:
		    Given a list of POINTs PS, we pick the POINT in PS which is
		    closest to the origin by:

				PICK	P  MINIMIZING  ABS(P)  FOR P $E PS;

		    The chosen P has the smallest "ABS(P)".


    pick  EXPR  maximizing  EXPR  QUANTIFIER		  ->	    EXPR

	  This is similar to the previous rule, except that the chosen iteration
	  is one which ~maximizes the second EXPR.  The following are equivalent:

		    PICK  A	 MAXIMIZING	 B  QUANTIFIER
		    PICK  A	 MINIMIZING	 -B  QUANTIFIER

	  Finally, you get the equivalent forms:

    QUANTIFIER  pick  EXPR  minimizing  EXPR	->	  EXPR

    QUANTIFIER  pick  EXPR  maximizing  EXPR	->	  EXPR

	  Each rule consumes as much text to the right of the keyward
	  "MINIMIZING" (or "MAXIMIZING") as possible.  These alternative
	  notations let you stress the QUANTIFIER instead of the two EXPRs.



22.1.10
Global Variables

    holding	 ID ; ID ; ... ID ;   give  EXPR  endhold		    ->	EXPR

	  Please refer to the HOLDING construct for STATEMENTs for a detailed
	  explanation.  The EXPR (following the GIVE) can be of any type, and
	  that is the type of the resulting EXPR.



22.1.11
Objective Modification

	  The following operators are actually required relatively rarely.


    @ ( EXPR )		->	  EXPR    (target)

	  This is the "@-operator", the one operator in ICL that actually
	  exposes the use of pointers.

	  This notation has meaning only on the lefthand side of an assignment
	  statement, as in:

		    @(P) := Q ;

	  This assignment statement does not modify P.	It modifies what P
	  points to.

	  This assignment causes the block of memory that P points to to be
	  overwritten with the contents of the block that Q points to.

		    Throughout all of ICL excluding this operator, all
		    modifications affect only variables and NEVER datastructures.

		    Thus for example, if X and Y are variables of the same record
		    type (Section 23.4), the assignment:

				X := Y ;

		    makes X point to the same block of memory that Y presently
		    points to.

		    Consider a subsequent assignment:

				Y.A :=  a new value ;

		    This assignment to "Y.A" affects the variable Y and not the
		    structure pointed to by Y.  Thus, even after the first
		    assignment made X and Y point to the same thing, the second
		    assignment makes Y point to a new block of memory, a record
		    which differs from the original in its A component.

		    We say that modifications always occur on a "copy-on-write"
		    discipline, as introduced in Chapter 10.  No existing data are
		    ever modified (without using the @-operator).  All
		    modifications are "subjective" in that each modification
		    affects exactly ONE point of view, a single variable.

		    This "subjective" default in ICL means that in the absence of
		    the @-operator, and in conjuntion with our "pass by value"
		    discipline for function calls, we can actually guarantee the
		    following:

				In looking at a program listing, if you don't see a
			variable's occurence on the lefthand side of an
				assignment, you can rest assured that that variable,
				and all data accessable from that variable, are
				entirely unchanged from start to finish.	This
				invariant is true, no matter how many functions might
				be called in the interim.

		    Also, in the absence of the @-operator, you can actually
		    believe that each and every assignment statement makes a
		    complete copy of all data accessable from the value being
		    assigned, and that every function call creates a complete copy
		    of each parameter passed into that function.

	  The @-operator overrides ICL's default "subjective" implementation of
	modification.  The @-operator allows data and not just variables to be
	modified.  Modifications implanted via the @-operator are said to be
	"objective" modifications; these modifications become apparent from
	~all points of view.

	Refer to the previous example involving X and Y.  Having said:

		X := Y ;

	we know that X and Y point to the same block of memory.  If we now
	go ahead and say:

		@(X).A :=  a new value  ;

	then we will affect not the variable X, but rather, the actual record
	referenced by X.  Since X and Y (still) point to the same record, Y's
	  A component will appear to have been modified, just like X's A
	component has.  In fact, any other data that reference this record will
	"see" this modification to this record's A component.

	  Of all possible types in ICL, only lists, records, variants, and
	  processes may be @-assigned.

	pic

	  Lists are special when compared to these other types.  Lists may
	  experience partial sharing.	 One list may in fact point to the tail
	  of another list.  (See T and S in figure 22.1.  T points to a tail of
	  S).	 Thus, an @-assign performed upon the tail (T) may become visible
	  to the long list (S).	 This fact can be used to advantage.

	  Example:
		    Let S be a "refreshed" list like in figure 22.1(a).  (More
		    about "refreshed" in a moment).	 We set T to be the tail of S
		    starting at S's 5'th element:

				T :=	S[5-] ;

		    (This notation is introduced in Section 23.3).  The
		    figure shows T, and also T[2-] (which is the same as S[6-]).
		    We can use the @-operator as follows:

				@(T) := T[2-] ;

		    This causes the block that T points to to be overwritten with
		    the value T[2-], as in figure 22.1(b).  That value, T[2-], is
		    the block containing an F.  Notice how the block at T comes to
		    hold that F and a pointer to the G node, just like the block
		    that was T[2-].  Thus, the @-operator allows for explicit
		    list processing, such as deleting elements in lists.

	  Example:
		    Let's consider another objective modification upon T:

			@(T) :=  X <$ Y <$ T[2-] ;

		This inserts the elements X and Y in place of the element T[1]
		objectively.  Figure 22.1(c) shows the value:

			X <$ Y <$ T[2-].

		Figure 22.1(d) shows the effect of this @-assignment.  The
		block referenced by T has been overwritten with this new value.
		Because of the objective @, S will see this modification as
		well.  X and Y will replace S's 5'th element.

	"Refreshed" Lists:

		Lists are NOT necessarily represented by a sequence of blocks
		left-to-right.  This is essential to know only if you use "@"
		on lists.

		Lists formed exclusivly via the curly-bracket notation and
		the left append operator ("<$") are said to be "refreshed".
		(See Section 23.3).  These lists are in fact
		guaranteed to be represented by a list of blocks whose order
		corresponds logically with the order of the list.

		In contrast, the right-append operator ("$>") and concatenate
		operator ("$$") do ~not produce "refreshed" lists.  All
		guarantees are off if S is not "refreshed", as far as the
		@-operator is concerned.  You can use the REFRESH operator to
		render any list "refrehsed".

	Subtle Example:

		If S is a refreshed list, then the assignment:

			@(S) :=  U <$ S ;

		actually creates a list with a cycle in it, i.e., a list
		that appears to have infinitely many U's in front!

	pic

		    Figure 22.2(b) shows "S" and "U <$ S".  Notice that "U <$ S"
		    points to S.	If we overwrite the S block with the
		    "U <$ S" block, as this assignment does, figure 22.2(c) shows
		    the result.  The block to which S points contains a reference
		    to itself, the S in "U <$ S".

		    In contrast, we gain the desired effect of inserting
		    objectively U at the front of S via:

				@(S) :=  U <$ COPY(S) ;

		    The righthand side of this statement no longer references what
		    S points to.	It references only a copy of the block S points
		    to.  Figure 22.2(d and e) show what happens.  The block that S
		    points to now represents the old value of S with U inserted
		    at the front as desired.

		    (Note that these considerations are absent if we omit the
		    @-operator.  The following has no problems:

				S :=	U <$ S ;

		    It merely makes S point to the leftmost block in figure
		    22.2(b)).

	  NOTE:   The @-operator issues a runtime error if the EXPR is NIL.



    copy ( EXPR )		->	  EXPR

	  The EXPR must be interpretable as an instance of a type which may be
	  @-assigned, e.g., records.	The result is of the same type.

	  The resulting value occupies a different memory block than does the
	  given value.  COPY thus produces a copy of ~exactly ~one block of
	  memory.

	  This operator is useful only in conjunction with uses of the @-
	  operator.	 (See previous example).

	  NOTE:   COPY issues a runtime error if the EXPR is NIL.


    EXPR  =:=  EXPR		  ->	    EXPR

	  Compare any two items of the same types, except for our non-pointer
	  types: INT, REAL, BOOL, and CHAR.	 Are the two items identical, that
	  is, do they reside at the same ~memory ~address?

	  Examples:

		    A	 =:=	A		    is always TRUE

		    A	 =:=	COPY(A)	    is always FALSE

		    If A=:=B, then the objective modification:

				@(A):= ... ;

		    will be apparent to B as well, since A and B reference the
		    same memory location.

	  You may need to enclose each of the two EXPRs in parentheses.  "=:="
	  binds to the smallest possible EXPRs on the left and right, even if
	  it results in datatype errors.  That is:

		    A	 \FUNCTION	B  =:=  C

	  groups as

		    A	 \FUNCTION	(B =:= C)

	  and not as:

		    (A  \FUNCTION	 B)  =:=  C


22.2
STATEMENTs

	  STATEMENTs perform actions rather than computing values as EXPRs do.


22.2.1
Assignment Statements

	  We begin with the most popular statement, the assignment statement.



    EXPR := EXPR ;		  ->	    STATEMENT

    EXPR ::= BOP EXPR ;		  ->	    STATEMENT

    EXPR ::= EXPR BOP ;		  ->	    STATEMENT

    EXPR ::= UOP ;		  ->	    STATEMENT

    EXPR ::= RHUOP ;		  ->	    STATEMENT

	  These rules are all forms of the assignment statement.

	  NOTICE that ALL forms of assignment REQUIRE a semicolon for
	  termination.

	  The standard assignment statement is given by the first rule.
	  All of the other forms of assignment will be described in terms of
	  the standard assignment.

	  The standard assignment (first rule) means:

		    Evaluate the righthand EXPR, and stuff that value into the
		    lefthand EXPR.

	  The lefthand and righthand EXPRs must be of the same type.

	  Generally, the lefthand EXPR is just a variable.  However, there are
	  other EXPRs that can appear there.  Each syntax rule specifies whether
	  or not it may be used on the lefthand side of assignment statements.
	  In the absence of any such statement, the syntax rule cannot be used
	  on the lefthand side.

	  Example (standard assignment):

		    If P, P1, and P2 are variables of type POINT, then the
		    assignment:

				P :=	P1 + P2 ;

		    is meaningful.

		    It evaluates the point P1+P2, the righthand EXPR, and stuffs
		    that value into the lefthand EXPR, P.

		    Similarly, if X and Y are REAL variables, then:

				X # Y	 :=  P1 + P2 ;

		    is also meaningful.	 (The presentation of the BOP "#" states
		    that it is meaningful on the lefthand side of assignments).
		    As a result of this assignment, X winds up holding the x-
		    coordinate of the point P1+P2, and Y winds up holding the
		    y-coordinate of that sum.

	  Each of the non-standard assignments is described now by a rewrite
	  operation.  The "::=" notation maps to the ":=" (standard) notation
	  by copying the lefthand EXPR over to the righthand side.

	  Let E1 and E2 be EXPRs, and B be a BOP.	 The assignment:

   1)		    E1  ::=	     B  E2 ;		means
		    E1  :=	(E1) B  E2 ;

	  Example:
		    The assignment:

				I ::= + 1 ;	    means	I := I + 1;

		    This shorthand increments I.  Similarly, the assignment:

				LIST ::= $> ELEMENT ;

		    means
				LIST :=  LIST $> ELEMENT ;

		    Either of these assignments right appends an element onto the
		    list.  Also:

				I ::=	 MIN	J ;

		    means
				I :=	I MIN J ;

		    This says "I becomes no larger than J".

   2)		    E1 ::=	E2  B	 ;			means
		    E1 :=	E2  B	 (E1)	 ;

	  Example:
		    The assignment:

				I ::= 1 - ;	    means	I := 1 - I ;

		    Also, the following left appends an element onto a list:

				LIST ::=  ELEMENT	 <$ ;

		    (which is equivalent to:

				LIST :=  ELEMENT <$ LIST ;		    )

	  Now let U denote any UOP.

   3)		    E1 ::=	U ;				means
		    E1 :=	U  (E1)  ;

	  Example:
		    The assignment:

				I ::= - ;	    means	  I := - I ;

		    and can be read as "negate I".

	  Now let R denote any RHUOP.

   4)		    E1 ::=	R ;				means
		    E1 :=	(E1)	R ;

	  Example:
		    "\ABS" is a RHUOP, and so:

				X ::= \ABS ;		means	  X := X \ABS ;
								or	  X := ABS(X) ;

   In addition:
	  The non-standard assignments involving unary operators (UOP and
	  RHUOP) are generalized to allow any sequence of unary operators.
	  That is, if U1, U2, ..., Un denote unary operators, then the general
	  assignment:

		    EXPR  ::=  U1	 U2  ...  Un ;

	  means "apply U1 to the EXPR, then apply U2 to that result, then
	  apply U3 to that result, ..., then finally apply Un to that result,
	  and stuff this final result into the EXPR.

	  Example:
		    The assignment:

				X  ::=  \ABS  -  ;

		    puts a non-positive number into X, X's negative ABSolute value.

   In addition:
	  Any of these assignment statements, if enclosed in parentheses, passes
	  as an EXPR (and not STATEMENT).  The value of that EXPR is the value
	  actually assigned.  (See Section 22.1.6).  For example, the following
	  are legal EXPRs:

		    (I:= 3;)
		    (I::= + 1;)
		    (I::= - ;)
		    (I::= \ABS - ;)



22.2.2
Global Variables

    holding	 ID ; ID ; ... ID ;   do   STATEMENT  endhold	    ->	STATEMENT

	  Each ID must denote a variable.  This construct executes the STATEMENT
	  and assures that each of the named variables appears unchanged upon
	  completion.

	  That is, even though the execution of the STATEMENT may assign new
	  values into those variables, their old values will be restored upon
	  completion of execution (the ENDHOLD).

	  This construct is useful primarily for dealing safely with global
	  variables.  It provides for a "scoped" assignment of global variables.
	  We can paraphrase a need for this construct:

		    "I now have in mind a use for these global variables, although
		     I don't know how they are presently being used.

		 Therefore, I will use the HOLDING to provide insulation
		 between my use of the globals and the present (unknown) use of
		 those globals.

		 When I'm done with them, (the ENDHOLD), they will appear to
		     have been untouched to their present (unknown) users. "

	  Example:
		    Suppose we are operating in a context where the global variable
		    ORIENTATION, a MATRIX, is meant to be applied to all POINTs
		    that we are about to plot.

		    Whenever a point is plotted, someone will incorporate this
		    ORIENTATION matrix by plotting not the given POINT, but rather
		    the transformed POINT:

				point	 \AT	orientation		  (a point)

		    Suppose now that we want to affect ORIENTATION so that for
		    a limited period, all points going to the plotter will be
		    transformed differently, say by the matrix NEW_ORIENTATION.

		    We specify:

				HOLDING   ORIENTATION ;

				DO	  ORIENTATION := NEW_ORIENTATION ;

					  cause points to be plotted

				ENDHOLD

		    This assures that all points will be plotted with the
		    original ORIENTATION except for those points plotted
		    during the reign of this HOLDING...ENDHOLD.	 Those points
		    will be plotted with the orientation NEW_ORIENTATION instead.
		    POINTs plotted before or after this program text will
		    plot at the original ORIENTATION (not NEW_ORIENTATION).

   In addition:
	  Each occurence of:

		    ID ;

	  in the HOLDING rules may be replaced by a general assignment statement,
	  as long as the lefthand side of that assignment statement is just a
	  variable (ID).	For example, we can write:

		    ID := EXPR ;		    in place of	    ID ;

	  Example:
		    Continuing with the ORIENTATION example shown above, we
		    can rewrite that text more concisely:

				HOLDING  ORIENTATION := NEW_ORIENTATION ;

				DO	  cause points to be plotted

				ENDHOLD

22.2.3
Decision Making

    if  EXPR  then  STATEMENT	 fi			->	  STATEMENT

    if  EXPR  then  STATEMENT	 else	 STATEMENT	fi	  ->	    STATEMENT

    if  EXPR  then  STATEMENT
     ef  EXPR  then  STATEMENT
     ef  EXPR  then  STATEMENT
     ...
     ef  EXPR  then  STATEMENT  fi				  ->	    STATEMENT

    if  EXPR  then  STATEMENT
     ef  EXPR  then  STATEMENT
     ef  EXPR  then  STATEMENT
     ...
     ef  EXPR  then  STATEMENT
    else  STATEMENT    fi				->	  STATEMENT

	  This is the IF-THEN-ELSE construct for STATEMENTs.

	  Each EXPR appearing here must be of type BOOLean.

	  The first rule executes the STATEMENT if the EXPR yields TRUE,
	  otherwise it does nothing.

	  The second rule executes the first STATEMENT if the EXPR yields TRUE,
	  otherwise it executes the second STATEMENT.

	  The third rule evaluates each EXPR, in order, until an EXPR yields
	  TRUE, at which point it executes the corresponding STATEMENT (following
	  the THEN).  If none of the EXPRs yields TRUE, then it does nothing.

	  The keyword "ef" is short for "else if".

	  The fourth rule is like the third, except that if all the EXPRs yield
	  FALSE, then it executes the final "else" STATEMENT.

	  The terminating FI is present to disambiguate for example the
	  following, which is written without a FI:

		    IF  A < B  THEN  I:= 1;
				   ELSE  J:= 2;  K:= 3;

	  If "A<B" is true, we certainly set I to 1, but do we also set K to 3?
	  That choice is dictated by the appearence of FI:

		    IF  A < B  THEN  I:= 1;
				   ELSE  J:= 2;  FI   K:= 3;
	  versus
		    IF  A < B  THEN  I:= 1;
				   ELSE  J:= 2;  K:= 3;	 FI

	  The former always sets K to 3 whether or not A<B.  The latter sets K
	  to 3 only if A<B is false.



    goto  EXPR
	NUMBER =>  STATEMENT
	NUMBER =>  STATEMENT
	...
	NUMBER =>  STATEMENT
    endgoto							->	  STATEMENT

	  The EXPR must be of type INTeger.

	  This acts exactly like a big IF-THEN-ELSE construction.  It chooses
	  the STATEMENT that follows the literal number (NUMBER) matching the
	  value yielded by the integer EXPR following the GOTO.

	  If the GOTO EXPR has a value that matches none of the NUMBERs, then
	  nothing is executed.

	  A similar GOTO construct exists for EXPRs as well.

   In addition:
	  You may substitute one occurence of "NUMBER" with the keyword
	  "ELSE" to capture all values not covered by the NUMBERs.

	  If you include an ELSE, some STATEMENT will always be chosen.

	  NOTE:   The NUMBERs are all non-negative

	  NOTE:   Given many clauses, this construct may be more efficient than
		    a corresponding IF-THEN-ELSE construct.


    case  ID  of
	ID :	STATEMENT
	ID :	STATEMENT
	...
	ID :	STATEMENT
    endcase							->	  STATEMENT

	  This is the ~variant CASE construct.  It is described along with
	  variant datatypes in Section 23.5.2


    case  EXPR  of
	ID :	STATEMENT
	ID :	STATEMENT
	...
	ID :	STATEMENT
    endcase							->	  STATEMENT

	  This is the ~scalar CASE construct.  It is described along with the
	  SCALAR datatype in Section 23.8.



22.2.4
Local Variables

    begin  DECL  STATEMENT  end			->	  STATEMENT

	  STATEMENTs, as well as EXPRs (Section 22.1.6) may be enclosed in a
	  BEGIN...END along with variable declarations.	 The following is an
	  example:

		    BEGIN	VAR  I = INT;

				I:= 2;
				DO  I:= I*I;  REPEAT 5;
				WRITE(I);
		    END

	  The new variable I is made available to the STATEMENT (3 lines) within
	  the BEGIN...END.



22.2.5
Looping

    do  STATEMENT	 QUANTIFIER				->	  STATEMENT

    QUANTIFIER  do  STATEMENT	 end			->	  STATEMENT

	  These two rules are semantically identical.

	  Execute the STATEMENT once for each iteration caused by the
	  QUANTIFIER.

	  Note that the second rule, which allows you to specify the STATEMENT
	  after the QUANTIFIER, ~requires the terminating END keyword.

	  Example:
		    The STATEMENT:

				DO	  CRLF; WRITE(I);	    FOR I FROM 1 TO 10;

		    prints the numbers from 1 to 10, each preceded by a carriage-
		    return line-feed (CRLF).

		    The following specification does exactly the same thing:

				FOR I FROM 1 TO 10;   DO     CRLF; WRITE(I);	 END




22.2.6
Miscellaneous:

    STATEMENT  STATEMENT		    ->	STATEMENT

	  In ICL, any sequence of STATEMENTs as a whole is a valid STATEMENT.
	  Sequences of STATEMENTs don't need to be enclosed by anything, not even
	  a BEGIN...END.

	  For example, each of the following is a valid STATEMENT:

		    I:= 2;

		    DO	I:= I*I;	    REPEAT 5;

	  Together, this whole piece of text is also a valid STATEMENT.


22.3
QUANTIFIERs

	  QUANTIFIERs cause looping.	Ultimately, any QUANTIFIER is associated
	  with a STATEMENT or an EXPR, so as to cause repeated execution of that
	  STATEMENT or EXPR.  A QUANTIFIER by itself is neither a STATEMENT nor
	  EXPR.


22.3.1
Basic Quantifiers

	  We first introduce basic QUANTIFIERs, some of which you may find in
	  many languages.	 We then introduce ways to combine QUANTIFIERs into
	  more complex QUANTIFIERs, and provide for the modification of any
	  QUANTIFIER.



    repeat	EXPR	;			    ->	QUANTIFIER

	  The EXPR must be of type INT.  This QUANTIFIER causes that INTeger
	  number of iterations.	 If the INTeger is less than or equal to zero,
	  zero iterations occur.

	  Note that the semicolon is required as part of the QUANTIFIER.



    while  EXPR  ;			    ->	QUANTIFIER

	  The EXPR must be of type BOOL.  This QUANTIFIER causes an iteration
	  while the EXPR yields TRUE.

	  This QUANTIFIER causes zero iterations if the EXPR yields FALSE
	  upon first evaluation.  Only if the EXPR yields TRUE will there be
	  another iteration.  The QUANTIFIER causes no more iterations as soon
	  as the EXPR yields FALSE.

	  Note that the semicolon is required as part of the QUANTIFIER.


    until  EXPR  ;			    ->	QUANTIFIER

	  The EXPR must be of type BOOL.  This QUANTIFIER causes ~another
	  iteration until if finds the EXPR yielding TRUE.

	  This QUANTIFIER always causes ~at ~least ~one ~iteration.	 It does not
	  evaluate the EXPR until the second iteration.

	  This quantifier is identical to the WHILE except that:

	     a)   it negates the EXPR,  and
	     b)   it gives always one iteration.

	  Note that the semicolon is required as part of the QUANTIFIER.



    for  ID	 from	 EXPR	 to  EXPR  by  EXPR  in	 EXPR	 ;	    ->   QUANTIFIER

    for  ID	 from	 EXPR	 to  EXPR  by  EXPR  in*  EXPR  ;	    ->   QUANTIFIER

	  This is the ~arithmetic ~FOR quantifier.  The ID must denote
	  a variable whose type is either INTeger or REAL.  The FROM-, TO-, and
	  BY-EXPRs must be of the same type as the variable.	The IN-EXPR must
	  be of type INTeger always.

	  Any subset of the four clauses (the FROM EXPR, TO EXPR, BY EXPR, and
	  IN EXPR) may be omitted.  Also, the clauses may appear in any order
	  (with no change in meaning).

	  Note that the semicolon is required as part of the QUANTIFIER.

	  The from-EXPR denotes the value to be taken on by the variable for
	  the first iteration.	If absent, the variable takes on its present
	  value for the first iteration.

	  The other three clauses, TO, BY, and IN, imply various meanings
	  dependent on their presence or absence.

	  The in-EXPR, if present, specifies the number of iterations.

	  The by-EXPR, if present, specifies the increment which will be applied
	  to the variable for all non-first iterations.

	  The to-EXPR, if present, specifies the value ~beyond ~which no more
	  iterations will occur.  The to-EXPR is ignored if both the by- and
	  in- EXPRs are present.

	  If the in-EXPR and the to-EXPR are present, but the by-EXPR is
	  absent, then the increment is chosen so as to divide the interval
	  from the FROM value to the TO value into IN sub-intervals.  You get the
	  ~left endpoint of each of those intervals.  You do not get the right
	  endpoint of the final sub-interval, the to-EXPR value, unless you put
	  an asterisk following the keyword IN.  If you do include that asterisk,
	  you get IN+1 iterations.

	  If you include only the to-EXPR, and not the by- nor in- EXPRs,
	  the increment is + or - 1, +1 if TO is greater than FROM, -1 if
	  TO is less than FROM.	 (IF TO equals FROM, then you get only one
	  iteration).

	  A summary of behavior based on the presence or absence of each of the
	  BY, TO, and IN clauses follows.  We specify the behavior by showing
	  both the chosen increment and the total number of iterations:

	  BY	TO  IN    !		  INCR			  COUNT
	  --	--  --    !		  ----			  -----
	  .	.   .	    !		  +1				  infinity
	  .	.   IN    !		  +1				  IN
	  .	TO  .	    !		  + or - 1			  1 + ABS( TO-FROM )
	  .	TO  IN    !		  (TO-FROM) / IN		  IN
	  BY	.   .	    !		  BY				  infinity
	  BY	.   IN    !		  BY				  IN
	  BY	TO  .	    !		  BY				  1 + (TO-FROM) / BY
	  BY	TO  IN    !		  BY				  IN

	  In case IN* is specified, the occurence of IN in the COUNT column
	  should be IN+1.

	  All arithmetic, including the divides, occur in the INTeger domain
	  if the variable (ID) is of type INTeger, otherwise they occur in
	  the REAL domain.

	  Examples:

	     FOR  I	 FROM 1 TO 10 ;

		    causes 10 iterations, with I taking on the values 1 thru 10.

	     FOR  I	 FROM 1 TO 10 BY 2 ;

		    causes I to take on the values 1,3,5,7, and 9.

	     FOR  I	 FROM 1 BY 2 IN 12 ;

		    causes 12 iterations, with I taking on the values
		    1,3,5,7,9,11,13,15,17,19,21,23

	     FOR  I	 FROM 1 BY 2 IN* 12 ;

		    causes 13 iterations, with I taking on the values 1,3,5,7,
		    9,11,13,15,17,19,21,23, and 25.

	     FOR  I	 FROM 1 ;

		    causes infinitely many iterations, with I taking on the values
		    1,2,3,...

		    (The utilitiy of such infinite QUANTIFIERs occurs in
		    conjunction with the "&&" operator for QUANTIFIERs, which
		    will be shown shortly).

	     FOR  I	 FROM 1 BY -2 ;

		    causes infinitely many iterations, with I taking on the values
		    1,-1,-3,-5,-7,...

	     FOR  I	 FROM 10 IN 17 ;

		    causes 17 iterations, with I taking on the values 10,11,12,...,
		    24,25, and 26.

	     FOR  R	 FROM	 0  TO  1.0	 IN  4 ;

		    We presume R is a REAL variable.  This QUANTIFIER causes 4
		    iterations, with R taking on the values 0, 0.25, 0.5, 0.75.

	     FOR  R	 FROM	 0  TO  1.0	 IN*	4 ;

		    We presume R is a REAL variable.  This QUANTIFIER causes 5
		    iterations, with R taking on the values 0, 0.25, 0.5, 0.75,
		    and 1.0.

	  Example Using The QUANTIFIER:

		    The following list of points denotes an N-sided circle
		    (regular polygon), where N is given:

			 { COLLECT	COS(T) # SIN(T)	FOR T FROM 0 TO TWO_PI IN N; }

		    T takes on the values 0 thru TWO_PI in N even steps.  That
		    is, it takes on the ~left endpoint of each of N even intervals.
		    The COS and SIN produce a point on the unit circle upon each
		    iteration.  (The ~COLLECT construction for lists appears in
		    Section 23.3).

		    The following list of points denotes the same, except that
		    the first point appears again at the very end.  T finally
		    takes on the value TWO_PI, which produces the same point as
		    did the first iteration, when T=0.

			 { COLLECT	COS(T) # SIN(T)	FOR T FROM 0 TO TWO_PI IN* N; }

	  NOTE:   All the EXPRs in the clauses are evaluated once, in the
		    preparation for the first iteration.	Thus, the body of your
		    loop cannot change their values midstream.

		    (The order of evaluation of those initial EXPRs is uncertain).

		    Also, the variable (the ID) is set at each iteration.  Thus,
		    even if you assign new values into that variable from within
		    the body of the loop, this will ~not affect values during
		    subsequent iterations.

		    One can count on the values in the iterations variable(s) upon
		    completion of the quantifier.  They hold the values that
		    existed upon the last iteration.


    for  EXPR  $e	 EXPR	 ;				->	  QUANTIFIER

	  This QUANTIFIER steps thru elements in a list.  The "$e" reads as
	  ~is ~an ~element ~of.

	  The second EXPR must be a list, and the first EXPR must be of that
	  list's ~element type.	 (Section 23.3 introduces lists).

	  This QUANTIFIER causes one iteration per element in the list.

	  Example:

		    Suppose we make the type declaration:

				TYPE	  LIST =  { INT }	 ;

		    and declare two variables:

				VAR	  L = LIST ;
					  I = INT ;

		    The QUANTIFIER:

				FOR  I  $e	L ;

		    which reads ~FOR ~I ~an ~element ~of ~L, sets I to each element
		    in L, causing one iteration for each value.

		    For example, the QUANTIFIER:

				FOR  I  $E	{1;2;5;1;3} ;

		    sets I to the numbers 1,2,5,1, and 3, in that order, and causes
		    one iteration for each of those values.

		    This "$e" QUANTIFIER is a special case of the following, "$c"
		    QUANTIFIER.



    for  EXPR  $c	 EXPR	 ;				->	  QUANTIFIER

	  This QUANTIFIER steps thru lists in a more general manner than does the
	  "$e" QUANTIFIER just shown.

	  The "$c" reads as ~contained ~in.	 We call this the official form.  The
	  "$e" FOR QUANTIFIER is a special case, and is rendered in terms of the
	  official "$c" QUANTIFIER as follows:

		    for  EXPR1  $e  EXPR2 ;
	  becomes:

		    for  { EXPR1 }   $c	  EXPR2 ;


	  The "$C" operator acts exactly like our familiar assignment operator
	  ":=".  By itself, it causes only one iteration.  It stuffs the
	  value of the righthand EXPR into the lefthand EXPR and gives exactly
	  one iteration.

	  All looping, the emergence of more than one iteration, is dictated
	  entirely by the lefthand EXPR.

	  For example, the abbreviated "$e" notation causes multiple iterations
	  by enclosing its given lefthand EXPR in curly brackets.  It is those
	  curly brackets around the lefthand EXPR that cause the original
	  lefthand EXPR to be assigned "each element in" the righthand EXPR.

	  The official "$c" QUANTIFIER requires that the two EXPRs on either side
	  of the "$c" be of the same type, just as our assignment statement
	  (":=") requires.  This is consistent with our description of the "$e"
	  QUANTIFIER.  That is, the QUANTIFIER:

		    FOR  X	$e  Y ;

	  requires X to be of the element type of the list Y.	 The EXPR:

		    { X }

	  is a list like Y.  Thus, the official form:

		    FOR  { X }  $C  Y ;

	  does indeed have the same (list) type on either side of the $C.

	  Example:

		    Our previous example presented with the "$e" QUANTIFIER:

				FOR  I  $E	L ;

		    is equivalent to the form:

				FOR  { I }	$C  L ;


    The Lefthand EXPR:	~Looping ~Targets

	  What forms can the lefthand EXPR take on?  The lefthand EXPR can be
	  any EXPR that is meaningful on the lefthand side of an assignment
	  statement.  In this simple case, the "$c" QUANTIFIER acts exactly like
	  an assignment statement, and causes exactly one iteration.  However,
	  the lefthand EXPR can be formed by some operators that are not valid
	  on the lefthand side of an assignment.

	  In general, the lefthand EXPR must make sense in the ~looping ~target
	  domain, a domain created especially for use in this FOR QUANTIFIER.

	  What is a looping target?  The set of all looping targets is formed
	  by first including all target forms, that is, all EXPRs that are valid
	  on the lefthand side of an assignment statement:

	     1)   target		  ->	    looping target

	  This transformation causes no additional iterations.

	  A looping target may be formed by enclosing other looping targets
	  within curly brackets:

	     2)   { looping target ; ... ; looping target }	    ->
										    looping target

	  We have seen an example of this form already, where only one element
	  appears between the curly brackets.  The "$e" gets its meaning by
	  using this form.

	  This formation of a looping target contributes one dimension of
	  iteration.  The ~given ~list is the one that appears to the right
	  of the "$c".  The first iteration sets the first looping target to
	  the first element in the given list.  It also assigns to the second
	  looping target the second element in the list, etc.

	  The second iteration sets the first looping target now to the second
	  element in the given list.	It also assigns to the second looping
	  target the third element in the given list, etc.

	  Examples:

		    Suppose we declare the following types and variables (See
		    Section 23.3 for declaring lists):

				TYPE	  LIST  =  { ELEMENT }	;

				VAR	  L, L1 = LIST ;
					  E1,E2,E3 = ELEMENT ;

		    The QUANTIFIER:

				FOR  { E1 }	 $C  L ;

		    causes one dimension of iteration, setting E1 to each element
		    in L (in order).

		    The QUANTIFIER:

				FOR  { E1 ; E2 }	$C  L ;

		    causes one dimension of iteration, setting E1 and E2 to
		    adjacent elements in L.  That is, the iterations set E1 and
		    E2 as follows:

				First iteration:		E1 = L[1]	and  E2 = L[2]
				Second iteration:		E1 = L[2]	and  E2 = L[3]
				Third iteration:		E1 = L[3]	and  E2 = L[4]
				...
				Last iteration:		E1 = L[n-1]	 and	E2 = L[n]

		    where n is the number of elements in L.  This is a total of
		    n-1 iterations.

		    The QUANTIFIER:

				FOR  { E1 ; E2 ; E3 }  $C  L ;

		    causes one dimension of iteration, setting E1, E2, and E3 to
		    triples of adjacent elements in L.  Whereas the previous
		    QUANTIFIER causes n-1 iterations, this QUANTIFIER causes
		    n-2 iterations.  (The last iteration has E1 holding the
		    n-2'th element of L).

	  This curly bracket formation of looping targets may include an
	  asterisk ("*") following any one of the semicolons.	 The asterisk
	  indicates that the elements (looping targets) specified to the right
	  of that asterisk may ~wrap ~around back to the beginning of the given
	  list.

	  Example:

		    The QUANTIFIER:

				FOR  { E1 ;* E2 }	 $C  L  ;

		    causes one dimension of iteration.  Like the previous
		    example without the asterisk, it sets E1 and E2 to adjacent
		    elements contained in L.	However, unlike the
		    previous example, we get an extra iteration at the end.	 The
		    final iteration sets E1 to the last element in L, and E2
		    to the first element in L.  The E2 has thus wrapped around back
		    to the beginning of the list.  This is a total of n iterations.

		    This quantifier is very useful to enumerate the ~edges of
		    a polygon represented by a list of vertices.  (L would be a
		    list of POINTs, the vertices, and E1 and E2 would be the two
		    POINT variables that represent the two endpoints of each edge).

		    The QUANTIFIER:

				FOR  { E1 ;* E2 ; E3 }	$C  L	 ;

		    causes one dimension of iteration.  Here, each of E2 and E3
		    is allowed to wrap around to the beginning of the list L.
		    The final iteration sets E1 to the last element in L, E2 to
		    the first element in L, and E3 to the second element in L.

		    The QUANTIFIER:

				FOR  { E1 ; E2 ;* E3 }	$C  L	 ;

		    differs from the previous example only in the placement of
		    the asterisk.	 Here, only E3 is allowed to wrap around, and
		    hence the final iteration sets E1 to the second to last element
		    in L, sets E2 to the last element in L, and E3 to the first
		    element in L.

	  We introduce now another form of looping target.  Whereas the previous
	  form gave access to element in a list, this next form delivers ~tails
	  of a given list.  The looping target form:

	     3)   looping target  -			->	  looping target

	  stuffs into the left looping target ~each successive tail of the given
	  list, starting with the entire list, then with the list less its
	  first element, etc.  The final tail delivered with this construct
	  is a list of length one, the final tail which contains only the last
	  element in the given list.

	  Example:

		    The QUANTIFIER:

				FOR  L1 -  $C  L	;

		    sets L1 to each tail of L.  We get iterations as follows:

			  First iteration:    L1  is	L
			  Second iteration:   L1  is	L[2-]
			  Third iteration:    L1  is	L[3-]
			  ...
			  Last iteration:	    L1  is	L[n-]

		    where n is the length of the given list L.	(For the "L[2-]"
		    notation, see Section 23.3.  It reads as "the tail of L
		    starting from the second element").  That is, on the first
		    iteration, L1 has length n, and on the second iteration, L1 has
		    length n-1, etc.



22.3.2
Quantifier Combinations

    QUANTIFIER  &&  QUANTIFIER			->	  QUANTIFIER

	  The "&&" causes two QUANTIFIERs to step in unison, also known as
	  ~lock-stepping.	 This combined QUANTIFIER stops as soon as either one
	  of the given QUANTIFIER stops.  In other words, the number of
	  iterations caused by the combined QUANTIFIER is the ~minimum of the
	  numbers of iterations caused by each of the given QUANTIFIERs.

	  Because of this early termination, one of the quantifiers can be a
	  non-terminating quantifier.

	  Example:

		    The QUANTIFER:

				FOR  E1  $E	 L1 ;	   &&	   FOR  E2	$E  L2 ;

		    sets E1 and E2 to corresponding elements in the lists L1 and
		    L2.  The first iterations sets E1 to the first element of L1,
		    and E2 to the first element in L2.  The second iteration sets
		    E1 to the second element of L1, and E2 to the second element of
		    L2, etc.

		    This QUANTIFIER causes as many iterations as the length of the
		    shorter list (L1 or L2).

		    The QUANTIFIER:

				FOR E1 $E L1;  &&	 FOR E2 $E L2;  &&  FOR E3 $E L3;

		    sets E1, E2, and E3 to corresponding elements in all three
		    lists L1, L2, and L3.



    QUANTIFIER  !!  QUANTIFIER			->	  QUANTIFIER

	  The "!!" causes two QUANTIFIERs to ~nest, the second nested within
	  the first.  That is, for each iteration caused by the first given
	  QUANTIFIER, step thru the entirety of the second QUANTIFIER.  The
	  number of iterations caused by the combined QUANTIFIER is the ~product
	  of the numbers of iterations caused by each of the given QUANTIFIERs.

	  Example:

		    The QUANTIFIER:

				FOR  E1  $E	 L1 ;	   !!	   FOR  E2	$E  L2 ;

		    sets E1 and E2 to all possible pairs of elements where E1 is
		    in L1 and E2 is in L2.

		    We often call the "!!" operator the ~cartesian ~product
		    operator.  As in this example, it sets the pair E1 and E2 to
		    each element in the cartesian product of the sets L1 and L2.

	  Example:

		    Suppose LL is a list of lists, e.g., as declared by:

				TYPE	 LIST_OF_LISTS  =	 { LIST }  ;

				VAR	  LL = LIST_OF_LISTS ;

		    The QUANTIFIER:

				FOR  L  $E	LL ;	  !!	  FOR	 E1  $E  L ;

		    sets L to each list in LL, and E1 to each element in that list
		    L.  This QUANTIFIER thus delivers individual elements from
		    a list of lists.


    QUANTIFIER  then  QUANTIFIER			->	  QUANTIFIER

	  The "then" has the second QUANTIFIER start up right after the first
	  QUANTIFIER stops.  The number of iterations caused by the combined
	  QUANTIFIER is the ~sum of the numbers of iterations caused by each
	  of the given QUANTIFIERs.

	  Examples:

		    The QUANTIFIER:

				FOR  E1  $E	 L1 ;	   THEN    FOR  E1  $E	L2 ;

		    sets E1 to each element of L1 and then to each element of L2.
		    It is logically equivalent to:

				FOR  E1  $E	 (L1 $$ L2) ;

		    which sets E1 to each element in the list formed by
		    concatenating the lists L1 and L2.

		    The QUANTIFIER:

				FOR  E1  $E	 L1 ;	   THEN    FOR E1 FROM 1 TO 10;

		    sets E1 to each element of L1 and then to each of the numbers
		    1 thru 10.

	  Finally, when more than one of these binary operators is used to
	  form a QUANTIFIER, the grouping, or "binding order" is uncertain.

	  However, the next rule allows you to put parentheses around any
	  QUANTIFIER, and thus dictate explicitly the grouping of QUANTIFIERs.



    (	 QUANTIFIER	 )					->	  QUANTIFIER

	  This rule is semantically an identity, but it allows you to specify
	  how QUANTIFIERs are grouped together.

	  Example:

		    The QUANTIFIER:

				FOR X FROM 1 TO 5;

	pic

		    sets X to the horizontal set of points (X#0) shown in figure
		    22.3(a).  The QUANTIFIER:

				FOR Y FROM 1 TO 5;

		    sets Y to the vertical set of points (0#Y) shown in figure
		    22.3(b).  The combined QUANTIFIER:

				FOR Y FROM 1 TO 5;
				!!
				FOR X FROM 1 TO 5;

		    sets X and Y so that X#Y forms the two-dimensional array of
		    points shown in figure 22.3(c).

		    Let's take this combined QUANTIFIER and make it lock-step with
		    the new quantifier:

				FOR I FROM 1 BY 1;

		    The combination:

				( FOR Y FROM 1 TO 5;
				  !!
				  FOR X FROM 1 TO 5; )

				&&
				FOR I FROM 1 BY 1;

		    sets the variables X, Y, and I so as to produce figure 22.3(d),
		    if we write I at the location X#Y.

		    In contrast, let's put in the parentheses differently, as in:

				FOR Y FROM 1 TO 5;
				!!

				( FOR X FROM 1 TO 5;
				  &&
				  FOR I FROM 1 BY 1; )

		    Now, the variables X, Y, and I are set so as to produce figure
		    22.3(e).  The "FOR I" quantifier lock-steps with the "FOR X"
		    quantifier, and both the X and I quantifiers do their thing
		    for each iteration caused by the "FOR Y" quantifier.




22.3.3
Quantifier Modifiers

	  Following are ways to ~modify a QUANTIFIER.  They are all of
	  the form:

		    QUANTIFIER  ~modifier		->	  QUANTIFIER

	  The modifiers each binds to the smallest QUANTIFIER to its left.


    QUANTIFIER  with  EXPR  ;				->	  QUANTIFIER

	  This WITH modifier filters out iterations from the given QUANTIFIER.
	  The resulting QUANTIFIER may have fewer iterations.

	  The EXPR must be of type BOOL.  The resulting QUANTIFIER shows only
	  those iterations for which the with-EXPR yields TRUE.  Iterations of
	  the given QUANTIFIER which cause the EXPR to yield FALSE are omitted.

	  Example:

		    The QUANTIFIER:

				FOR E1 $E L1;   WITH  E1.X > 5 ;

		    sets E1 to all elements of L1 for which the EXPR

				E1.X > 5

		    is TRUE.  It therefore sets E1 to all elements of L1 whose
		    x-coordinates exceed 5.  (This example presumes that L1 is
		    a list of POINTs, and that E1 is a POINT, whose x-coordinate
		    is acquired by the notation "E1.X").

	  This WITH construct can be read as the mathematician's
	  "...such that...".


    QUANTIFIER  initially  STATEMENT  ;		->	  QUANTIFIER

	  Cause the STATEMENT to be executed ~before starting up the given
	  QUANTIFIER



    QUANTIFIER  first_do  STATEMENT	 ;		->	  QUANTIFIER

	  Execute the STATEMENT upon the ~first iteration of the
	  given QUANTIFIER.  That is, after the given QUANTIFIER prepares for
	  the first iteration, execute the STATEMENT, before the loop body is
	  entered.



    QUANTIFIER  other_do  STATEMENT	 ;		->	  QUANTIFIER

	  Execute the STATEMENT upon all non-first iterations of the given
	  QUANTIFIER.  That is, after the QUANTIFIER prepares for each non-
	  first iteration, execute the STATEMENT.



    QUANTIFIER  each_do	 STATEMENT	;		->	  QUANTIFIER

	  Execute the STATEMENT uopn each iteration caused by the given
	  QUANTIFIER.  That is, after the QUANTIFIER prepares for each
	  iteration, execute the STATEMENT.

	  Notice that:

		    QUANTIFIER  first_do  STATEMENT ;
				    other_do  STATEMENT ;

	  is equivalent to

		    QUANTIFIER  each_do	 STATEMENT ;

	  if all three STATEMENTs here are identical.



    QUANTIFIER  finally_do  STATEMENT  ;		->	  QUANTIFIER

	  Execute the STATEMENT ~after the QUANTIFIER stops.	This does ~not
	  execute the STATEMENT upon the QUANTIFIER's last iteration, rather
	  it causes the STATEMENT to be executed ~after the last iteration.

	  You can imagine that the QUANTIFIER tries to cause another iteration,
	  but finds that there are no more.	 At that point in time, the STATEMENT
	  is executed.


	Example:

	  The following STATEMENT sums up the integers from 1 to 10:

		    FOR I FROM 1 TO 10;
					  INITIALLY	 ANSWER:= 0; ;
		    DO
				ANSWER::= + I ;
		    END

	  The QUANTIFIER used here:

		    FOR I FROM 1 TO 10;
					  INITIALLY	 ANSWER:= 0; ;

	  sets I to 1 thru 10, but first sets ANSWER to 0.  The body of the
	  loop sums I into ANSWER on each iteration.  (The appearence of two
	  semicolons after the "0" is correct.  The first semicolon belongs to
	  the assignment statement:

		    ANSWER:= 0 ;

	  The second semicolon is part of the INITIALLY construct, as per the
	  rule:

		    QUANTIFIER  initially  STATEMENT  ;		    ->   QUANTIFIER
	  ).

	  This loop can be written equivalently as:

		    ANSWER:= 0 ;
		    FOR I FROM 1 TO 10;
		    DO
				ANSWER::= + I;
		    END

	  The advantage of using the INITIALLY construct is that ANSWER's
	  initialization is part of the quantifier.  As just rendered without
	  the INITIALLY, some programmer might overlook this relationship, and
	  erase or move that initial assignment to ANSWER.

	  In ICL, this same loop can be written most simply as:

		    ANSWER:=  +  I  FOR I FROM 1 TO 10; ;

	  (The appearence of two semicolons following the 10 is correct.	The
	  first semicolon is part of the FOR-quantifier, and the second is part
	  of this overall assignment statement).

     Example:

	  The following EXPR uses INITIALLY to set a variable C to a value used
	  in all iterations:

		    +	 SIN(X*C)  FOR X $E L;
						    INITIALLY  C:= SQRT(Y+Z); ;

     Example:

	  The following quantifier sets R to the square-root of each member in L:

		    FOR X $E L;
				EACH_DO  R:= SQRT(X);;

     Example:

	  The following quantifier causes two iterations, setting K to R and then
	  setting K to -R:

		    REPEAT 2;
				FIRST_DO  K:= R;;
				OTHER_DO  K:= -R;;

	  We can combine this quantifier with our previous quantifier as
	  follows:

		    FOR X $E L;  EACH_DO  R:= SQRT(X);;
		    !!
		    REPEAT 2;
				FIRST_DO  K:= R;;
				OTHER_DO  K:= -R;;

	  This sets K to both the positive and negative square-roots of each
	  element in L.  We cause two iterations (REPEAT 2;) for each X in L,
	  via the "!!" notation.

	  This complex quantifier can be rendered equivalently as:

		    FOR X $E L;
		    !!
		    REPEAT 2;
				FIRST_DO  K:= SQRT(X);;
				OTHER_DO  K:= -K;;

     Example:

	  The following STATEMENT writes out the numbers 1 thru 10 with commas
	  ~between the numbers:

		    FOR I FROM 1 TO 10;
					  OTHER_DO	WRITE(',');;
		    DO
				WRITE(I);
		    END

	  That is, a comma precedes each number, on all but the first iteration.

     Example:

	  The following EXPR tells whether each element in L1 is less than its
	  corresponding element in L2:

		    ALWAYS	  X < Y    FOR X $E L1;	 &&  FOR Y $E L2;

	  That is, for X and Y holding corresponding elements in L1 and L2, is
	  X always less than Y?

     Example:

	  The following QUANTIFIER sets X to all positive elements in L1 and
	  then to all negative elements in L2:

		    FOR X $E L1;	WITH X>0 ;
		    THEN
		    FOR X $E L2;	WITH X<0 ;

     Example:

	  Imagine that the positive elements in L1 correspond to the positive
	  elements in L2.	 The following QUANTIFIER sets X and Y to corresponding
	  positive elements:

		    FOR X $E L1;	WITH X>0;
		    &&
		    FOR Y $E L2;	WITH Y>0;

     Example:

	  The following EXPR delivers the sum of the products of corresponding
	  elements in L1 and L2:

		    +	  X*Y	  FOR X $E L1;  &&  FOR Y $E L2;

     Example:

	  Given two sets S and T, the following EXPR delivers the minimum
	  difference between all elements in S against all elements in T:

		    MIN   ABS(X-Y)   FOR X $E S;  !!  FOR Y $E T;

	  The following delivers the same, where only the positive elements in S
	  and T are considered:

		    MIN   ABS(X-Y)   FOR X $E S; WITH X>0 ;
					   !!
					   FOR Y $E T; WITH Y>0 ;

     Example:

	  The following STATEMENT writes both the positive and negative square-
	  roots of the elements in L, each on a separate line:

		    ( FOR X $E L;
			!!
			REPEAT 2;
				FIRST_DO  Y:= SQRT(X);;
				OTHER_DO  Y:= -Y;;	)
		    DO
			  CRLF; WRITE(Y);
		    END

	  (The CRLF writes out a carriage-return and line-feed).  (The
	  parenthese around the two quantifiers are optional).  Our next
	  example does the same, but writes at the beginning of each line the
	  line number (1,2,3...):

		    ( FOR X $E L;
			!!
			REPEAT 2;
				FIRST_DO  Y:= SQRT(X);;
				OTHER_DO  Y:= -Y;;	)
		    &&
		    FOR I FROM 1 BY 1;
		    DO
				CRLF; WRITE(I); TAB; WRITE(Y);
		    END

	  Notice how easily we introduced the text:

		    &&
		    FOR I FROM 1 BY 1;

	  to our general QUANTIFIER, so as to deliver a line number for each
	  iteration.  Even though this FOR quantifier by itself causes
	  infinitely many iterations, the large quantifier (in parentheses)
	  preceeding the "&&" causes only finitely many iterations, and so as a
	  whole, this entire quantifier causes only finitely many iterations.

	  Suppose we wanted to consider only positive elements in L.  We
	  introduce the text shown italicized:

		    ( FOR X $E L;	 ~WITH ~X>0 ~;
			!!
			REPEAT 2;
				FIRST_DO  Y:= SQRT(X);;
				OTHER_DO  Y:= -Y;;	)
		    &&
		    FOR I FROM 1 BY 1;
		    DO  ...	 END

	  Our line numbers (I) still correspond to each line written, although
	  there might now be fewer lines.  In contrast, the following rendition
	  omits the same lines, but also omits those lines' line numbers:

		    ( ( FOR X $E L;
			  !!
			  REPEAT 2;
				FIRST_DO  Y:= SQRT(X);;
				OTHER_DO  Y:= -Y;;	)
			&&
			FOR I FROM 1 BY 1;		   )

		    ~WITH  ~X>0 ~;

		    DO  ...	 END

	  We have moved the WITH clause so as to encompass now also the FOR-I
	  quantifier.  The WITH clause here omits entire lines ~including their
	  line numbers.  We can get the following output:

		    1		.2786
		    2		-.2786
		    5		.331
		    6		-.331

	  (Here, we imagine that the second element in L is not positive, and
	  hence we omit lines 3 and 4).  In the former example, we would get:

		    1		.2786
		    2		-.2786
		    3		.331
		    4		-.331

     Example:

	  The following QUANTIFIER sets X to all elements in S, and Y to all
	  elements in T which are greater than X:

		    FOR X $E S;
		    !!
		    FOR Y $E T; WITH Y>X ;

     Example:

	  The following EXPR uses that QUANTIFIER, delivering the smallest
	  difference between elements in S and T where the element in T is
	  greater than the element in S:

		    MIN   Y-X   FOR X $E S;
				    !!
				    FOR Y $E T; WITH Y>X ;

	  The following EXPR delivers the apple whose weight to price
	  ratio is maximized:

		    PICK  APPLE  MAXIMIZING  WEIGHT(APPLE) / PRICE(APPLE)

					  FOR APPLE $E APPLES;

	  The next EXPR yields a similar apple, but this time we consider only
	  apples whose prices are less than 1:

		    PICK  APPLE  MAXIMIZING  WEIGHT(APPLE) / PRICE(APPLE)

					  FOR APPLE $E APPLES;	WITH	PRICE(APPLE) < 1;


22.4
DECLARATIONs

	  Declarations serve to ~augment the linguistic universe.  DECLARATIONs
	  can introduce new types, variables, functions, and coercions.



22.4.1
Type Declaration:

  type  ID = TYPEX ;		  ->	    DECLARATION

	  This declares a new type.  The ID is the name for the new type, and the
	  TYPEX is the specification of the new type.

	  Example:
		    TYPE  INTEGERS =  { INT }	 ;

	  INTEGERS now denotes the type list of INTegers.


22.4.2
Variable Declaration:

  var	 ID , ID , ... , ID = TYPEX ;			->	  DECLARATION

	  This declaration introduces new variables.  Each ID in each list of IDs
	  is declared to be a new ~variable of type TYPEX.  (Read this as:

		    var  ID, ID, ..., ID  ~each ~is	 =  TYPEX ;			)


	  For example, the following declaration(s) create new variables:

		    VAR	AGES , HEIGHTS  =	 INTEGERS ;
				SEX		    =	 BOOL ;
				DATES		    =	 INTEGERS ;

	  Each of AGES, HEIGHTS, and DATES is a new variable of type INTEGERS.

	  As this example shows, within a sequence of VAR declarations, the word
	  VAR may be omitted on all but the first line.

	  Each declared variable, say X, is now a valid EXPR, e.g.,:

		    x		->	  EXPR

	  The type of the EXPR is the type just now associated with the new
	  variable X.  This EXPR is valid also on the lefthand sides of
	  assignment statements.



22.4.3
Function Declarations

  define  ID ( ID : TYPEX  ID : TYPEX  ...  ID : TYPEX ) = TYPEX :
	EXPR
  enddefn								  ->	    DECLARATION

	  This declares a new function.  The name of the function follows the
	  word DEFINE.  The parameters of the function appear between the
	  parentheses.  Each parameter is denoted by a variable name (the ID)
	  and the type of that parameter (the TYPEX).  Following the "=", the
	  TYPEX denotes the type of this function's result.

	  The IDs specified in the input parameters become variables that hold
	  the actual input values given when this function is called.  Those
	  variables may be used within the body of the function, the EXPR.

	  The function body (EXPR) must be of the type specified as this
	  function's result's type, the TYPEX following the "=".

	  If within the EXPR you assign new values to any of the input
	  parameters, this will have ~no effect from the point of view of the
	  caller of this function.  In other words, input parameters are always
	  passed ~by ~value (Section 19.10.1).

	  (Within this function body, any such assignment does affect the
	  variable, as you would expect.  In fact, each input variable is really
	  a local variable that has an initial value already, the value passed
	  in by the caller).

	  Example:

		    The following declares a function POWER:

				DEFINE  POWER( X:REAL  EXPONENT:INT ) = REAL:

					  *  X  REPEAT  EXPONENT;

				ENDDEFN

		    This function has two input parameters, a REAL and an INT,
		    in that order.  This function's result is of type REAL (see the
		    "=").  The body of this function multiplies X by itself
		    EXPONENT many times.  The EXPR uses the input variables X and
		    EXPONENT.

	  In general, the declaration:

		  DEFINE  NAME ( ID(1):TYPEX(1)  ...  ID(k):TYPEX(k) ) = TYPEX(0):
			EXPR
		  ENDDEFN

	  effectively adds the rule of grammar:

		    name ( ~TYPEX(1) , ... , ~TYPEX(k) )		->	    ~TYPEX(0)

	  This rule supports the calling of this function.  It means that our
	  example POWER function introduces the rule:

		    power( ~REAL , ~INT )		->	  ~REAL

	---------------- Parentheses in previous paragraph around "1",
	----------------	nad "0" and "k" mean subscripting! --------------------


	  If there are only two input parameters, we also effectively introduce
	  the rule:

		    ~TYPEX(1)  \name  ~TYPEX(2)		  ->	    ~TYPEX(0)

	  Thus, our example function, which takes in two parameters, also
	  introduces the rule:

		    ~REAL  \power	 ~INT			->	  ~REAL

	---------------- Parentheses in previous paragraph mean subscripting! ---


	  If there is only one input parameter, we also effectively introduce the
	  rule:

		    ~TYPEX(1)  \name			->	  ~TYPEX(0)

	---------------- Parentheses in previous paragraph mean subscripting! ---


	  The actual syntax rules that support these notations are:

		    ID ( EXPR , EXPR , ... , EXPR )		  ->	    EXPR

		    \ ID						  ->	    BOP

		    \ ID						  ->	    RHUOP


   In addition:
	  Each of the "ID:TYPEX"s appearing in these rules may also be of the
	  form:

		    ID , ID , ... , ID	:  TYPEX

	  This is a shorthand form that represents more than one input parameter,
	  all of which have the same type.	For example, the following two
	  function declarations are absolutely equivalent:

		    DEFINE	SUM( I:INT	J:INT ) = INT:	  I+J	    ENDDEFN
	  and
		    DEFINE	SUM( I,J: INT )  =  INT:	  I+J	    ENDDEFN

	  Note that the order of parameter specification is important.  That
	  order is assumed by the caller of the function.


22.4.3.1
Polymorphism

	  Note that ICL is a ~polymorphic language.  This means that
	  you may define two or more functions of the same name, as long as
	  their input and output types provide some distinction.  For example,
	  we can define the following two functions:

		    DEFINE	DISTANCE( A,B: REAL ) = REAL:

				ABS( A-B )

		    ENDDEFN

		    DEFINE	DISTANCE( A,B: POINT ) = REAL:

				SQRT( (A.X-B.X)^2 + (A.Y-B.Y)^2 )

		    ENDDEFN

	  Both of these functions go by the name DISTANCE, but they are
	  distinguished in that one takes in POINTs whereas the other takes in
	  REALs.

	  When you call DISTANCE, one or the other of these two functions will
	  be called; the choice will be based upon the types of the parameters
	  you pass in that call.  For example, if you say:

		    WRITE(	DISTANCE( 5 , 6 )	 ) ;

	  you will see "1.0" on your terminal, but if you say:

		    WRITE(	DISTANCE( 1#2 , 4#6 )  ) ;

	  you will see "5.0" printed on the terminal.


22.4.3.2
Variations On The Function Declaration

	  The following three rules are variations on the one function
	  declaration rule just shown.  This next rule declares a function that
	  returns no value:


  define  ID ( ID : TYPEX  ID : TYPEX  ...  ID : TYPEX ) :
	STATEMENT
  enddefn								  ->	    DECLARATION

	  Notice that the function body is a STATEMENT, not a value (EXPR).
	  Also note that a colon follows the close parenthesis.  Compared to our
	  first function declaration rule, we have dropped the "=TYPEX"
	  following the close parenthesis.	This kind of function without a
	  resulting value, is often called a ~procedure.

	  ICL provides only one way to call a procedure:

		    ID ( EXPR , EXPR , ... , EXPR ) ;	     ->	STATEMENT

	  This is identical to the notation for calling functions that deliver
	  values, except that a terminating semicolon is required.	This
	  notation forms a STATEMENT instead of an EXPR.  (The terminating
	  semicolon is present so as to look like the assignment statement, which
	  also ends in a semicolon).

	  The remaining rules declare functions and procedures that take no
	  inputs at all:

  define  ID = TYPEX :
	EXPR
  enddefn								  ->	    DECLARATION

  define  ID :
	STATEMENT
  enddefn								  ->	    DECLARATION

	  These are like the first two rules except that the parentheses and
	  everything between them is omitted.  We call these ~parameterless
	  functions (procedures).

	  You call a parameterless function that returns a value just by
	  specifying the function's name, i.e.:

		    ID		  ->	    EXPR

	  You call a parameterless procedure (that returns no value) by
	  specifying the name and then a semicolon:

		    ID ;		  ->	    STATEMENT

	  Example:

		    The following declares a parameterless function that returns
		    a value:

				DEFINE  RANDOM_NUMBER = REAL:
				   some EXPR
				ENDDEFN

		    You call this function via:

				RANDOM_NUMBER

		    RANDOM_NUMBER denotes a REAL value.

	  Example:
		    The following declares a parameterless procedure:

				DEFINE  CRLF :
				   some STATEMENT
				ENDDEFN

		    You call this procedure via:

				CRLF ;

	  We chose to require a semicolon following procedure calls so
	  as to match our most popular STATEMENT, the assignment
	  statement.


22.4.3.3
Coercion Declarations


  let	 ID : TYPEX	 become  TYPEX  by  EXPR  enddefn	     ->   DECLARATION

	  This declares a new coercion.  A coercion is a function, without a
	  name, that takes in one parameter and yields a value.

	  Unlike functions, you never explicitly call a coercion.  (There is
	  no name with which to call it)!  The ICL compiler determines where
	  to call which coercions based on the requirements of context.

	  ICL always applies a minimum number of coercions over your program
	  text, in its effort to make sense of your program within the domain
	  of datatypes.

	  For example, we can tell the ICL compiler that "any INTeger may be
	  viewed also as a REAL" by writing:

		    LET  I:INT  BECOME	REAL	BY	FLOAT(I)	    ENDDEFN

	  Having made this declaration, we can call our function DISTANCE
	  (defined earlier) even if we specify INTegers, say, the INTeger
	  variables I and J:

		    WRITE(	DISTANCE( I , J )	 ) ;

	  This program text requires two applications of our new coercion so that
	  each of I and J can be interpreted as a REAL, prior to calling the
	  DISTANCE function defined for REALs.  Of course, ICL worries about all
	  this for you; you don't have to say any more than what appears here.

	  You can declare coercions between any two types, without restriction.
	  You can even declare the following coercion as well as the one just
	  shown:

		    LET  X:REAL  BECOME	 INT	BY	FIX(X)	    ENDDEFN

	  Although this last coercion might be objectionable, as it loses
	  information, there are examples where two-way pairs of coercions
	  offer some profound capabilities concerning program maintenance
	  (Section 23.5.3.2).

	  Another example coercion follows, which lets a REAL be viewed as a
	  POINT (complex number):

		    LET  X:REAL  BECOME	 POINT  BY	   X#0	    ENDDEFN

	  The given REAL becomes the x-coordinate of the result, and the y-
	  coordinate is zero.  This is consistent with our view of POINTs as
	  complex numbers.

	  The coercion:

		    let  ID : TYPEX1  become	TYPEX2  by	EXPR	;

	  introduces simply the rule of grammar:

		    ~TYPEX1		  ->	    ~TYPEX2


22.4.4
Miscellaneous DECLARATIONs

  DECLARATION  DECLARATION			->	  DECLARATION  (left-to-right)

	  This indicates that any sequence of DECLARATIONs is itself a valid
	  DECLARATION.

	  Thus, for example, the following text can be seen as a single
	  DECLARATION:

		    TYPE  INTEGERS = { INT } ;
		    VAR  NUMBERS	=  INTEGERS ;
		    DEFINE	F( X:REAL ) = REAL:   ...   ENDDEFN
		    DEFINE	G( X:INT ) = POINT:   ...   ENDDEFN

	  The order of declarations put together this way is always irrelevant.
	  For example, F can reference G even though G is defined later.


22.5
The Grouping Of DECLARATIONs Into UNITs Of Compilation

	  Programmers deliver DECLARATIONs.	 They deliver function and
	  coercion declarations, type declarations, and global variable
	  declarations.  The wealth of these contributions is realized by calling
	  functions, creating and examining instances of the new types, and/or
	  placing values in and reading values out of the new global variables.

	  As a system grows, as the number of declarations increases, it becomes
	  necessary to organize or group declarations.

	  Declarations may be entered into files.	 Each file may contain many
	  declarations.  ICL reads one file at a time, and compiles all
	  declarations in the file at once.	 Each file containing declarations
	  becomes known to ICL as a ~unit, and ICL compiles one unit at a time.

	  It is possible to ~plug ~in, or ~include any subset of units.  You can
	  use all declarations within that subset of units.  Units not included
	  are inaccessible.  Their declarations are invisible.  Thus for example,
	  if you want the coercion from REAL to INT, you INCLUDE the unit
	  containing that declaration, otherwise, you don't include that unit.

	  Beyond the notations of ICL shown so far, we introduce basically two
	  more notations.	 The first meaningful line in a file containing
	  declarations should be:

		    unit  ID  :

	  The ID gives a name to this unit.	 It is by this name that the
	  declarations contained in this file will be made available to others.
	  In another file, one gains access to the declarations in this unit by
	  using a second notation, saying:

		    include	 ID  ;

	  This ~include stands for all the declarations in the named unit (ID).

	  For example, here is a unit that delivers three declarations:

		    UNIT  ABSOLUTE_VALUE :

		    DEFINE	ABS(I:INT)=INT:  IF I<0 THEN -I ELSE I FI	 ENDDEFN
		    DEFINE	ABS(R:REAL)=REAL: IF R<0 THEN -R ELSE R FI  ENDDEFN
		    DEFINE	ABS(P:POINT)=REAL:
				   SQRT( P.X^2 + P.Y^2 )		    ENDDEFN

	  Now, by INCLUDing unit ABSOLUTE_VALUE, you can use these three ABS
	  functions.  (It is certainly not required that all function names in
	  a unit be the same, although this example happens to do so).

	  In another unit, say MATH_1, the three ABS functions may be used, as
	  one is in:

		    UNIT	MATH_1 :

		    INCLUDE ABSOLUTE_VALUE ;

		    DEFINE	CLOSEST_TO_ORIGIN( PS: SET_OF_POINTS ) = POINT:
			  BEGIN  VAR  P = POINT ;
				PICK	P  MINIMIZING  ABS(P)  FOR P $E PS;
			  END
		    ENDDEFN

	  This unit MATH_1 includes ABSOLUTE_VALUE so as to gain access to the
	  function ABS.

	  ~Includes cannot be circular.  That is, if unit A includes unit B, then
	  unit B may ~not include unit A.

	  The contents of a file of declarations is formed just as described
	  via the following rules of grammar.  These new rules produce the new
	  part-of-speech UNIT_SPEC:

		    unit  ID  :				->	  UNIT_SPEC

		    include	 ID, ID, ..., ID ;	->	  UNIT_SPEC

	  Of course, DECLARATIONs may be part of a unit's specification, and so
	  we include the rule:

		    DECLARATION		    ->	UNIT_SPEC

	  Any sequence of these three forms of UNIT_SPECs makes up a unit, as
	  is supported by the rule:

		    UNIT_SPEC  UNIT_SPEC		->	  UNIT_SPEC


	  The DECLARATION may include the declaration of variables, variables
	  other than those declared within functions.  For example, consider the
	  following unit that contains all three kinds of declaration:

		    UNIT	GENERIC_OUTPUT:

		    TYPE	OUTPUT_DEVICE =  //(CHAR)\\ ;	  "Type declaration"

		    VAR	THE_OUTPUT_DEVICE = OUTPUT_DEVICE;	 "Variable decl"

		    DEFINE	OUTPUT( C: CHAR ) :		  "Function declaration"
			 <*THE_OUTPUT_DEVICE*>(C);
		    ENDDEFN

	  The variable THE_OUTPUT_DEVICE is declared in no function, and hence
	  it is a ~global ~variable.	That variable can be accessed by
	  anybody who INCLUDEs this unit GENERIC_OUTPUT.

	  You may wish to specify also a STATEMENT, outside of any function,
	  which will perform something as soon as compilation is complete, like
	  initializing a global variable.  For example, following the VAR
	  declaration, we might like to assign an initial value into
	  THE_OUTPUT_DEVICE, as in:

		    UNIT	...
		    TYPE	...
		    VAR	...

		    THE_OUTPUT_DEVICE:= //(C:CHAR)	WRITE(C)  \\

		    DEFINE	...

	  This assignment is carried out first thing once this unit is
	  compiled.	 Our assignment makes THE_OUTPUT_DEVICE send characters to
	  the terminal (because we used WRITE).

	  Such initializing STATEMENTs are admitted into unit specifications via
	  the rule:

		    STATEMENT		    ->	UNIT_SPEC



22.5.1
The PRIVATE And PUBLIC Parts Of A UNIT

	  We introduce now a dichotomy into the contents of a unit.	 We
	  introduce the optional "PRIVATE" part, which may coexist with the
	  familiar "PUBLIC" part.  Thus far in our presentation of units, we've
	  assumed that the entirety of a unit's specification resides in the
	  PUBLIC part of the unit.  By default, all parts of a unit in fact
	  reside in the PUBLIC section, and so everything shown so far remains
	  entirely valid.

	  Before we show how to create a PRIVATE part in a unit, let's
	  motivate the existence of a least some kind of dichotomy.

	  The author of a unit experiences an inevitable conflict:	On one
	  hand, the author wants to provide a brief and simple set of bullet-
	  proof functions for use by people who might INCLUDE this unit.	On the
	  other hand, the author generally needs access to other functions and
	  units in order to write the definitions for these functions.

	  For example, the author may wish to define some "intermediate"
	  functions to aid in the definitions of the functions desired
	  originally.  The author needs such "intermediate" functions but
	  simultaneously abhores the thought of giving users access to them.
	  Such intermediate functions are very often necessarily not bullet-
	  proof; they may offer "too much" flexibility and pose great danger if
	  used by anybody less experienced in the application than the author.

	  Not only might the author prefer to render a PRIVATE set of
	  "intermediate" functions, but the author might wish also to INCLUDE
	  privately a set of units, or possibly declare privately some global
	  variables.  A private global is indeed a global variable, but it
	  may be accessed only within the unit where it's declared.	 Rendering
	  items ~private reduces name conflicts within large projects.

	  That is, to aid in the definition of the bullet-proof
	  functions desired originally, the author may need to INCLUDE some
	  (dangerous) units but may simultaneously in all good conscience need
	  to supress their accessability to the (naive) users of the author's
	  new services.


22.5.2
The Keywords PRIVATE And PUBLIC

	  Any declaration can be removed from the public section and be
	  placed into the private section by inserting the keyword PRIVATE in
	  front of those declarations.  The keyword PRIVATE "sets a mode" in that
	  one appearence is sufficient to render all subsequent declarations as
	  PRIVATE, until a subsequent appearence of our second keyword, PUBLIC,
	  sets the mode back to the default.  You may change modes as often as
	  you like.	 You are always started in PUBLIC mode at the top.

	  The PRIVATE and PUBLIC keywords are admitted via the rules:

		    private		  ->	    UNIT_SPEC
		    public		  ->	    UNIT_SPEC


	  Let's render a unit named NUCLEAR_POWER_PLANT.  This unit INCLUDEs
	  publically the units ELECTRICITY and POWER_LINES, as would any power
	  plant.  It INCLUDEs privately the units URANIUM and FISSION, which it
	  must have to operate, but which it does not want to deliver as part of
	  its overall service.	Finally, it defines one function that yields
	  electricity.  Since this one function is the desired service, it is
	  declared publicly.  The body of that function however has access to
	  the private parts, as would the body of any function defined in this
	  unit.

		    UNIT	NUCLEAR_POWER_PLANT:

		    INCLUDE ELECTRICITY, POWER_LINES ;

		    PRIVATE
				INCLUDE URANIUM, FISSION ;
		    PUBLIC

		    DEFINE	POWER_SUPPLY = ELECTRICITY:

			  URANIUM \PURIFIED \FISSION_REACT	\HEAT_WATER \INTO_TURBINE

		    ENDDEFN

	  Presumably the referenced functions

		    ~URANIUM  \purified			->	  ~NUCLEAR_FUEL
		    ~NUCLEAR_FUEL	 \fission_react	->	  ~HEAT

	  are defined somewhere in units URANIUM and FISSION, and the functions:

		    ~HEAT  \heat_water			->	  ~PRESSURE
		    ~PRESSURE  \into_turbine		->	  ~ELECTRICITY

	  are defined somewhere in the units ELECTRICITY and POWER_LINES.

	  Please note that the distinction between PUBLIC and PRIVATE
	  applies to function headers, not to function bodies.  The bodies of all
	  functions in a unit have access to all PUBLIC ~and PRIVATE entities
	  regardless of whether the particular function's header is PUBLIC or
	  PRIVATE.

	  In summary:

	     1)   Anybody who INCLUDEs a unit acquires only its PUBLIC entities,

	  and

	     2)   During the compilation of a unit, the distinction between
		    PUBLIC and PRIVATE ceases to exist in that unit.	All PRIVATE
		    declarations in the unit act as though they are PUBLIC.	 Put
		    another way, you could remove any or all occurences of the
		    keywords PUBLIC and PRIVATE and not affect the legality of
		    your functions whatsoever.

	  Again, the distinction between PUBLIC and PRIVATE manifests itself
	  only when somebody INCLUDEs a unit.



22.6
Interactive ICL

	  Sitting at the terminal, you can specify something for ICL to
	  execute immediately.	Any UNIT_SPEC is valid input, although one
	  usually issues only STATEMENTs.  One may also specify DECLARATIONs,
	  which last as long as the interactive session.  Thus the user can
	  declare functions, coercions, types and/or variables interactively,
	  and then make use of them at will.  The user may also INCLUDE units so
	  as to gain access to their declarations.

	  Interactive ICL expects a UNIT_SPEC followed by a control-G (^G).
	  The ^G instead of the carriage-return was chosen to terminate ICL
	  interactions so as to allow multi-line inputs.

	  For example, to declare a mutually recursive pair of functions, you
	  may want to use two lines to specify them.  Multiple functions or
	  multiple types that depend on one another must be declared in one
	  gulp, with no intervening ^Gs.