Let's implement the heart of a language that involves datatypes.
	This will let us show a language that has to make sense in more
	than one domain.

Syntax Parts-Of-Speech

	We begin by declaring the syntax parts-of-speech:

		POS	EXPR[8] : -  ;	"Semantic actions is to generate
					 phrases in the datatype language."

		POS	STATEMENT : -  ;  "Like EXPR"
		POS	QUANTIFIER : -  ;  "Like EXPR"

	The semantics of all these parts-of-speech are the same.  Each
	generates phrases in the datatype language.

	In our original example language, the semantics
	of these parts-of-speech were to generate machine language programs.
	Who generates machine language programs now?

Datatype Parts-Of-Speech

	It is the semantics of the datatype grammar that will now generate
	machine language programs.  Let's declare the parts-of-speech of
	  the datatype grammar.

	  We first declare one giant array of parts-of-speech to encompass all

		    POS	TYPE[10000] : -  ;   "Semantic action is to generate a
							    machine language program which
							    when executed, will leave the
							    answer in register 1"

	  We have allowed for 10000 types.	Type declarations will allocate new
	  types from this array of parts-of-speech, by using a new index for each
	  new type.

	  Let's give names to the first three parts-of-speech in TYPE:

		POS	BOOL = TYPE[1] ;
		POS	INT  = TYPE[2] ;
		POS	REAL = TYPE[3] ;

	Now for example, the part-of-speech INT is the second part-of-speech in
	the array TYPE.

	The semantic action of each TYPE part-of-speech generates a machine
	language program that leaves the answer in register 1.  That is,
	our TYPE parts-of-speech behave identically to the
	semantics of EXPR shown in Chapter 8.

The Lefthand Side Of Assignments - Target Types

	When an EXPR (e.g., a variable) appears on the lefthand side of an
	assignment statement, it still has a type.  However, not just any EXPR
	is valid on the lefthand side.  We want only some forms of EXPR to
	appear on the lefthand side.

	Different requirements are made of lefthand side EXPRs than righthand
	side EXPRs.  Where righthand side EXPRs ultimately generate machine
	language that leaves the answer in  register 1, lefthand side EXPRs
	must behave quite differently.  On the lefthand side, we want the EXPR
	to take an answer in register 1 and ~store it some place.

	We therefore declare another array part-of-speech which denotes ~target
	~types.  We will expect a target type on the lefthand sides of
	assignment statements, and a regular type on the righthand sides.

	We declare the target type array part-of-speech:

		POS	TARGET_TYPE[10000] : -  ;
					"Semantic action is to generate a
					 machine language program which when
					 executed, will read the value in
					 register 1 and store it some place."

	Each regular type has a corresponding target type, and vice versa.
	That is,

		TYPE[i]	    corresponds with    TARGET_TYPE[i]

	An assignment statement will require the same value for I on the
	lefthand and righthand EXPRs, as in:

		~TARGET_TYPE[i]   :=   ~TYPE[i]  ;

STATEMENTs In The Datatype Language

	Finally, we need a part-of-speech in the datatype grammar to denote
	STATEMENTs.  STATEMENTs don't represent values, and so no type is
	  associated with STATEMENTs.	 So that STATEMENTs will still have
	  meaning in the datatype grammar, we declare the part-of-speech SS2:

		    POS	SS2 : -  ;	    "Semantic action is to generate a
						     machine language program"

	  A STATEMENT's semantics will be to generate the phrase <SS2>, a phrase
	in the datatype language.

	The semantics of the SS2, as commented just now, is to generate a
	machine language program that carries out the statement.  No mention
	is made of register 1 as no value is involved.

		BOX:	What is the semantic action of EXPR?
		BOX:	What is the semantic action of each of TYPE and
		BOX:	What relationship is required between the TARGET_TYPE
		BOX:	on the lefthand side of an assignment and the righthand
		BOX:	side's TYPE?

An Example Language

