Variables, constants, expressions

KEY

Types

KEY Each data item (i.e. each constant or variable) used by an IMP80 program has a type associated with it which determines what sort of item it is or can have as a value. There are five categories of type:

Arithmetic types

KEY These comprise integer and real types, as follows: %byte %integer %short %integer %half %integer %integer %long %integer %real %long %real %long %long %real Some implementations of IMP80 might not provide all of these types; see Appendix B for details.
The modifiers %byte, %short, etc. relate to the size or precision of items of the appropriate type. For byte-addressed machines, the ranges and (where appropriate) precisions associated with arithmetic types are as follows: ______________________________________________________________________ | | | type normal range of values | | storage (inclusive) | | allocation | |______________________________________________________________________| |%byte %integer 8 bits 0 to 255 | |(or just %byte) | |%short %integer 16 bits -32767 to 32767 | |(or just %short) | |______________________________________________________________________|
______________________________________________________________________ | type normal range of values precision| | storage (inclusive) (decimal | | allocation digits) | |______________________________________________________________________| |%half %integer 16 bits 0 to 65535 | |(or just %half) | |%integer 16 bits or -32767 to 32767 or | | 32 bits -2147483647 to 2147483647 | |%long %integer 64 bits -9223372036854775807 to | | 9223372036854775807 | | Integer arithmetic involving values outside the range | | which a variable of type %integer can hold may be invalid. | |______________________________________________________________________| |%real 32 bits \ 7 | | | -7.2x10@75 to -1.2x10@(-77), | |%long %real 64 bits |- 0, 16 | | | 1.2x10@(-77) to 7.2x10@75 | |%long %long %real 128 bits / 36 | |______________________________________________________________________|

String type

KEY The type %string relates to sequences of characters. An item of this type has a length associated with it, the actual or maximum number of characters which the item comprises or can have as a value.

Record types

KEY An item of type %record is a composite of several sub-items, each of which has an associated type. When a variable of type %record is declared, its precise composition must be specified.

Array types

KEY An item of array type is a composite of (in general) several sub-items, each with the same associated type, which must be one of those listed above. The name of the array type is obtained by appending the keyword %array to the name of the type in question. For example: type corresponding array type %byte %integer %byte %integer %array %record (<format>) %record (<format>) %array %string(<n>) %string(<n>)%array

Reference types

KEY An item of this type is, or has as its value, a reference to a variable of a specified type. For each of the foregoing types there is a corresponding reference type, the name of which is obtained by appending the keyword %name to the name of the type in question. For example: type corresponding reference type %byte %integer %byte %integer %name %record (<format>) %record (<format>) %name %string(<n>) %string(<n>)%name %real %array %real %array %name Variables of this type are known as reference variables or pointer variables.

Variables

KEY Variables are named store locations used to hold numeric or textual information. Each variable must be defined in a declaration statement which specifies its type and an identifier to name it. The amount of storage allocated to a variable depends on its type. All variables must be declared at the head of the block in which they are to be used, or in an outer block. The initial value of a variable, i.e. the value assigned to it when it is created, is implementation-dependent; in most cases it is undefined (see Appendix B for details). Any attempt to use a variable whose value is undefined will cause an event to be signalled. {IMP77: all variables can be assigned initial values. The syntax is as for %own variable initialisation, described below. Stack variables are re-initialised whenever they are re-created.} Variables can be divided into four categories:
Arithmetic String Record Reference The following standard integer function is provided (a 'standard' procedure is one which is predefined; see Section 7): %integer %function SIZE OF(%name A) The number of storage units occupied by the given variable is returned. The unit is implementation-dependent but commonly is a byte.

Arithmetic variables

KEY Arithmetic variables may be of two types: %integer and %real. The first holds whole numbers and the second holds numbers with fractional parts. For more efficient use of store, %short, %half, %byte and %long integer types may be provided, whilst greater precision will be obtained when %long %real and %long %long %real are available. However, the provision of different lengths is necessarily hardware dependent, though type %integer will always be available; it corresponds to the word length of the machine. Furthermore, it is possible that on some restricted implementations for small machines, type %real will not be supported. Where implementation is on a byte-addressed machine (e.g. IBM 370, ICL 2900 ranges) %short %integer and %half %integer would be 16 bits in length, %integer 16 or 32 bits, %long %integer 64 bits, and %real types would be 32 bits, 64 bits and 128 bits in length. On such machines, %real variables can only hold values to a precision of 7.2 significant decimal digits whereas %long %real variables are precise to 16.8 decimal digits and %long %long %real variables (if available) to 36 decimal digits. Further details of the representation of variables can be found in the relevant hardware manuals.
The following example illustrates the declaration of various arithmetic variables. Example: %begin %integer I, J %real P, Q %begin %byte %integer Z : : P = I+J+Q Z = 0 : : %end : : %end %of %program
Arithmetic variables can be grouped into arrays. The array bounds separated by the symbol ':' are given in brackets after the array identifier when the array is declared. Example: %integer %array IN(1:10), OUT(1:20) Multi-dimensional arrays can be used. The maximum number of dimensions is implementation dependent. Example: %integer %array BITLIST(-4:4, 1:2, 10:100, 1:2) When an individual array element is accessed, the array identifier is followed by an ordered list of integer expressions (one for each dimension) enclosed in brackets. These integer expressions are called subscripts.
Examples: BITLIST(3, 1, 54, J) BITLIST(I+K, I, 10, 1) Each of these integer expressions must evaluate to an integer which lies within the range described by the bounds for the relevant dimension. A run time fault may occur if the array bounds are exceeded. An array can be declared with integer variables instead of constants for the array bounds. Obviously, the variables used in such a declaration must be declared and given a value before the array declaration occurs.
Examples: %begin %integer TOP READ(TOP); ! TOP is given a value from the input data. %begin %integer %array TABLE(1:TOP) : : %end : %end

