.CH "Operators Useful in Procedure Definitions"
.ti
.op "ADDAA_OP                 1"
int 1
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the sum of the values of the
left and right operands.
As a side effect, the sum is stored back into the left operand.
The left operand must be an lvalue or a bit field (see FIELD_OP).
Both operands must have the same mode as the ADDAA operation.
The operation mode may not be STOWED.
.sp
ADDAA stands for "add and assign."
This operator is normally used to implement the addition assignment operator
("+=" in C, "+:=" in Algol 68).
.bx
Example:  i += 1 (where i is an integer object with object id 12)
         1              ADDAA_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "ADD_OP                   2"
int 2
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the sum of the values of the
left and right operands.
Both operands must have the same mode as the ADD, and STOWED mode is
not allowed.
.sp
ADD is used to implement simple addition of fixed or floating point
values.
.bx
Example:  i + 1 (where i is an integer object with object id 12)
         2              ADD_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "ANDAA_OP                 3"
int 3
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the bitwise logical "and" of the
values of the left and right operands.
As a side effect, the conjunction is stored back into the left operand.
The left operand must be an lvalue or a bit field (see FIELD_OP).
Both operands must have the same mode as the ANDAA operation;
the only allowable modes are INT, UNSIGNED, LONG INT, and LONG UNSIGNED.
.sp
ANDAA stands for "'and' and assign."
ANDAA_OP is used to implement the logical-and assignment operator
("&=" in C).
.bx
Example:  i &= 1 (where i is an integer object with object id 12)
         3              ANDAA_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "AND_OP                   4"
int 4
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the bitwise logical-"and" of
the values of the left and right operands.
Both operands must have the same mode as the AND operation;
the only allowable modes are INT, LONG INT, UNSIGNED, and LONG UNSIGNED.
.sp
AND_OP is normally used to implement the bitwise logical conjunction
of integers ("&" in C).
Although AND_OP can be used to implement conjunction in Boolean expressions,
the short-circuit conjunction operator (SAND_OP) is probably a better
choice, since it guarantees evaluation order and prevents undesirable
side effects.
.bx
Example:  i & 1 (where i is an integer object with object id 12)
         4              AND_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "ASSIGN_OP                5"
int 5
int mode
tree left
tree right
int length
.bd
The result of this operator is an rvalue, namely the value of the right
operand.
As a side effect, the result is stored into the left operand.
The left operand must be an lvalue or a bit field (see FIELD_OP).
Both operands must have the same mode as the ASSIGN operation.
Any mode is allowable, but the parameter
'length' must be set to the operand length, in 16-bit words.
.sp
ASSIGN implements the semantics of assignment statements in most
algorithmic languages.
Note that STOWED mode values are allowed, so things like Pascal
record assignment can be handled.
.bx
Example:  i = 1 (where i is an integer object with object id 12)
         5              ASSIGN_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
         1                 length of assigned quantity is 1 word
.ex
.op "BREAK_OP                 6"
int 6
int levels
.bd
BREAK_OP yields no result value, but
causes an exit from one or more enclosing loops or
multiway-branch ("switch," in C terminology; "case" in Pascal) statements.
The operand 'levels' is an integer giving the number of nested loops
and multiway branches to terminate.
Obviously, 'levels' must be between 1 and the number of nested loops
and multiway branch statements currently active, inclusive.
.sp
BREAK is mainly intended to implement premature loop exits.
Because of (inadequate) historical reasons, a BREAK is also required
to force control out of a multiway-branch alternative to the end of
the statement.
Thus, in implementing a Pascal-style case statement with the SWITCH_OP
described below, each alternative would end with a BREAK_OP
with 'levels' equal to 1.
If the BREAK_OP was missing, control would fall through from
case to case, as it does in C.
.bx
Example:  break 2  (terminate 2 enclosing loops)
         6              BREAK_OP
         2                 Levels to break