Numbers And Floating Numbers

	  The rule:

		    NUMBER		  ->	    EXPR

	  used to read as:

		    <NUMBER:N>	  ->	    <EXPR:	LOAD( 1, ADDRESS_OF(N) );   >

	  The semantics of the EXPR would generate a machine language program
	  that loads into register 1 the number.	However, now we require that
	  the semantics of EXPR generate a phrase in the datatype language.
	  In this case, we want to generate the phrase <INT>.

	  We generate the phrase <INT> by writing:

		    <INT: ... >

	  We do that within the semantics of the EXPR, as in:

		    <NUMBER:N>	  ->	    <EXPR:	 <INT: ... >   >

	  This EXPR's semantics will now generate the phrase <INT>.

	It is the semantics of the datatype grammar that is supposed to
	generate machine language now.  Let's specify those semantics under
	  the part-of-speech INT, as in:

		    <INT:	LOAD( 1 , ADDRESS_OF(N) );   >

	  Put all together, the NUMBER syntax rule is:

	     <NUMBER:N>	  ->	  <EXPR:
						    <INT:	LOAD( 1 , ADDRESS_OF(N) );   >

	  Now, the semantics of the EXPR generates the datatype phrase <INT>,
	  whose own semantics generates machine language which leaves the answer
	  in register 1.	This rule is now consistent with our new conventions
	  for EXPR and TYPE.

	  Similarly, we have a rule for floating numbers, numbers specified with
	  a decimal point:

	     <FLOATING_NUMBER:N>     ->

						    <REAL:	LOAD( 1 , ADDRESS_OF(N) );   >

	  The semantics of the EXPR generate the datatype phrase <REAL>.
	  The <REAL>'s semantics generate machine language, as we expect.
	As of now, two distinct types can appear, INT and REAL.


	Let's now introduce the famous EXPR-BOP-EXPR rule:

		<EXPR[I]:E1>  <BOP[J]:B>  <EXPR[K]:E2>		    ->

				IF  I =< J	&  K < J  THEN

					  <EXPR[J]:		<*E1*>; - <*E2*>; - <*B*>;   >


	  The surrounding IF statement is explained in Section 3.2.1.
	  This rule performs:

		    <EXPR[J]:	<*E1*>; - <*E2*>; - <*B*>;	  >

	  upon seeing an EXPR-BOP-EXPR.  The semantics of the resulting EXPR
	  generate a reverse polish phrase.

	  That is, the semantics of EXPR has E1 generate phrases for the
	  lefthand EXPR, then has E2 generate phrases for the righthand EXPR, and
	  then finally has the BOP generate phrases.  These three phrase
	  generations are built left-to-right, because these actions are
	  connected together by dashes.

	  We've seen example EXPRs.  Here are some example BOP rules:

		+	->	<BOP[3]:   <PLUS>   >
		*	->	<BOP[2]:   <TIMES>  >

	"+"'s semantics generates the datatype phrase <PLUS>, and "*"
	  generates <TIMES>.  We declare the parts-of-speech <PLUS> and <TIMES>,
	  as in:

		    POS	PLUS: - ;	    "Semantics ignored"
		    POS	TIMES:- ;	    "Semantics ignored"

	  Now, what datatype phrase(s) will the following syntax generate?

		    1 + 2.5

	  The EXPR-BOP-EXPR rule generates:

		    phrase_for_1	 phrase_for_2.5	phrase_for_+

	  The phrase for "1" (a NUMBER) is generated by the semantics of the

		    <NUMBER:N>	  ->	    <EXPR:	 <INT: ... >   >

	  Those semantics of the "1" EXPR generate the phrase INT.
	  The semantics of the "2.5" EXPR generate the phrase REAL.	 The
	  semantics of the "+" BOP generates the phrase PLUS.	 Thus, the phrase:

	    phrase_generated_by_1  phrase_generated_by_2.5  phrase_generated_by_+

	  is actually:

		    ~INT  ~REAL  plus

	  This phrase, while being generated, will be augmented by the
	  application of rules from the datatype grammar.  (Those rules may
	  turn the INT into a REAL, and then rewrite the whole thing as one full-
	  spanning REAL).

		    BOX:	What do the semantics of each of NUMBER and FLOATING_
		    BOX:	NUMBER rules do?
		    BOX:	What about the semantics of the EXPR-BOP-EXPR rule?