String variables

KEY A string variable is one which holds textual information. The maximum length of a string is implementation dependent but is not normally less than 255 characters. When the string variable is declared, the maximum number of characters which the string may hold is specified, in parentheses, after the keyword %string. Example: %string(24) S : S = "Results of last test" As the string of characters may vary in length within the given location while the program executes, an indication of the current length is stored along with the current contents.
In all implementations on byte-oriented machines to date, the current length is held in an extra byte at the front of the string location. Thus the string S declared in the above example would be allocated 25 bytes of storage. As can be seen from the above example, the character " (double quote) is used to delimit textual information to be stored in a string location. Where one double quote character is part of the text, two consecutive double quote characters should occur in the text, to distinguish it from the terminating delimiter. Example: MESSAGE = "Peter says ""No"" " Multi-dimensional string arrays can be used. Note that the maximum number of dimensions is implementation dependent. Each element of a string array must have the same maximum length, which is specified when the array is declared.
Example: %string(63)%array FIELDS (1:5) FIELDS consists of five strings, each of maximum length 63 characters. The occurrence in an IMP program of a semi-colon or newline character normally terminates a statement. However, both are permitted in string constants. Example: S = "A; B; C" SNL = " " A string may be regarded as having a value based on the ISO code values of the characters of the string. Thus the relational operators >, <, =, #, <=, >= may be used to compare strings. In particular, strings composed entirely of alphabetic characters can be regarded as having a dictionary ordering for the purposes of comparison. Example: "AB" < "C" is TRUE "AB" < "ABC" is TRUE "IMP" < "FORTRAN" is FALSE

Record variables