.ex
.op "CASE_OP                  7"
int 7
tree value
tree actions
tree next_case
.bd
CASE is used to label an alternative in a multiway branch statement
(like 'switch' in C or 'case' in Pascal).
The 'value' parameter is the case label value for the alternative;
it must be a CONST_OP node of the same mode as the switch expression
(see SWITCH_OP).
The mode may not be STOWED.
The 'actions' parameter is the code to be executed for the given case
label.
The 'next_case' operand is a DEFAULT_OP or another CASE_OP
or a NULL_OP (for the last alternative in the multiway-branch).
.sp
CASE_OP is simply a structural device; it organizes the alternatives
in a multiway-branch so that variable-sized SWITCH operators are not
necessary.
.bx
Example:  case 10: i += 1   (i is an integer with object id 12)
         7              CASE_OP
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         10                   value of first word is 10
         1                 ADDAA_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         9                    CONST_OP
         1                       INT_MODE
         1                       length is 1 word
         1                       value of first word is 1
         7 or 12 or 39     CASE_OP or DEFAULT_OP or NULL_OP,
                           depending on next element of SWITCH
.ex
.op "CHECK_LOWER_OP          72"
int 72
int mode
tree expression
tree lower_bound
int source_line_number
.bd
The result of this operator is an rvalue, the value of the parameter
'expression'.
The expression must have the mode given by the parameter 'mode',
and may not be FLOAT, LONG_FLOAT, or STOWED.
If at run time the value of the expression is less than the value of
the expression
given by the parameter 'lower_bound', an error message is printed
and a RANGE_ERROR exception raised.
The parameter 'source_line_number' is printed as part of the error
message, and is identified as the number of the source code line
that caused the range check to be generated.
.sp
This operator would normally be used in a situation that permitted
optimized range checking, like assignment of one integer subrange
variable to another.
.bx
Example:  var i: 0..100; j:  1..100; begin ...; j := i; ... end
          (where i has object id 12 and j has object id 13,
          and the code above appears on line 14)

         5        ASSIGN_OP
         1           INT_MODE
         40          OBJECT_OP
         1              INT_MODE
         13             Object id for j
         72          CHECK_LOWER_OP
         1              INT_MODE
         40             OBJECT_OP
         1                 INT_MODE
         12                Object id for i
         9              CONST_OP
         1                 INT_MODE
         1                 Length is 1 word
         1                 Value is 1
         14             Line number in source code
         1           Length of assigned quantity is 1 word
.ex
.op "CHECK_RANGE_OP          70"
int 70
int mode
tree expression
tree lower_bound
tree upper_bound
int source_line_number
.bd
The result of this operator is an rvalue, the value of the parameter
'expression'.
The expression must have the mode given by the parameter 'mode',
and may not be FLOAT, LONG_FLOAT, or STOWED.
If at run time the value of the expression is less than the value of
the expression
given by the parameter 'lower_bound'
or greater than the value of the expression given by the parameter
'upper_bound'
an error message is printed
and a RANGE_ERROR exception raised.
The parameter 'source_line_number' is printed as part of the error
message, and is identified as the number of the source code line
that caused the range check to be generated.
.sp
This operator would normally be used where a complete range check
was necessary (an array subscripted by an unconstrained integer variable,
for example).
.bx
Example:  var a: array 1..10 of integer; i: integer; ...a[i]...
          where 'a' has object id 4, 'i' has id 12,
          and the subscripting operation appears on line 97
          of the source code:

         25       INDEX_OP
         1           INT_MODE (element type of a)
         40          OBJECT_OP; this is the base address of 'a'
         7              STOWED_MODE
         4              Object id of 'a'
         70          CHECK_RANGE_OP; this is the index expression
         1              INT_MODE
         40             OBJECT_OP
         1                 INT_MODE
         12                Object id of 'i'
         9              CONST_OP; this is the lower bound
         1                 INT_MODE
         1                 Length of constant is 1 word
         1                 Value of constant is 1
         9              CONST_OP; this is the upper bound
         1                 INT_MODE
         1                 Length of constant is 1 word
         10                Value of constant is 10
         97             Range check is on line 97
         1           Array element size is 1 word
