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 .