KEY A record is a variable comprising a collection of entities which may be of different types. It has an identifier which refers to the whole collection and each entity has an identifier; an entity (or "sub-field") can be referenced by using the record identifier together with the required sub-field identifier. The collection of sub-fields which makes up the record is described in a record format statement, which specifies the identifier and type of each sub-field. Arrays with constant bounds may be used as sub-fields. Example: %constant %integer FROM=3, TO=5 %record %format F(%byte %integer A, %string(8) S, %integer %array M, F(FROM:TO, 1:400), %real Y) %record (F) R :
Record format statements are placed with other declarations at the head of a block or procedure. They do not cause allocation of storage. Note that the sub-field identifiers need not be distinct from other identifiers in use in the program, as they are always associated with a specific record identifier. A record format may include alternatives. Example: %record %format AS(%byte %integer %array CHAR(0:12) %or %c %string(12) TEXT) The space allocated to a record of this format can be regarded as holding a byte integer array of 13 elements or a string of maximum length 12 characters.
Alternatives provide a means of imposing different interpretations on all or part of a record. Where only part of a record is to have an alternative format, brackets must be used within the record format statement to enclose the alternatives. Example: %record %format AT(%real X, (%byte %integer A, B, C %or %real R %c %or %integer E), %string(10) F) Every sub-field in the record format must be distinct. Each alternative will start at the same address within the record and will be padded out to the size of the largest. (In the example above padding will be added, as the three alternatives are not all of the same size). The amount of padding required depends on the amount of store allocated to each sub-field, which is implementation-dependent (as is the relation between elements in different alternatives).
A record format may contain several sets of alternatives, and alternatives may be nested to any depth. Note, however, that redundant brackets within a record format statement are not allowed. Records are declared at the head of a block or procedure. Space is allocated according to the associated record format statement whose identifier occurs in parentheses in the record declaration. The amount of space occupied by a record of given format is the total number of bytes occupied by all the sub-fields plus the minimum number of 'padding' bytes required to achieve alignment of sub-fields appropriate to their types. This alignment is implementation-dependent. Example: %record %format F(%integer A, %string(8) S) %record (F) R %record (F) PP, QQ, RR
Note that, as in the example above, more than one record may be declared having the same record format. {EMAS IMP80: in a record declaration it is permissible to give the actual record format instead of giving the name of a record format. Example: %record (%integer I, J, %string(7) S) A, B, C It is also permissible to give the name of a record already declared in place of a record format name. The format of the specified record is then taken as the required format for the record being declared. Example: %record (A) D ! A is the record declared in the previous example.
Each sub-field of a record can be referenced as a location of the appropriate variable type by subscripting the record identifier with the sub-field identifier, the two being separated by the underline character '_'. Examples: %record %format F(%integer A, %string(8) S) %record (F) R : %if R_S="INC" %then R_A = R_A+1 : %record %format PE(%integer I, %real %array X(0:10)) %record (PE) P %integer J : P_X(J+1) = P_X(J)*2 : :
Arrays of records are analogous to the arithmetic and string types of arrays already described. Each element of a record array is a record of format specified in the record array declaration. Example: %record %format F(%integer A, %real %array X(1:5)) %record (F) %array RA(1:100) The fifth element of sub-field X in the 76th record array element may be referenced as follows: RA(76)_X(5) As with other types of array, several record arrays having the same bounds and format may be defined in a single declaration. Example: %record (F) %array RR1, RR2(1:100)
A sub-field may be of type %record. In this case its format must have been already declared. In particular, its format may not be the record format being described (c.f. record name sub-fields). Example: %record %format P(%integer %array X(0:4), %integer I) %record %format F1(%integer A, B, %record (P) D) %record %format F2(%record (P) J, K) %record (F1) ENT %record (F2) JAK An arbitrary depth of subscription can thus obtain. Using the above declarations, the following are valid references to record elements: ENT_D_X(1) JAK_J_I
A sub-field of type %record is word-aligned in most implementations, irrespective of the format of the sub-field. Whilst sub-fields of records may be used exactly like IMP80 entities of corresponding type, it is also possible to assign a whole record from one location to another. Two assignment operators are permitted: '=' and '<-'. Both operators require that operands on each side of the assignment refer to %record locations, except in the case where zero occurs on the right-hand side of the '=' operator: this results in the space allocated to the record referenced by the left-hand operand being set to binary zeros. When the '=' operator is used, the record formats associated with the left-hand and right-hand operands must be the same. {EMAS IMP80: the formats need not be the same, but they must have the same length.} The '<-' assignment operator transfers as many bytes from the record referenced by the right-hand operand as will fit into the record referenced by the left-hand operand. The '<-' operator takes no account of record formats. Example: %record %format F(%integer X, Y, Z, A) %record %format Q(%byte %integer %array B(0:15)) %record (F) J %record (Q) %array K(0:100) : : J = K(1) K(1) = 0; ! K(1)_B(0), K(1)_B(1), ..., K(1)_B(15) ! all set to binary zeros. {IMP77: A %record %format %spec statement is provided to enable a record format to be referred to before it has been declared. A statement of the form %record %format %spec <name>
specifies a record format identifier. Until the format is declared fully in a %record %format statement the identifier may only be used in the declaration of record reference variables (described below). Example: %record %format %spec Y %record %format X(%record (Y) %name P, %real VALUE) %record %format Y(%record (X) %name Q, %integer VALUE) Record formats of this sort are useful in list processing when the items in the list are records of alternating format X, then Y, then X, etc.}

Reference variables

KEY A reference variable (or "pointer variable") is one which has as its value, not a constant, but a reference to a variable of a specified type. Reference variables are declared in the same way as the variables to which they can refer, but with the suffix %name added. Example: %integer A %integer %name AREF When a reference variable is declared, space is allocated for a reference to a variable of the corresponding type and precision. The operator "==" is used to establish the reference. Once a reference is established, all references to the reference variable will be redirected to the variable which it references. Note that the reference can be established before the referenced variable has been assigned a value. Reference variables are often used in conjunction with store mapping facilities (see Section 6).
Example: %integer %name N %integer B N == B; ! Reference established : : N = 10; ! Assigns 10 to B : In exactly the same way, a reference to an array can be set up in an %array %name variable of the appropriate type.
Example: %real %array %name P %real %array Q(0:27) %real %name Z P == Q; ! Reference established. : : P(25) = 10.3; ! This puts 10.3 into Q(25). Z == P(27) : : Z = 0; ! This sets the 27th element of Q to zero. : The examples above have been of reference variables of arithmetic types. However, string and record reference variables may also be used.
Example: %string(20)%name SREF %string(20) S : SREF == S : A maximum size must be specified for a string reference variable, as for a string variable. A string reference variable can only refer to a string variable whose maximum size is equal to that of its own. However, where a string reference variable is required to refer to several strings of different maximum sizes, the form %string(*)%name <var> may be used. {EMAS IMP80: the string variable maximum size may be omitted. Whether it is or not, the EMAS IMP80 compiler treats the size specification as '(*)'.}
In the case of record reference variables, the format of the record to be referenced must be specified in the reference variable declaration. Example: %record %format RECFORMR(.....) %record (RECFORMR) REPORT %record (RECFORMR) %name REP2 A reference variable of type %record %name is assigned to by using the '==' operator (as before), where the right-hand operand is a reference to a record location with the same format as that specified for the reference variable.
Example: %record %format F(.....) %record (F) %name F1 %record (F) Q, R %record (F) %array A(1:10) %record (F) %array %name Z, W F1 == Q; ! Makes F1 a synonym for record Q F1 == A(10); ! Makes F1 a synonym for 10th element of A Z == A; ! Makes Z a synonym for A {EMAS IMP80: the record location referenced by the right-hand operand does not have to have the same format as the record reference variable.} {IMP77: when a record reference variable is declared, the format can be specified as (*), meaning that the variable can refer to a record of any format. The reference variable can have no associated sub-fields; it is only of use when it is passed as a parameter to a procedure, to be pointed at subsequently within the procedure by a reference variable with a specific format.}
Note that records may contain sub-fields of type %record %name. In this case the format of the record name sub-field may be the record format being described (c.f. sub-fields of type %record). The following example illustrates how the recursive nature of the format and sub-field format definitions facilitates the creation of a list structure: Example: %record %format F(%integer DATA, %record (F) %name LINK) %record (F) %array P(1:1000) The structure may be initialised as follows so that the 'link' field of each element of the record array P 'points' to the subsequent element: %record %format F(%integer DATA, %record (F) %name LINK) %record (F) %array P(1:1000) %record (F) END %integer J
P(J)_LINK == P(J+1) %for J=1,1,999 P(1000)_LINK == END : : %if P(J)_LINK == END %then .... Note how the link field of the last record in the chain is set to point to the record END.

%own, %constant and %external

KEY Additional properties can be given to variables by means of the prefixes %own, %constant (which can be abbreviated to %const) or %external added to the type in their declarations. An %own variable is allocated storage in such a way that it preserves its value between successive entries to the block or procedure in which it is declared. It can be initialised in its declaration statement. An %own variable can be used in any circumstances in which a normal variable of the corresponding type can be used. A %constant variable is declared in a similar manner to an %own variable, but it cannot be changed from its initial value. Constant variables are also known as "named constants", which better describes them, in that they have all the attributes of constants. Note that they do not have addresses (see ADDR, described in Section 6). Wherever a constant is permitted in an IMP80 program, a "constant expression" can be used instead. A constant expression is one which can be evaluated at compile-time, i.e. its operands are constants or named constants.
Example: %string (73) DELIVERY can be replaced by %constant %integer MAXNAME=20, MAXADDRESS=52 %string (MAXNAME+1{for the newline}+MAXADDRESS) DELIVERY The constant integer NL is predefined: it contains the code value for the newline character. The constant long real PI is predefined. It is the value of pi to the long real precision of the implementation; where 64 bits are used to hold a long real, this is 3.141592653589793. An %external variable is a special form of %own variable which is used to provide communication between sections of program compiled separately (see "External linkage", 3.3). An %external variable can be used in any circumstances in which a normal variable of the corresponding type can be used.
%own, %constant and %external arrays are normally one-dimensional, but need not be. Examples: %constant %byte %integer NUL=0, CR=13, DEL=127, FF=12 %own %long %real RMIN = -3.5@-4, RMAX = 17.23614@10 The initial values to be assigned to %own, %constant and %external variables are specified when the variables are declared. A variable can be followed by =<cexpr> , where <cexpr> is a constant or constant expression of the appropriate type. (A constant expression is one which can be evaluated at compile-time, i.e. made up of constants or variables of type %constant.) The variable is initialised to the value of <cexpr>. If no initial value is specified, the value assigned by default is implementation-dependent.
{EMAS IMP80: %own, %constant and %external variables which are not assigned initial values are set to binary zeros.} {IMP77: %own, %constant and %external variables which are not assigned initial values are undefined, and any attempt to use them before they are assigned will cause an event ("unassigned variable") to be signalled.} {IMP77: the '<-' assignment operator can be used in %own, %constant and %external variable initialisation.} Any identifier being declared as %external may be given an "alias". The details of this facility are described in Section 3.3. An %own, %constant or %external array is initialised by appending a list of values to its declaration. Only one array may be declared per statement. Each element of the array must have a corresponding value with which it is to be initialised. In order to simplify this, each value may be followed by a repetition count in parentheses, and an asterisk, (*), may be used to represent the number of remaining elements of the array. If the array is multi-dimensional, the order in which the array elements are assigned the initial values is implementation-dependent. {EMAS IMP80 and IMP77: in a two-dimensional array whose first element was (1,1), the order would be (1,1), (2,1), (3,1), i.e. first subscript changing fastest.} Examples: %external %integer %array VALUES(-3:7) = %c 17, 4, 23, -2, 3(4), 7, 1(2) %constant %integer RED=1, ORANGE=2, YELLOW=4, GREEN=8, BLUE=16, INDIGO=32, VIOLET=64, WHITE=127 %own %byte %integer %array COLOUR(1:22) = %c RED, VIOLET(3), BLUE+GREEN, VIOLET, INDIGO+ORANGE+BLUE, YELLOW(2), WHITE(*)
The {...} form of comment is useful for commenting array initialisation. Example: %own %integer %array OPCODE(0:20) = %c {opcode values} 16_5800, 16_4800, 16_5000, 16_4000, { L LH ST STH 16_5A00, 16_5B00, 16_5C00, 16_5D00, { A S M D 16_1A00, 16_1B00, 16_1C00, 16_1D00, { AR SR MR DR -1(*) {all the rest} %own, %constant and %external strings can be likewise initialised, with string constants or constant expressions at the time of their declaration. Example: %own %string(19) FILENAME = "ERCC00.TEST" %constant %string(6)%array F(0:4) = "Peter", "Mac", ""(3)
Records may also be declared as %own, %constant or %external, but these may not be initialised at the time of declaration. {EMAS IMP80: the space allocated to such records is filled with binary zeros.} {IMP77: the values of the sub-fields of such records are undefined.} Variables of type %constant %record cannot be assigned at all, unless some implementation-dependent method is provided; see Appendix B. Reference variables may also be declared as %own, %external or %constant. If initialisation is permitted in the implementation, then the initialisation establishes the initial reference in an implementation-dependent manner. This facility is only useful for unusual system programming features.
{Example: EMAS IMP80: the following declaration is valid: %constant %integer %name K INST PER SECOND = X'80C000C0' IMP77: the following declaration is valid: %constant %integer %name K INST PER SECOND == X'80C000C0' The value to which the integer name variable is being initialised specifies a particular storage location, and is therefore system dependent.} The initialisation of constant array name variables, if available, is described in Appendix B.

Constants

KEY Constant values can be assigned to variables. In general, the type of the constant must be the same as the type of the variable, although an automatic type conversion is carried out on a constant of integer type before assignment to a variable of real type.

Decimal constants

KEY Decimal Constants are written in a straightforward notation: 2.538 1 .25 The exponent, where present, consists of the symbol @ followed by an optional sign and decimal digits: -17.28@-1 1@7 The type of a decimal constant depends on its value. It is of integer type if it has no fractional part, i.e. no decimal point in its specification and the exponent (if present) is non-negative; otherwise it is of real type. The particular real or integer type depends upon the magnitude or precision of the constant.

Base constants

KEY A base constant may be constructed by using the prefix <decimal constant>_ to specify the base (up to a maximum of 36) of the subsequent constant. The letters A, B, ..., Y, Z are used to represent the digits 10, 11, ..., 34, 35. Example: 2_1010 ten in Binary 8_12 ten in Octal 9_11 ten in base nine 16_A ten in Hexadecimal An alternative form is provided for constants to bases 2, 8 and 16. The constant is written with the digits enclosed in single quotes and preceded by a code letter for the base, the codes being B for base 2 (Binary), K for base 8 (Octal) and X for base 16 (Hexadecimal). Example: B'1010' ten in Binary K'12' ten in Octal X'A' ten in Hexadecimal Either upper or lower case letters may be used in this form of constant, but spaces may not occur. When a program is to be used on other machines, care should be taken in the use of constants as the values of the constants may vary, particularly in a transfer from a machine using ones-complement arithmetic to one using twos-complement arithmetic, and vice-versa. Base constants are of type %integer. {IMP77: the base can have any positive integer value. However, if it is greater than 36 then not all the digits will be representable by 0...9 and A...Z. Example: I = 256_1234 where I is a four-byte integer, assigns the values 1, 2, 3 and 4 respectively to the four bytes of I.}
{IMP77: a base constant can include a decimal part, in which case it is of type %real. Examples: 3_0.1 {= 1/3} 16_3.102A9 }

Character constants

KEY The ASCII code value of any character may be obtained as an integer value by enclosing the character in single quotes. When the required character is a single quote, it must be represented by two consecutive single quotes. Examples: 'A', 'a', '+', 'o', '"', '''', ' ', ' ' Note the last three examples which represent the code values for single quote, space and newline, respectively. The predefined named constant NL may be used in place of the rather cumbersome form of a newline character enclosed in quotes. The code values for several characters may be packed together to form a single integer constant by enclosing the characters in single quotes and giving the prefix M. Examples: M'over', M'MAX', M'1+2', M'*@@#'
The value of the constant is calculated by evaluating the expression: (..(c1<<b + c2)<<b + c3)<<b + ... where c1, c2... are the characters in the order specified, and b is an implementation-defined constant (commonly 8). The number of characters which can be packed into an integer in this way is (no. of bits in an %integer)//b . Character constants are of type %integer.

String constants

KEY A %string constant is a sequence of characters enclosed in double quote characters, a double quote being represented inside a string constant by two consecutive double quotes. The maximum number of characters allowed in the string is implementation dependent, but is not usually less than 255. Examples: "starting time" "x-y*4+2" "red" "HOOD" The null string, a string of no characters, is permitted and is represented by two consecutive double quote characters (""). A string constant of <n> characters is of type %string(<n>).

Named constants

KEY These are treated in this manual as variables of type %constant (see Section 2.2.5).

Arithmetic operators & expressions

KEY

Arithmetic operators

KEY There are two assignment operators for use with arithmetic expressions: = equals <- jam transfer Where the = operator is used, the expression on the right-hand side is evaluated and the value obtained is assigned to the destination indicated by the left-hand side, provided that the lengths and types are compatible. A fault occurs if an attempt is made to assign too large a value to a variable using this operator. Where the <- is used, only as many bits as will fit the location designated by the left hand side are assigned, starting with the least significant bits. In general the arithmetic assignment instruction assigns the result of evaluating an arithmetic expression to a variable. Only the result of an integer expression may be assigned to an integer variable, but the result of an integer or real expression may be assigned to a real variable.
The following operators may be applied to real and integer variables in arithmetic expressions: _______________________________________ | | | + addition | | - subtraction | | * multiplication | | / real division | | // integer division | | \ real exponentiation | | (e.g. Y\3 = Y cubed) | | \\ integer exponentiation | |_______________________________________|
The established order of precedence for the arithmetic operators is given in the following table, starting with the highest. Operators on the same horizontal line of the table have equal precedence. _________________________ | | | \ \\ | | * / // | | * - | |_________________________| Parentheses may be used to override the natural order of evaluation of an expression or to remove ambiguity. Where operators are of equal precedence, left-hand precedence pertains as in normal mathematical usage.
Examples: A-B+C is equivalent to (A-B)+C A-(B+C) (A)-(B+C) A/B*C (A/B)*C A/(B*C) (A)/(B*C) A**B*C (A**B)*C A**(B*C) (A)**(B*C) The one exception to the left-hand precedence rule is that consecutive exponentiations are evaluated from right to left; thus A**B**C is evaluated as A**(B**C), not as (A**B)**C.

Arithmetic expressions

KEY An arithmetic expression is a sequence of operators and integer or real operands obeying the elementary rules of algebra. Expressions may be real or integer according to context. Apart from the rules for operator precedence given above, no assumptions may be made about the order of evaluation of expressions.

Integer expressions

KEY An expression is evaluated as integer if it is being assigned to an integer variable, or passed as an integer value parameter, or occurs in a position where an integer expression is mandatory. All the operands and operators in an integer expression must yield integer values. The operators available for use in integer expressions are: + addition - subtraction * multiplication // integer division. This operator always yields an integer result. The result consists of a quotient whose sign is determined algebraically and a remainder which is ignored. Note that dividend and divisor must both be integer expressions.
\\ integer exponentiation. This operator only operates on integer variables and always yields an integer result which is obtained by repeated multiplication. The exponent must be an integer expression with a value in the range 0 < exp < 63. The precision used in evaluating integer expressions depends on the operands. Variables of type %byte %integer, %short %integer and %half %integer are expanded to normal integer precision before the operation is carried out. An operation between an integer variable and a long integer variable will be carried out by long integer arithmetic. However, **** is anomalous in that long integer **** integer is carried out by repeated long integer multiplication but integer **** long integer is carried out by repeated integer multiplication. The following standard integer functions are provided (a 'standard' procedure is one which is predefined; see Section 7):
%integer %function IMOD(%integer I) This function returns the modulus (absolute value) of the parameter. {IMP77: the modulus of an integer expression can also be obtained by enclosing the expression between vertical bars; e.g. |I-J| .} %integer %function INT PT(%long %real L) This function returns the integer part of L, any truncation being towards zero. Hence INT PT(-1.5)=-1. An event is signalled if the result cannot be held in an integer variable.
%integer %function INT(%long %real L) This function returns the nearest integer to the parameter, truncation being towards zero. It is thus equivalent to: %integer %function INT(%long %real L) %result = INT PT(L+0.5) %end

Real expressions

KEY All the operands and operators in a real expression must yield real or integer values, and assignment can only be made to a real variable. Integer values will automatically be converted into their real equivalents before being used. The operators available for use in real expressions are: + addition - subtraction * multiplication / division ** real exponentiation. This always yields a real result. Where the exponent is an integer expression, the operation is carried out by repeated multiplication. A negative exponent, e.g. X**(-4), is evaluated as 1/X**4.
{EMAS IMP80: where the exponent is a real expression, the result is obtained by using the standard functions LOG and EXP, and events relating to these functions may be signalled.} A real expression is evaluated to single precision until a long real variable is encountered. Thereafter the expression is evaluated to double precision. Double precision work is time and space consuming and should only be used when strictly necessary to preserve accuracy. However, it is often required with floating-point arithmetic where loss of accuracy may occur in addition and subtraction due to cancellation of significant figures. The following standard real functions are provided (a 'standard' procedure is one which is predefined; see Section 7):
%long %real %function FRAC PT(%long %real L) The fractional part of the parameter L is returned as the result. Note that the fractional part is always treated as being greater than or equal to zero; e.g. FRAC PT(-4.6) is 0.4 . %long %real %function MOD(%long %real I) This function returns the modulus (absolute value) of the parameter. {IMP77: the modulus of an real expression can also be obtained by enclosing the expression between vertical bars; e.g. |X-Y| .} %long %real %function FLOAT(%integer N) The floating-point equivalent of the integer parameter is calculated and returned as the result.

Logical ops and expressions

KEY Logical operations are performed on bit patterns stored in integer variables, which may be of any of the permitted lengths. Before the operation is carried out, byte, short, and half integer variables are made up to full integer length in one of two ways, according to the length of the initial variable: a) byte and half integers are made up by filling the left hand bits with zeros; b) short integers are made up by sign extension, i.e. the leftmost bit of the variable - the sign bit - is propagated leftwards until the necessary number of bits have been obtained. Where necessary, integers are made up to long integer precision by sign extension. There are two assignment operators available for logical expressions. = equals treats the result of the logical operation as a signed integer and attempts to perform an arithmetic assignment to the designated variable. Hence it is not always possible to put the result back into a variable of the same precision as that in which an operand of the logical expression was originally held.
<- jam transfer copies the bit pattern of the expression indicated by the right hand side into the variable indicated by the left hand side, starting with the least significant bits and stopping when the variable has been filled. The choice of assignment operator depends on the context of the program. The following is a list of the logical operators available, excluding the assignment operators discussed above.
_________________________ | | | << left shift | | | | >> right shift | | | | & and | | | | ! or | | | | !! exclusive or | | | | \ (or ~) not | |_________________________| The shift operators allow the programmer to move the bit pattern of an integer of any length to the left or right by a number of places less than the number of bits in the specified integer.
Example: J = I>>N This causes integer I to be shifted to the right the number of places specified by N and the result stored in integer J. If I or N are of less than integer precision they will be made up to integer precision, as described above, before the operation takes place. In a left shift, bit positions vacated at the right hand end are filled with zeros and bits shifted off the left hand end are lost. In a right shift, bit positions vacated at the left hand end are filled with zeros and bits shifted off the right hand end are lost. Note that a shift of more than N-1 characters will result in an integer whose value is implementation- dependent, not necessarily zero-filled. The operators &, !, !! are carried out on a bit-by-bit basis between the patterns stored in two integer variables. Where one operand is a long integer, the other will be made up to long integer by sign extension.
'and' (&) produces a pattern containing a 1-bit where the two source patterns both have 1-bits and containing 0-bits elsewhere. 'inclusive or' (!) produces a pattern containing a 0-bit where the two source patterns both have 0-bits and containing 1-bits elsewhere. 'exclusive or' (!!) produces a pattern containing a 1-bit where the bits in the source patterns are different and contains 0-bits elsewhere. These rules are summarised in the following table:
______________________________ | | | | Operands | & ! !! | |____________|_________________| | | | | 0 0 | 0 0 0 | | | | | 0 1 | 0 1 1 | | | | | 1 0 | 0 1 1 | | | | | 1 1 | 1 1 0 | |____________|_________________| The \ operator operates on a single operand to invert the value of each bit; that is, 0-bits become 1-bits and vice versa.
Example: If X contains the bit pattern 01....0100110011 then \X is 10....1011001100 thus \X + X is 11....1111111111
Arithmetic and logical operators may occur in the same arithmetic expression. The established order of precedence, starting with the highest, is: ________________________ | | | \ | | | | ** >> << | | | | * / // & | | | | + - ! !! | |________________________| Operators given on the same line in the above table have equal precedence.
Example: %integer I, J ! Variables of type %integer are assumed to have 32 bits ! in this example. %byte %integer %array B(0:3) : I = .... : B(J//8) = I>>(24-J) & X'FF' %for J = 0,8,24 : In this example, a 32-bit integer I is copied, in groups of 8 bits, into the byte integer array B. Note that X'FF' represents a bit pattern of eight 1s in the least significant end of the specified location and zeros elsewhere.

String ops and expressions

KEY There are three assignment operators available for use with strings: "=", "<-" and "->". Where "=" is used, the string expression on the right-hand side is evaluated and assigned to the string location specified on the left-hand side. The string expression must evaluate to a string constant which is no larger than the maximum which the left-hand string location can hold. A run-time error will occur if the left-hand string location overflows. "<-" is known as the "jam transfer" operator. It will assign to the location specified on the left-hand side only as many characters of the right-hand string as will fit. Any remaining characters from the right-hand end of the string being assigned will simply be omitted and no error will occur. "->" is known as the "string resolution" operator. It is used exclusively for the manipulation of strings. Its effect is described below.
Another operation exclusive to strings is "concatenation". This allows them to be joined in a prescribed order. The strings to be concatenated are listed in the required order and separated by the symbol '.' . Example: %begin %string(65) S %string(15) NAME1, NAME2, NAME3 %string(20) ADDRESS NAME1 = "Peter " NAME2 = "John " NAME3 = "Smith " ADDRESS = "12 Bothwell Drive" S = NAME1.NAME2.NAME3.ADDRESS PRINTSTRING(S) NEWLINE %end %of %program
String S is assigned the concatenated characters of the four strings NAME1, NAME2, NAME3 and ADDRESS. Thus the printed output would read Peter John Smith 12 Bothwell Drive Note that the string NAME3 has a newline character in the text after the name Smith. The only type of string expression in IMP80 is that produced by concatenation, for which bracketed expressions are neither required nor permitted. String resolution allows a string to be searched for a specified substring of characters. If this substring does not occur in the string being resolved, an error condition occurs. If, however, the substring is found on searching the string from left to right, then all characters to the left and right of the substring will be stored respectively in two strings specified to the left and right of the substring in the resolution instruction. The substring, which may be a string expression (a constant, a variable or a concatenation), is enclosed in parentheses with a string identifier on either side, each of these three elements being separated by '.' . Example: S = "ERCC00.FLAG" S -> A.(".").B ! A now contains "ERCC00" and B contains "FLAG". Thus string S has been split into two smaller strings neither of which include '.' . The same exercise would be accomplished by the following: S = "ERCC00.FLAG" X = "." S -> A.(X).B
The substring may be a concatenation: Example: FIRST NAME = "John" SURNAME = "Smith" NAME AND ADDRESS = "Peter John Smith, 12 Bothwell Drive" NAME AND ADDRESS -> A.(FIRST NAME." ".SURNAME).B {EMAS IMP80: multiple resolution is permitted; it is treated as a series of simple resolutions. Example: S = "WINSTON SPENCER CHURCHILL" S -> A.(" ").B.(" ").C The above resolution will be treated as S -> A.(" ").PRIV %and PRIV -> B.(" ").C}
The strings used to store the characters which occur before and after the specified substring may be omitted, in which case the characters are discarded. Examples: S = "ERCC00.FLAG" S -> (".").B ! B now contains "FLAG". S = "ERCC00.FLAG" S -> A.(".") ! A now contains "ERCC00". S = "ERCC00.FLAG" S -> (".") ! Resolution would fail if "." did not occur in S. ! There are no other products of this resolution.
Since a resolution must either succeed or fail, it may be used as a simple condition. Examples: S = A.B %while S -> A.(" ").B ! This statement removes all spaces from string S. %if S -> A.("/").B %then T = A." or ".B Note that, although the string resolution is used here as a condition, it is nonetheless carried out if it can be (i.e. if the condition is true).
There are four procedures provided for the manipulation of strings. %byte %integer %map CHAR NO(%string(*)%name S, %integer N) This map returns a reference to the Nth character of string S. An event is signalled if N is negative or greater than the current length of S. %byte %integer %map LENGTH(%string(*)%name S) The result is a reference to a variable containing the current length of the string S. %string(*)%function SUBSTRING(%string(*)%name S, %integer I, J) The result is the substring of S comprising the Ith to Jth (inclusive) characters of S. An event is signalled unless 1 <= I <= LENGTH(S) and I-1 <= J <= LENGTH(S). If J=I-1 then a null string is returned.
%string(1)%function TO STRING(%integer I) The result is a string of length 1 comprising the character defined by the least significant byte of integer I. Example: %string(80) S %integer %name L : : L == LENGTH(S) L = L-1 %while L>0 %and CHARNO(S,L) = ' ' ! This example shows how to delete trailing spaces ! from a string.

Record operators

KEY The only record operators taking complete records, rather than record sub-fields, as their operands are the assignment operators '=', '<-' and '=='. These are described above, in 2.2.3/9 .