.ex
.op "CHECK_UPPER_OP          71"
int 71
int mode
tree expression
tree upper_bound
int source_line_number
.bd
The result of this operator is an rvalue, the value of the parameter
'expression'.
The expression must have the mode given by the parameter 'mode',
and may not be FLOAT, LONG_FLOAT, or STOWED.
If at run time the value of the expression is greater than the value of
the expression
given by the parameter 'upper_bound', an error message is printed
and a RANGE_ERROR exception raised.
The parameter 'source_line_number' is printed as part of the error
message, and is identified as the number of the source code line
that caused the range check to be generated.
.sp
Like CHECK_LOWER, this operator is normally used in situations that
permit optimized range checks.
.bx
Example:  var i: 1..100; j:  1..10; begin ...; j := i; ... end
          (where i has object id 12 and j has object id 13,
          and the code above appears on line 14)

         5        ASSIGN_OP
         1           INT_MODE
         40          OBJECT_OP
         1              INT_MODE
         13             Object id for j
         71          CHECK_UPPER_OP
         1              INT_MODE
         40             OBJECT_OP
         1                 INT_MODE
         12                Object id for i
         9              CONST_OP
         1                 INT_MODE
         1                 Length is 1 word
         10                Value is 10
         14             Line number in source code
         1           Length of assigned quantity is 1 word
.ex
.op "COMPL_OP                 8"
int 8
int mode
tree operand
.bd
The result of this operator is an rvalue, the bitwise complement of
the operand.
The operand must have the same mode as the COMPL operation;
the only allowable modes are INT, LONG INT, UNSIGNED, and LONG UNSIGNED.
.sp
This operator implements bitwise complementation in languages that
support bit operations (e.g. the "~" operator in C).
In most cases, it should not be used for logical negation;
the NOT_OP is more appropriate.
.bx
Example:  ~i (i is an integer object with id 12)
         8                 COMPL_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id is 12
.ex
.op "CONST_OP                 9"
int 9
int mode
int length
int word[1]
int word[2]
...
int word[length]
.bd
The result of this operator is an rvalue, equivalent to the value of the
constant it defines.
'Length' is the length of the constant in 16-bit machine words.
'Mode' may take on any of the operand mode values, although
STOWED constants are not of much use outside initializers.
.sp
CONST_OP is the only operator whose IMF representation varies in length
depending on its contents.
Most literals in a source language program eventually are expressed as
CONST_OPs in the IMF.
.bx
Example:  14 (an integer constant)
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         14                   first word has value 14
.ex
.op "CONVERT_OP              10"
int 10
int source_mode
int destination_mode
tree operand
.bd
The result of this operator is an rvalue, namely the value of the
operand converted to the data mode specified by 'destination_mode'.
The operand mode must be the same as 'source_mode'.
STOWED mode is not permissible in either mode parameter.
Note that in most cases, no range checking is performed;
it is possible, for example, to convert an UNSIGNED quantity into an
negative INT quantity.
Floating point to integer conversions are performed by truncation.
.sp
CONVERT is the only means of converting data from one mode to another;
the code generator never coerces data from one mode to another, unless
the coercion is called for by a CONVERT operator.
.bx
Example:  x = i (x is a FLOAT object, with id 6;
                 i is an INT object, with id 12)
         5                 ASSIGN_OP
         5                    FLOAT_MODE
         40                   OBJECT_OP
         5                       FLOAT_MODE
         6                       Object id is 6
         10                   CONVERT_OP
         1                       from INT_MODE
         5                       to FLOAT_MODE
         40                      OBJECT_OP
         1                          INT_MODE
         12                         Object id is 12