Example Datatype Rules

	  Datatype rules may be built-in or may be contributed by declarations.
	  One built-in rule is:

		    ~REAL  ~REAL	plus			->	  ~REAL

	  We specify this rule formally as:

		    <REAL:X>  <REAL:Y>	PLUS		->

						    <REAL:	 INSTRUCTION( 270, X, Y );   >

	  The semantics of REAL, a member of the array part-of-speech
	  TYPE, is to generate code that leaves the answer in register 1.	 This
	  new REAL's semantics is a call to the function INSTRUCTION.  The op-
	code 270 passed in is presumably the number for the machine language
	instruction ~floating_add.

	INSTRUCTION invokes each of X and Y so as to generate machine language
	which loads answers into register 1.  It then assembles the machine
	instruction whose op-code is given, to combine the two answers, leaving
	the result in register 1.  Chapter 8 showed things like this.

	Another rule, which could be built-in or contributed by a coercion
	declaration is:

		~INT	->	~REAL

	Written formally, it appears as:

		<INT:X>		->	<REAL:   INSTRUCTION(300,X);   >

	The semantics of the resulting REAL is a call to INSTRUCTION (like
	we've just seen with PLUS).  This call will invoke X so as to get the
	  matched INTeger into register 1.	It then assembles an instruction
	  of the given op-code 300.  The op-code 300 presumably is the
	  ~convert_integer_to_real instruction.

	  Here is a larger set of datatype rules:

		<INT:X>  <INT:Y>	PLUS	    ->	<INT: INSTRUCTION(170,X,Y); >
		<REAL:X>  <REAL:Y>  PLUS    ->	<REAL: INSTRUCTION(270,X,Y); >

		<INT:X>  <INT:Y>	TIMES	    ->	<INT: INSTRUCTION(171,X,Y); >

		<INT:X>			    ->	<REAL: INSTRUCTION(300,X);  >

A Variable Is An EXPR

	  An ID can be an EXPR, a variable, as supported by the following rule:

	     <ID:I>		->	  <EXPR:

						    [ADDRESS:A  TYPE:T] :=  I \LOOKUP;

						    IF  T <> 0  THEN

								<TYPE[T]:	     LOAD(1,A);	>

								<TARGET_TYPE[T]:	STORE(1,A); >


	  The first line after the BEGIN loads into our variables A and T the
	  ~address of and the ~type of the given ID.

	  That ID is presumably a declared variable.  LOOKUP yields NIL if no
	  variable by that name has been declared.  That will assign into A a
	  NIL and into T a zero.

	  If the variable does exist, its type T will be non-zero.	In this case,
	  we generate ~two phrases:

		    <TYPE[T}:   LOAD( 1, A );	  >
		    <TARGET_TYPE[T]:   STORE( 1, A );   >

	  The first phrase's part-of-speech (TYPE[T]) is the type of the given
	variable.  Its semantics naturally loads into register 1 the contents
	of the variable's address (A).

	  We also generate:

		    <TARGET_TYPE[T]:   STORE( 1, A );   >

	  This presents the variable as a target type, which will be required
	  ultimately if this ID appears on the lefthand side of an assignment
	  statement.  (We will get to the assignment statement rule shortly).

	  The semantics under the target type takes the value in register 1 and
	  stuffs it someplace, namely into the address of the given variable (A).
	  This is a correct action for a target type to perform.

		    BOX:	How many phrases does the rule:
		    BOX:		  ID	    ->	EXPR
		    BOX:	generate during the EXPR's semantics?
		BOX:	How is the type of the variable (the ID) acquired?

The Assignment Statement

	The rule for assignment statements follows:

	    <EXPR:L>  ':='  <EXPR:R>  ';'	   ->

				     T1,T2 = INT;

				"Acquire the possible types of L and R ..."

				L1:=   [>   <*L*>;   <]  ;
				R1:=   [>   <*R*>;   <]  ;

				"Look thru those types ... "

				WANT  <TYPE[T1]:RHS>  FROM  R1;

				WITH  T1 = T2 ;

					<SS2:	"Load into register 1..."

						"Store from register 1..."

	We first set L1 and R1 to the CHOICE_OF_PHRASES (i.e., set of types)
	generated by the lefthand and righthand EXPRs, as in:

		L1 :=   [>   <*L*>;   <]  ;

	This has L generate its phrases, and sets L1 to all of the full-
	spanning unit-length phrases generated by L's invocation.

	  We then look at each TYPE in R1, the righthand EXPR, setting T1 to
	  each matched type, as in:

		    WANT   <TYPE[T1]:RHS>  FROM  R1 ;

	  This sets not only T1, but it sets also RHS to the semantics of the
	  matched type.

	  Against each of those matches, we consider all the TARGET_TYPES of L1,
	  setting T2 to the target type and LHS to its semantics.

	  For all iterations caused by those nested ("!!") quantifiers, we
	  preserve only those iterations when T1 and T2 are equal (the WITH
	  clause).	Thus, we receive in LHS and RHS only the semantics of EXPRs
	  having the same type (T1=T2).

	  The body of the loop:

		    <SS2:	<*RHS*> ;	    "Load into register 1"
				<*LHS*> ;	    "Store from register 1"

	  generates the phrase SS2.  Recall that SS2 is a part-of-speech in the
	  datatype grammar that we wish STATEMENTs to generate.  The semantics
	  of the SS2 generate machine language which carries out the assignment.

	  The execution of RHS, being the semantics of TYPE, generates code that
	  loads the righthand side into register 1.  The subsequent execution of
	  LHS, being the semantics of TARGET_TYPE, generates code that moves
	  data from register 1, and stores it some place, e.g., into the variable
	  that makes up the assignment statement's lefthand side.

	If there is no type in common between L1 and R1, this quantifier causes
	zero iterations.  No SS2 is generated.  The assignment statement thus
	has no interpretation in the datatype language.

		BOX:	In the assignment statement, what relation is required
		BOX:	of the lefthand and righthand side EXPRs?
		BOX:	What does L1 hold?
		BOX:	What does LHS hold?
		BOX:	Why did we use the "!!" instead of, say "&&" to
		BOX:	combine the two WANT-quantifiers?


	The rule for the IF-THEN-ELSE follows:

	    IF  <EXPR:i>  THEN  <EXPR:t>  ELSE  <EXPR:e>  FI	->

			        IF2, THEN2, ELSE2 = BASIC_PROCESS; T1,T2 = INT;

			IF1:=    [>   <*I*>;   <]  ;
			THEN1:=  [>   <*T*>;   <]  ;
			ELSE1:=  [>   <*E*>;   <]  ;


			WITH	T1 = T2;



	We first assign into IF1, THEN1, and ELSE1, the set of possible types
	(a CHOICE_OF_PHRASES) for each of the IF-THEN-ELSE's components, as

		    IF1:=	[>   <*I*>;	  <]	;

	  We then demand, via a WANT quantifier, a BOOL interpretation for IF1,
	  the IF-clause.	IF2 winds up holding the semantics of the matched
	  BOOL.  We then consider all types in THEN1 and ELSE1.  T1 and T2 denote
	  the type of each.  Only for those iterations where T1 and T2 match
	  (the WITH clause) do we go on to generate a phrase.

	  Each iteration, if any, has IF2 holding the semantics of a BOOL, and
	  THEN2 and ELSE2 holding the semantics of a common type (T1=T2).	 Given
	  these, we generate a phrase:

		    <TYPE[T1]:  IF_THEN_ELSE( IF2, THEN2, ELSE2 );   >

	  This phrase represents the common type (T1) of the THEN and ELSE
	  clauses.	The semantics for this type are given now in the function
	  IF_THEN_ELSE, which looks like things we've seen already in Chapter 8:



		<* IF2 *> ;		"Get IF boolean into register 1"

		JUMPEQ( 1 ,  (ELSE:= NEW;)  ) ;		"Jump if FALSE"

			<* THEN2 *>;			"The THEN clause"

			JUMP(  (EXIT:= NEW;)  );	"end of THEN clause"

		EQU( ELSE );		"Beginning of ELSE clause"

			<* ELSE2 *>;	"The ELSE clause"

		EQU( EXIT );		"End of IF-THEN-ELSE"

		BOX:	Does the IF-THEN-ELSE rule require that then THEN
		BOX:	clause be of one specific type?
		BOX:	What does each of the variables, E, ELSE1, and ELSE2
		BOX:	hold?


	Our example language in Chapter 8 did not support general
	quantification.  Here, like in ICL, we introduce a part-of-speech
	QUANTIFIER.  QUANTIFIERs may be combined and modified, before their
	ultimate destiny, when a QUANTIFIER is ~applied to a STATEMENT so as to
	cause the STATEMENT to execute repeatedly.

	Before we introduce more grammar rules, let's see how quantifiers are
	  represented and implemented.  The essence of a quantifier is declared
	  next, the type QUANT_PARTS:

						     RESUME:  BASIC_PROCESS  ] ;


	  The START component generates code which prepares for the ~first
	  iteration.  RESUME generates code that prepares for all ~non-first
	  iterations.  Figure 26.1(a) shows how these two parts of a quantifier
	  are placed to surround the body of the loop.

	  Notice how START gets control first.  When START is complete, we are
	  ready for the first iteration, and so we enter the loop body (that
	  which will be executed repeatedly).  When the loop body finishes its
	  first execution, we fall into the RESUME code.  The RESUME code
	  prepares for the ~next iteration and then goes back to the loop body.

	  As shown so far, our loop never terminates.  RESUME ~always goes back
	  to the loop body, forever.

	  We expect however that the quantifier itself should be responsible for
	  causing termination.	We therefore let each of START and RESUME
	  generate code that can ~conditionally escape out from the loop.

	  We invent a LABEL called QUANT_EXIT for START's and RESUME's code
	  to escape to.  While the quantifier may jump to QUANT_EXIT, the
	  quantifier itself does ~not define where QUANT_EXIT is.

	  QUANT_EXIT is setup prior to START's and RESUME's generation of
	  machine language code.  It is the procedure that ~applies the
	  QUANTIFIER to a STATEMENT that defines where QUANT_EXIT is.

	  Figure 26.1(b) shows how we assemble the application of a QUANTIFIER to
	  a STATEMENT, including START's and RESUME's ability to escape by
	  jumping to QUANT_EXIT.  We now declare the LABEL variable QUANT_EXIT:


	  We show once again the declaration of the type QUANT_PARTS, written
	  with comments stating the convention:

								  "Generates code that prepares
								   for the first iteration"

								  "Generates code that prepares
								   for non-first iterations"
						    ] ;

					  "The code generated by each can rely on the
					   global variable QUANT_EXIT.  They jump there
					   when no more iterations are to be had"

	  Following is how we combine a QUANTIFIER and a STATEMENT.	 It assembles
	  what figure 26.1(b) shows:



		    HOLDING QUANT_EXIT:= NEW;		"Tell the QUANT where to exit"

		    DO	<*Q.START*>;		"Set up for first iteration"

				EQU((LOOP:= NEW;));	"Loop entry"

					  <*LOOP_BODY*>;	   "The body of the loop"

					  <*Q.RESUME*>;	   "Setup for next iteration"

					  JUMP(LOOP);	   "Go back to loop body"

				EQU(QUANT_EXIT);		"End of loop"
								"(Here when Q is exhausted)"


		    BOX:	What do the START and RESUME code of a quantifier do?
		    BOX:	What is the label QUANT_EXIT refer to?
		    BOX:	How many times does the START code execute, and
		    BOX:	similarly for the RESUME code?
