!TITLE Variables, constants, expressions !KEY ! ! ! !) %record () %array %string() %string()%array !> !) %record () %name %string() %string()%name %real %array %real %array %name Variables of this type are known as reference variables or pointer variables. !> !> ! !, <, =, #, <=, >= 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 !> ! !PAGE 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.} !> ! 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 '(*)'.} !PAGE 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. !PAGE 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.} !PAGE 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 !PAGE 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. !PAGE 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. !PAGE %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 = , where 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 . If no initial value is specified, the value assigned by default is implementation-dependent. !PAGE {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(*) !PAGE 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) !PAGE 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. !PAGE {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. !> !> ! !_ 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.} !PAGE {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 } !> ! ! characters is of type %string(). !> ! !> ! ! ! !> !> !> 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. !PAGE 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. !PAGE '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: !PAGE ______________________________ | | | | 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. !PAGE Example: If X contains the bit pattern 01....0100110011 then \X is 10....1011001100 thus \X + X is 11....1111111111 !PAGE 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. !PAGE 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. !> !". 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. !PAGE 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 !PAGE 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 !PAGE 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} !PAGE 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. !PAGE 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). !PAGE 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. !PAGE %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. !> !