.ex
.op "DECLARE_STAT_OP         11"
int 11
int object_id
string external_name
.bd
See "Operators useful in the Static Data Stream".
.bx
.ex
.op "DEFAULT_OP              12"
int 12
tree actions
tree next_case
.bd
This operator is used to label the default action in a
multiway-branch statement.
(In C, the default action is labeled "default"; in Pascal, it is
labeled "otherwise".)
The DEFAULT_OP need not be the last alternative in the list of
alternatives following a SWITCH.
A DEFAULT_OP behaves much like a CASE_OP, in that control will
fall through to the next alternative unless the actions conclude
with a BREAK_OP.
.bx
Example:  default: i += 1 (where i is an integer object with id 12)
         12             DEFAULT_OP
         1                 ADDAA_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         9                    CONST_OP
         1                       INT_MODE
         1                       length is 1 word
         1                       value of first word is 1
         7 or 39           CASE_OP or NULL_OP, depending on structure
                           of SWITCH
.ex
.op "DEFINE_DYNM_OP          13"
int 13
int object_id
tree init_list
int size
.bd
This operator causes storage for the object identified by 'object_id'
to be allocated in the current stack frame.
It is generated for local variable declarations and for temporary
variables allocated by the front end.
'Object_id' must be used in all subsequent references to the object,
and the object's definition with DEFINE_DYNM must precede all
such references.
The init_list is a list of expressions whose values will be assigned
to successive words of the newly-declared object (see INITIALIZER_OP
and ZERO_INITIALIZER_OP).
The size parameter specifies the amount of storage to be reserved for
the object, in 16-bit words.
(Slightly fewer than 65,535 words are available for local storage in each
procedure.)
.sp
When processing a declaration, the front-end should assign each declared
variable an integer "object id."
To be safe, the object id should be unique within an IMF module.
This object id must be used whenever the variable being declared is
referenced.
.bx
Example:  int blank = 160;    (a local declaration; assume 'blank'
                              is assigned the object id 4)
         13             DEFINE_DYNM_OP
         4                 Object id is 4
         26                INITIALIZER_OP
         1                    INT_MODE
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         160                     Value of first word is 160
         39                   NULL_OP (end of init list)
         1                 Size is 1 word
.ex
.op "DEFINE_STAT_OP          14"
int 14
int object_id
tree init_list
int size
.bd
This operator causes storage for the object identified by 'object_id'
to be allocated in the current link frame (static data area).
It is normally generated by the front end for global variable declarations.
'Object_id' must be used in all subsequent references to the object,
and the object's definition with DEFINE_STAT must precede all
such references.
The init_list is a list of [ul constants] whose values will be assigned
to successive words of the newly-declared object
(see INITIALIZER_OP and ZERO_INITIALIZER_OP).
The size parameter specifies the amount of storage to be reserved for
the object, in 16-bit words.
(Slightly fewer than 65,535 words are available for static storage in each
module.)
.sp
Any storage reserved by a DEFINE_STAT_OP that is not filled
by an initializer will be set to zero.
.sp
When processing a declaration, the front-end should assign each declared
variable an integer "object id."
To be safe, the object id should be unique within an IMF module.
This object id must be used whenever the variable being declared is
referenced.
.bx
Example:  int blank = 160;    (a global declaration; assume 'blank'
                              is assigned the object id 4)
         14             DEFINE_STAT_OP
         4                 Object id is 4
         26                INITIALIZER_OP
         1                    INT_MODE
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         160                     Value of first word is 160
         39                   NULL_OP (end of init list)
         1                 Size is 1 word
.ex
.op "DEREF_OP                15"
int 15
int mode
tree operand
.bd
The result of this operator is an lvalue, the object whose address
is given by the value of the operand.
The operand must yield a 32-bit LONG INT or LONG UNSIGNED value.
The operation mode is not restricted.
.sp
DEREF is one of the few operators that yield an lvalue, and are
therefore allowed as left-operands of assignments.
DEREF is normally used for indirection through pointers in languages
that support them explicitly (eg "^" operator in Pascal, or unary "*"
in C), although it is also useful in obtaining the value of a variable
that is passed to a procedure by reference.
.bx
Example:  i = *p  (or i = p^ in Pascal)
                  (i is an integer object with id 12;
                  p is a long unsigned object with id 32)
         5              ASSIGN_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id is 12
         15                DEREF_OP
         1                    INT_MODE
         40                   OBJECT_OP
         4                       LONG_UNS_MODE
         32                      Object id is 32