The QUANTIFIER and QQ2 Parts-Of-Speech

	  We declared the syntax part-of-speech QUANTIFIER earlier as:

		    POS	QUANTIFIER : -  ;		"Semantic action is to generate
								 phrases in the datatype

	  Like a STATEMENT, a QUANTIFIER does not represent a value.  We
	  therefore do not want it to be a member of the array part-of-speech

	  We invent a new part-of-speech, QQ2, to represent quantifiers
	  in the datatype language.  We have done the same for STATEMENTs,
	  inventing the new datatype part-of-speech SS2.  Here we declare QQ2:

		    POS	QQ2 :	 QUANT_PARTS  ;

	  Unlike the part-of-speech SS2 and the array TYPE, the semantics of
	  a QQ2 is not an action.  The semantics are of type QUANT_PARTS.
The WHILE Quantifier

	  Here is the rule for the WHILE quantifier:

		  WHILE  <EXPR:X>	 ';'			->

				<QUANTIFIER:    WANT  <BOOL:B>  FROM  [>	<*X*>;  <]	;

								<QQ2:	  WHILE_QUANT(B)	>

	  The semantics of the QUANTIFIER insists upon seeing the EXPR X as a
	  BOOL, which we expect of a WHILE quantifier.	The set of all possible
	  types of the EXPR X are acquired by the:

		    [>  <*X*>;  <]

	  which causes X to execute, generating the possible phrases (types) of
	  the EXPR.	 The "[>...<]" delivers the generated phrases as a
	  CHOICE_OF_PHRASES, which is always required in the FROM part of a WANT
	  quantifier.  For each BOOL interpretation of the EXPR we generate QQ2
	  to represent the valid quantifier in the datatype language.

	  (If no BOOL can be found, then WANT causes zero iterations and no QQ2
	  is generated, indicating that there is no valid interpretation for the

	  The definition for the referenced function WHILE_QUANT follows:


		    [START:	  //[B;]
					  JUMPEQ( 1, QUANT_EXIT );	    \\

		     RESUME:  //[B;]
					  JUMPEQ( 1, QUANT_EXIT );	    \\	]

	  This function generates a QUANT_PARTS, which is used as the semantics
	  of the QQ2.

	  The START and RESUME code generators are identical.	 Each invokes B,
	  the EXPR, so as to generate code that evaluates the BOOLean EXPR,
	  leaving in register 1 a zero for FALSE or non-zero for TRUE.  In case
	  of FALSE, which means the WHILE quantifier should terminate, the
	  generated code in START and RESUME in fact jumps to the label
	  QUANT_EXIT.  In case of TRUE, the generated code falls thru, ready to
	  execute the loop body again.

		    BOX:	How many iterations will be had if the START code
		    BOX:	jumps to QUANT_EXIT?
		    BOX:	How is the requirement that the while-EXPR be of type
		    BOX:	BOOL expressed here?
		    BOX:	What happens if the while-EXPR has no BOOL
		    BOX:	interpretation?

	  Following is the rule that applies a QUANTIFIER to a STATEMENT:

		<QUANTIFIER:q>  DO  <STATEMENT:s>  END		    ->


					  Q1:=   [>	  <*Q*>;   <]  ;
					  S1:=   [>	  <*S*>;   <}  ;

					  WANT  <QQ2:Q2>	FROM	Q1;
					  WANT  <SS2:S2>	FROM	S1;

						    <SS2:	APPLY(Q2,S2)    >

	  We first have the quantifier and statement generate phrases in the
	  datatype language, and capture those phrases ("[>...<]"), assigning
	  them to Q1 and S1.  We then insist that Q1 be interprettable as a QQ2,
	  and S1 as an SS2.  The two WANTs together will cause an iteration only
	  when these desired interpretations exist.

	  Such an iteration generates the phrase SS2, indicating that a valid
	  interpretation exists for the resulting STATEMENT.	The semantics of
	  the resulting SS2, a call to APPLY, generates the machine language
	  code which has the quantifier cause repeated execution of the given
	  statement.  (APPLY was defined earlier).
Combining Two Quantifiers

	  The following rule supports the combination of QUANTIFIERs, via "&&",

		<QUANTIFIER:A>  '&&'  <QUANTIFIER:B>		    ->

						 A2, B2 = QUANT_PARTS;

					  A1:=   [>	  <*A*>;   <] ;
					  B1:=   [>	  <*B*>;   <] ;

					  WANT  <QQ2:A2>	FROM	A1 ;
					  WANT  <QQ2:B2>	FROM	B1 ;
						    <QQ2:	LOCK_STEP(A2,B2)	 >

	  We first insist that each of the two given QUANTIFIERs be seen as QQ2s,
	  valid quantifiers in the datatype language.  For each such
	  interpretation, we generate QQ2 for the combined quantifier.  (If one
	  or the other of the given quantifiers fails to be interprettable as
	  QQ2, then we generate no QQ2 for the combined quantifer).

	  Given the semantics of the two QQ2s, objects of type QUANT_PARTS, we
	  deliver as the semantics for our new QQ2 the result of calling
	  LOCK_STEP.  LOCK_STEP takes in two QUANT_PARTS and delivers a
	  QUANT_PARTS for the resulting QQ2:


		    [START:	 //[A;B;]
						    <*B.START*>;		    \\

		     RESUME: //[A;B;]
						    <*B.RESUME*>;		    \\	]


	  The resulting START code starts up both of the given quantifiers.  The
	  resulting RESUME code resumes both of the given quantifiers.  Thus,
	  we prepare for the first iteration by having both quantifiers prepare
	  for the first iteration.  Similarly, both quantifiers prepare for non-
	  first iterations together.	This is what lock-stepping means.

	  This concludes our example language with datatypes.	 Other rules are
	  similar to those just shown.

		    BOX:	If two while-quantifiers are combined via "&&", what
		    BOX:	condition will cause the combined quantifier to
		    BOX:	terminate?
		    BOX:	Can you always be sure here that the while-
		    BOX:	EXPR of the second quantifier will be evaluated at
		    BOX:	least once?