.ex
.op "DIVAA_OP                16"
int 16
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the quotient of the value
of the left operand divided by the value of the right.
As a side effect, the quotient is stored back into the left operand.
The left operand must be an lvalue or a bit field (see FIELD_OP).
Both operands must have the same mode as the DIVAA operation;
any mode other than STOWED is acceptable.
.sp
DIVAA stands for "divide and assign."
The operator is usually used to implement the division assignment
operator ("/=" in C, "/:=" or "divab" in Algol 68).
.sp
If the operation mode is UNSIGNED or LONG UNSIGNED and the right
operand is a power of 2, the division will be performed by a right
logical shift.
.bx
Example:  i /= 10 (where i is an integer object with object id 12)
         16             DIVAA_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         10                   value of first word is 1
.ex
.op "DIV_OP                  17"
int 17
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, the quotient of the value
of the left operand divided by the value of the right.
Both operands must have the same mode as the DIV operation, and the
mode STOWED is not allowed.
.sp
DIV is used to implement simple division.
.sp
If the operation mode is UNSIGNED or LONG UNSIGNED and the right
operand is a power of 2, the division will be performed by a right
logical shift.
.bx
Example:  i / 10 (where i is an integer object with object id 12)
         17             DIV_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         10                   value of first word is 1
.ex
.op "DO_LOOP_OP              18"
int 18
tree body
tree condition
.bd
This operator implements a test-at-the-bottom loop.
'Body' specifies the operations to be performed in the loop.
The loop is performed until the value of the expression specified
by 'condition' is non-zero.
A BREAK_OP may be used to terminate execution of the loop from
within the body, and a NEXT_OP may be used to cause an immediate
transfer to the condition test from within the body.
.sp
It is not kosher to use a DO_LOOP as a value-returning construct.
.bx
Example:  do i *= 2 until (i > j)
          (where i and j are integer objects, with ids 12 and 60)
         18             DO_LOOP_OP
         33                MULAA_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id is 12
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         2                       Value is 2
         23                GT_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id is 12
         40                   OBJECT_OP
         1                       INT_MODE
         60                      Object id is 60
.ex
.op "EQ_OP                   19"
int 19
int mode
tree left
tree right
.bd
The result of this operator is an rvalue: 1 if the value of the left
operand equals the value of the right, and 0 otherwise.
Both operands must have the mode specified by the parameter 'mode',
but note that the result mode of EQ is [ul always] INTEGER.
The operation mode may not be STOWED.
.sp
EQ is used to implement test-for-equality for both expressions yielding
Boolean values and for control flow tests.
The restriction against STOWED operands will hopefully be lifted in the
near future.
.bx
Example:  i == 1 (where i is an integer object with object id 12)
         19             EQ_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "FIELD_OP                69"
int 69
int mode
int offset_from_msb
int length_in_bits
tree base_address
.bd
FIELD is used to select a partial field of a word or double word.
It may be used on the left hand side of assignments, to cause the
right hand side value to be placed in the field, or as an rvalue,
to yield the value stored in the field.
The operation mode must be INT, UNSIGNED, LONG INT, or LONG UNSIGNED.
The parameter 'base_address' is an lvalue which specifies the first
16-bit word containing any portion of the bit field.
The parameter 'offset_from_msb' gives the offset, in bits, of the beginning
of the field from the left-hand (most significant) bit of the first word.
The parameter 'length_in_bits' gives the length of the bit field.
Bit fields may be 1 to 32 bits in length, and must be aligned so as not
to cross more than one word boundary.
.sp
FIELDs behave like lvalues in most circumstances;
for instance, they can be used in left-hand-sides of assignments.
However, bit fields cannot be addressed, so they may not be passed
by reference on procedure calls or used as an operand of the REFTO
operator.
FIELDs can always be used as rvalues.
.sp
Bit fields may not cross more than one word boundary, since this
would require 48 bit shifts for field extraction.
Formally, this means that
'offset_from_msb'[bl]+[bl]'length_in_bits' must be less than or
equal to 32.
.bx
Example:  Fetching the right-hand byte of a 16-bit word in
          the integer object i, with id 12:

         69       FIELD_OP
         1           INT_MODE
         8           Bit field begins 8 bits from the most
                     significant bit
         8           Bit field is 8 bits long
         40          OBJECT_OP; the base address of the field
         1              INT_MODE
         12             Object id for 'i'
.ex
.op "FOR_LOOP_OP             20"
int 20
tree init
tree cond
tree reinit
tree body
.bd
The FOR_LOOP_OP implements the general-purpose C 'for' loop.
The parameters 'init', 'reinit', and 'body' correspond to statements;
'cond' corresponds to a Boolean expression.
The for-loop
.be
for (init; cond; reinit) statement
.ee
is equivalent to
.be
init; while cond do begin statement; reinit end
.ee
A typical application in languages other than C might be the
construction of an arithmetic loop like the Pascal 'for' or the
Fortran 'do'.
.sp
Within the body of the loop, a BREAK_OP may be used to cause early
loop termination, and a NEXT_OP may be used to cause an immediate
jump to the 'reinit' code in preparation for another iteration.
.sp
It is not reasonable to use a FOR_LOOP as a value-returning construct.
.bx
Example:  for (i = 1; i <= n; i += 1)
              j *= i;
           (where i, j, n are integers with object ids 12, 60, 44)
         20             FOR_LOOP_OP
         5                 ASSIGN
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         1                       Value is 1
         1                    Assign 1 word
         28                LE_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         40                   OBJECT_OP
         1                       INT_MODE
         44                      Object id 44
         1                 ADDAA_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         1                       Value is 1
         33                MULAA_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         60                      Object id 60
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
.ex
.op "GE_OP                   21"
int 21
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, 1 if the value of the left
operand is greater-than-or-equal-to the value of the right, 0
otherwise.
Both operands must have the mode given in the parameter 'mode';
note, however, that the result of GE is [ul always] of mode INTEGER.
The operation mode may not be STOWED.
Note that if the operands are unsigned, a "magnitude" comparison is
performed to insure correct results.
.sp
GE_OP implements the test for greater-or-equal in both Boolean
expressions and flow-of-control tests.
The restriction against STOWED operands may be lifted someday.
.bx
Example:  i >= 1 (where i is an integer object with object id 12)
         21             GE_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "GOTO_OP                 22"
int 22
int object_id
.bd
GOTO_OP is used to implement unrestricted 'goto' statements in languages
that support such nonsense.
The parameter 'object_id' is the integer object identifier of the label
which is the target of the goto.
(See LABEL_OP).
.sp
The stack is [ul not] adjusted if the target label is outside the current
procedure.
.bx
Example:  goto label    (where 'label' has object id 99)
         22             GOTO_OP
         99                Object ID of target label
.ex
.op "GT_OP                   23"
int mode
tree left
tree right
.bd
The result of this operator is an rvalue, 1 if the value of the left
operand is greater than the value of the right, 0 otherwise.
Both operands must have the mode given by the parameter 'mode';
but note that GT always returns a value of mode INTEGER.
The operation mode may not be STOWED.
Note that if the operands are of mode unsigned, a "magnitude"
comparison will be performed to insure correct results.
.sp
GT implements the test for greater-than for Boolean expressions and
expressions in flow-of-control context.
The restriction against STOWED operands might be lifted if the public
demands it.
.bx
Example:  i > 1 (where i is an integer object with object id 12)
         23             GT_OP
         1                 INT_MODE
         40                OBJECT_OP
         1                    INT_MODE
         12                   Object id 12
         9                 CONST_OP
         1                    INT_MODE
         1                    length is 1 word
         1                    value of first word is 1
.ex
.op "IF_OP                   24"
int 24
int mode
tree condition
tree then_part
tree else_part
.bd
IF can be used to implement conditional expressions or conditional
evaluation of statements; it always returns an rvalue.
If the value of the condition is non-zero, the 'then_part' will be
evaluated; otherwise, the 'else_part' will be evaluated.
Either 'then_part' or 'else_part' may be omitted (ie, replaced by a
NULL_OP).
The operation mode may not be STOWED;
if the operator is used to return a value (as in a conditional
expression) then the modes of both the 'then_part' and the 'else_part'
must be the same as the operation mode.
.sp
IF is most often used to implement conditional statements (eg
the 'if' statement of most algorithmic languages).
Since the code generator tends to view operators as value-returning,
IF may also be used to implement conditional expressions
('if'-'then'-'else' in the Algol family, or '?:' in C).
.bx
Example:  if a < b then m = a else m = b
         (where a, b, m are floating point objects with id's 1, 2, 13)
         24             IF_OP
         5                 FLOAT_MODE
         31                LT_OP
         5                    FLOAT_MODE
         40                   OBJECT_OP
         5                       FLOAT_MODE
         1                       Object id 1
         40                   OBJECT_OP
         5                       FLOAT_MODE
         2                       Object id 2
         5                 ASSIGN_OP
         5                    FLOAT_MODE
         40                   OBJECT_OP
         5                       FLOAT_MODE
         13                      Object id 13
         40                   OBJECT_OP
         5                       FLOAT_MODE
         1                       Object id 1
         2                    Length is 2 words
         5                 ASSIGN_OP
         5                    FLOAT_MODE
         40                   OBJECT_OP
         5                       FLOAT_MODE
         13                      Object id 13
         40                   OBJECT_OP
         5                       FLOAT_MODE
         2                       Object id 2
         2                    Length is 2 words
.ex
.op "INDEX_OP                25"
int 25
int mode
tree array_base
tree index_expression
int element_size
.bd
The result of this operator is an lvalue,
one member of a vector of identical objects.
The parameter 'array_base' is the base of the vector; it is typically
a simple OBJECT_OP, although it may be an expression yielding the base
address of the vector (a dereferenced pointer, for example).
It must be an lvalue.
The 'index_expression' selects the particular vector element desired;
it should have a value greater than or equal to zero and less than the
number of elements in the vector.
(Note that this implies zero-origin addressing.)
(Note furthermore that there is no subscript checking.)
The 'index_expression' must be of mode INTEGER or UNSIGNED
(indexing across 64K-word segment boundaries produces incorrect results
in V mode).
'Element_size' is the size of one element of the vector, in 16-bit words.
The operation mode must be the same as the mode of the vector elements,
but is otherwise unrestricted; in particular, STOWED mode is allowed.
.sp
INDEX is used to implement array subscripting.
The operator has deliberately been made rather primitive, to allow
the front-end greater freedom in selecting storage layouts.
For example,
multidimensional arrays may be implemented by treating arrays
as vector elements, and subsuming the additional addressing calculations
in the 'index_expression'.
This allows a compiler to select row- or column-major addressing.
Note that subscripting is vastly more efficient if vector elements
are a power of 2 words in length, and furthermore that lengths
1, 2, and 4 are most efficient.
.bx
Example:  a[i + 1]  (where a is a floating point object with id 1,
                    and i is an integer object with id 12)
         25             INDEX_OP
         5                 FLOAT_MODE
         40                OBJECT_OP
         7                    STOWED_MODE
         1                    Object id 1
         2                 ADD_OP
         1                    INT_MODE
         40                   OBJECT_OP
         1                       INT_MODE
         12                      Object id 12
         9                    CONST_OP
         1                       INT_MODE
         1                       Length is 1 word
         1                       Value is 1
         2                 Array element is 2 words long
.ex
