This document is a work-in-progress conversion of the Edinburgh IMP Language Manual (1974)
which has been OCR'd by OlmOCR2 and is now being manually reformatted.
Edinburgh IMP Language Manual
A description of the IMP Language as implemented by ERCC
Second edition
June 1974
PREFACE
This edition of the IMP Language Manual is intended to replace in part, the
Edinburgh IMP Language Manual published in 1970. Two associated manuals are
being prepared - the 'Edinburgh IMP/FORTRAN System Library Manual' which will
contain details of all the items in the IMP system library and 'A Syntactic and
Semantic Definition of the IMP Language as Implemented at the Edinburgh Regional
Computing Centre'. This edition contains some material from its predecessor, and
some new material. The sections on Strings, Records, Conditional Instructions and
Input/Output facilities have been completely rewritten. The references to Job Control
requirements have been removed; the user is referred to the User Manual for the
appropriate computer for information on this topic.
The IMP programming language has been implemented on several computers. This man
ual describes the current version running on ICL 4/75 and IBM 370/158 computers.
These machines both use 32 bit words and byte addressing. Other implementations
of the language use machines with different word lengths and addressing. The
user who is likely to move his IMP programs to other machines should ensure
that he is aware of these and other differences between implementations of the
language.
The Manual is intended as a reference manual rather than a teaching manual. Little
attempt has been made to order material in a sequence suitable for a newcomer
to programming. It has been assumed that the reader has some knowledge of
programming in IMP or a similar language. On the other hand facilities which
are not usually found in other high level languages, e.g. Records and Strings,
are described in considerable detail since it is likely that in these areas at
least the manual will have to serve as a teaching manual.
The Manual is the work of many people in the Edinburgh Regional Computing Centre.
Particular mention should be made of the contributions of Keith Yarwood, Gordon
Burns, Peter Stephens and Andrew McKendrick. Anne Tweeddale, Laura Lang and
Dorothy Kidd, together with staff of the Reprographics section were all
involved in the production of the Manual.
Roderick McLeod
Editor
May 1974
CONTENTS
SECTION TITLE
1 Basic Language
2 Arithmetic Operations
3 Logical Operations
4 Control of Sequence of Instructions
5 Storage Allocation and Block Structure
6 Routines and Functions
7 Store Mapping
8 Strings
9 Records
10 Input/Output
11 Aids to Program Development
12 Compile Time Faults
13 Run Time Faults
14 Fault Trapping
15 Internal Character Code
16 Routines, Functions and Maps in the IMP Library
Index
SECTION 1 - THE BASIC LANGUAGE
TYPING CONVENTIONS FOR IMP PROGRAMS
Programs written in IMP are typed on some form of data preparation equipment,
for example a card punch or a teletype, according to the following rules:
1. Only the first 72 character positions in a line may be used.
2. Statements must be separated by a newline character or a
semi-colon.
3. Apart from text contained within quotes all letters must be in
upper case.
4. Spaces are only significant where they appear within quotes, or
where they follow a word which is a delimiter.
5. Delimiters, which have a pre-defined meaning in the language, are
sequences of symbols. When these are letters they are preceded by a
% sign to distinguish them from NAMES. The % indicates to the
compiler that the letters which follow are to be treated as a
delimiter. The effect of the % ceases at the first character that
is not a letter. So, for example, in the declaration of an integer
it is essential to have a space between the delimiter and the name
being declared.
%INTEGER MINE
If the space were omitted the compiler would treat it as one delimiter
'INTEGERMINE'.
6. Text is for some purposes enclosed within quotes. In these cases
everything within the quotes is treated as part of the text,
including spaces and newlines. If the quote character is required
in the text it has to be typed as two separate quote characters to
distinguish it from the terminators.
7. If it is necessary to continue a statement on to a new line the
sequence '%C' should be used at the end of the first line. It may
be used at any convenient point in the statement. If it is used
within a delimiter a '%' must be used at the beginning of the
continued line.
8. A mis-typed character can be deleted by use of the double quote (")
delete character, immediately after it. Multiple double quote
characters can be used to delete a sequence of wrong characters as
far back as the beginning of the line.
NAMES
Names are used in IMP programs for the following entities:-
Arithmetic, Logical and String Variables
Records and Record sub-fields
Routines and Functions
Simple Labels
Record Formats and Array Formats
A name consists of a letter followed optionally by a sequence of up to
254 letters and/or numerals in any order. It is recommended that
meaningful names be used where possible in order to improve the
legibility of programs. The following are valid IMP names:
ROW1
NUMBER OF BLOCKS
C1900T01970
END POINT
COMMENTS
Comments should be used to make programs more meaningful both to the
originator and to anyone else who needs to work on them. Either the
delimiter %COMMENT or ! may be used to introduce a comment. A comment
is a statement and must be separated from the statement before it and
after it by the usual separators: newline or semi-colon.
DELIMITERS
These are a pre-arranged and pre-defined set of sequences of symbols
which have fixed absolute meanings to the compiler. They include:
Operators: arithmetic, assignment, relational, logical, sequential
Separators: e.g., %COMMENT
Brackets: e.g (, ), %BEGIN, %END
Declarators: e.g. %OWN, %LONG, %REAL
Specificators: e.g. %LIST, %RETURN.
NOTE
Some symbols of the language have more than one meaning, but are
defined in a context which normally is unambiguous. For example:
! or (operator)
! comment (delimiter)
! modulus sign (used in pairs)
VARIABLES
Variables are locations in the store of the computer which are used to
hold numeric or textual information. Each variable or group of
variables used in a program is given a name by the programmer.
Variables can be divided into three groups:
Arithmetic variables - see below
String variables - see Section 8
Records - see Section 9
ARITHMETIC VARIABLES
There are five types of arithmetic variable, the first three can only
hold whole numbers, the last two can additionally hold numbers which
include fractional parts.
Type Length in bits Range of Values
%BYTEINTEGER 8 0 : 255
%SHORTINTEGER 16 -32768 : 32767
%INTEGER 32 -2147483648 : 2147483647
%REAL 32 -7075 : 7075 (approx.)
%LONGREAL 64 -7075 : 7075 (approx.)
The format 7@75 means '7 multiplied by 10 to the power of 75', see
below.
The choice of which integer variable to use can be made on the basis of
the values it is required to hold. The choice between %REAL and
%LONGREAL will depend upon the accuracy required. %REAL variables can
only hold values to a precision of between 6 and 7 significant decimal
digits, whereas %LONGREAL variables hold values to a precision of
between 14 and 15 digits on the ICL 4/75 and between 15 and 16 digits
on the IBM 370. Further details of the representation of variables can
be found in the hardware manual for the appropriate computer.
CONSTANTS
DECIMAL CONSTANTS
Decimal constants are written in a straightforward notation:
2.538 1 .25 -17.28@-1 1@7
The last two examples mean -1.728 and 10000000, respectively.
The numerical part (mantissa) can be written in a number of ways:
15 015 15. 15.000
all of which are equivalent. The exponent, where present, consists of
'@' followed by optional sign and decimal digits.
THE CONSTANT π
The symbol 'π' can be used in IMP programs. It has the value
3.141592653589793. It can be used in any expression requiring the value
of π, for example:
AREA = π*RADIUS**2
SYMBOL CONSTANTS
Symbol constants having a numerical value within the range 0 to 127 may
be written by enclosing the required symbol within quotation marks:
'*'
The internal code values of symbols are given in Section 15. A %BYTE
can hold 1 symbol, a %SHORTINTEGER 2 symbols and an %INTEGER 4 symbols.
A constant containing more than 1 symbol is preceeded by 'm' for
example:
M'XYER'
NOTES
1. Spaces and newlines are always significant between quotes and the
numerical values of the symbols (they are not zero) will be
included in the value of the constant if any should appear.
2. If a single quotation mark is required as part of a constant it
must be replaced by two single quotation marks.
3. Each symbol occupies one byte i.e. 8 bits of the %INTEGER or
%SHORTINTEGER location, any unused bytes at the most significant
end of the location will be set to zero.
HEXADECIMAL CONSTANTS
A hexadecimal constant consists of a string of hexadecimal digits,
enclosed in quotation marks and preceded by the letter X. In addition
to 0, 1, 2, ..., 9 which have their usual significance, a hexadecimal
digit may also be A, B, C, D, E or F which stand for the decimal
numbers 10, 11, 12, 13, 14 or 15 respectively:
X'2A'
would have the same value as the decimal number 42 i.e. 2 * 16 + 10,
since A represents 10 in the scale of 16 i.e. the hexadecimal scale.
Each hexadecimal digit occupies a location of four bits length; hence a
%BYTEINTEGER variable can hold two such digits, a %SHORTINTEGER
variable four, and an %INTEGER variable eight.
%INTEGER I
I = X'6789ABCD'
BINARY CONSTANTS
This type of constant consists of a string of binary digits, enclosed
in quotation marks and preceded by the letter B. A binary digit, which
occupies just one 'bit' of store, may be either 0 or 1. Eight may
therefore be stored in a %BYTEINTEGER variable, sixteen in a
%SHORTINTEGER variable, and thirty-two in an %INTEGER variable.
%BYTEINTEGER M
M = B'01011011'
NOTES
1. Hexadecimal and Binary constants may appear in arithmetic
expressions; they will, however, be most used in conjunction with
the logical operators (see Section 3).
2. If the number of digits or characters which appear in a constant is
less than the maximum permissible e.g. a constant of three
hexadecimal digits being assigned to a %SHORTINTEGER variable, then
the value assumed is the same as if the digits or characters had
been right justified in a location of 32 bits and the remaining bit
positions filled with zero bits.
For a %SHORTINTEGER variable N,
N = X'2AB'
will have the same effect as
N = X'02AB'
3. Both the 4/75 and the 370 computers store integers in
twos-complement form. When writing programs that are likely to be
moved to other machines programmers should consider carefully the
possible change of arithmetic value of binary and hexadecimal
constants.
DECLARATION OF VARIABLES
All variables must be declared at the head of the block in which they
are used, or at the head of an outer block. (see Section 5). A
declaration consists of a type delimiter followed by one name or a list
of names separated by commas:
%INTEGER FIRST
%LONGREAL TOP, BOTTOM, LARGEST
DECLARATION OF ARRAYS
Arrays of variables are declared in a similar manner. The bounds of the
array are written after the name, in brackets:-
%INTEGERARRAY IN(1:10),OUT(1:20)
Multi-dimensional arrays of up to seven dimensions may be declared:
%SHORTINTEGERARRAY BITLIST (-4:4,1:2,10:100,1:2)
When accessing an individual element of an array the name must be
written, followed by an integer expression for each dimension:
BITLIST (J+I,J,I0,I) = 0
The values of the expressions must be within the bounds for the
relevant dimension otherwise the run time fault 'ARRAY BOUND FAULT'
will occur.
ARRAYS WITH VARIABLE BOUNDS
It is possible to use integer expressions involving variables for the
bounds of arrays. The variables referenced should be global to the
block containing the declaration. An example of the use of this is:
%BEGIN
%INTEGER TOP
READ (TOP)
%BEGIN
%INTEGERARRAY TABLE (1:TOP)
.
.
.
%OWN VARIABLES
The delimiter %OWN may be written before the type of a variable. It has
the following effects:
1. The variable will remain in existence for the duration of the
program. If it is within a routine or function it will retain its
value between calls of the routine, which is not the case for other
variables local to routines and functions.
2. The variable can be set to an initial value e.g.
%OWNINTEGER MAXIMUM = 527
The value must be expressed as a constant. If no initial value is
provided the variable will be set to zero.
3. %OWN arrays may be declared, but only of single dimension and with
constant bounds. Elements may be initialised by writing a list of
values, separated by commas and newlines. Note that in this
situation the %C continuation delimiter is not required, even if
the list extends on to several lines, so long as the line is
terminated with a comma.
%OWNBYTEINTEGERARRAY HEXTAB (0:15) = '0','1',
'2','3','4','5','6','7','8','9',
'A','B','C','D','E','F'
Note that there must be the same number of constants as there are
elements in the array. If one constant is to be repeated it may be
written once, followed by a count in brackets:
%OWNINTEGERARRAY IN(1:10) = 1,0(9)
Apart from these points %OWN variables are used in exactly the same way
as normal variables.
%CONST VARIABLES
The delimiter %CONST may be used in place of %OWN if the variables are
to have a constant value for the duration of the program. Any attempt
to assign values to them other than in the declaration statement will
result in a compile time fault. They are initialised in the same way as
%OWN variables.
%EXTERNAL VARIABLES
The delimiter %EXTERNAL written before a variable gives it all the
attributes of an %OWN variable, and additionally makes it available to
other, seperately compiled, programs or routines. (See Section 6)
%REALSLONG
This statement can appear at any point in a program. Its effect is to
cause the compiler to interpret any subsequent %REAL statements in
declarations, function types, and parameter lists for routines or
functions as %LONGREAL. The statement %REALSNORMAL causes the compiler
to revert to its default mode.
SECTION 2 - ARITHMETIC OPERATIONS
ARITHMETIC OPERATORS
The following operators may be applied to real and integer variables in
arithmetic expressions. Logical operators are described in Section 3.
The Operators
Symbol Meaning
+ addition
- subtraction
* multiplication
/ division
// integer division
** exponentiation (i.e. Y**3 = Y cubed)
NOTE
Implied multiplication should be avoided; in IMP it is only accepted in
the case of a constant followed by a name, e.g. 34X. Thus, whereas in
common mathematical notation XY may mean X multiplied by Y, the IMP
compiler will correctly interpret this as the name XY and will fault
the line as variable name not set. The correct presentation is X * Y.
PRECEDENCE OF ARITHMETIC OPERATORS
Rules, following normal practice, have been established to which the
IMP compilers conform and for arithmetic operators the order of
precedence is given below, whilst for logical and mixed arithmetic
logical expressions the rules are given in Section 3.
Highest precedence (1) **
(2) * or / or //
Lowest precedence (3) + or -
The programmer may override the natural order of evaluation by using
brackets. Extra brackets are acceptable to ensure clarity and to remove
doubts. The left hand precedence between operators otherwise of equal
precedence agrees with normal mathematical usage.
Expression: Meaning:
A - B + C (A - B) + C not 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)
ARITHMETIC EXPRESSIONS
Expressions may be real or integer according to context. An expression
is evaluated as real if it is being assigned to a real variable or
passed as a real value parameter (see Section 6). 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.
INTEGER EXPRESSIONS
An integer expression may contain integer constants and variables
declared to be of type integer; these may be simple or subscripted
variables, or integer functions (see Section 6).
There are two division operators in IMP:
Arithmetic Division (/)
Integer Division (//)
Arithmetic Division may occur in real expressions; Integer Division may
only occur in integer expressions.
1. Arithmetic Division (/). If this operator occurs is an integer
expression, it must always yield an integer result.
N*(N-1)/2 is always satisfactory,
but N*((N-1)/2) fails if N is even.
Note that Integer Division is preferred in the context of integer
expressions.
2. Integer Division (//). This operation always yields an integer
result and is exactly comparable to the Algol integer division. The
result consists of a quotient whose sign is determined
algebraically, and a remainder which is ignored. Note that both the
dividend and the divisor for an integer division must be integer
expressions.
9//2 = 4
100/15 = 6
(-9)/2 =-4
The definitions of division given above ensure that integer expressions
always yield an integer result. Integer expressions are always
evaluated single length (32 bits) and integer overflow will occur if at
any point in evaluation the capacity of a single length variable is
exceeded. If the calculation requires a wider range of numbers, real
arithmetic must be used.
Exponentiation is carried out by repeated multiplication. In integer
expressions the exponent must be an integer expression with a value in
the range 0 <= n <= 63.
THE INTRINSIC INTEGER FUNCTIONS 'INT' AND 'INT PT'
The built-in integer function INT yields as its result the nearest
integer from a real expression, and may be used in an integer
expression. The integer function INT PT yields as its result the the
value of the integral part of the quantity specified on entry. Strictly
the result is the integer that is less than or equal to the expression,
hence:
INT PT(-3.7) is -4
REAL EXPRESSIONS
A real expression may have, as operands, simple variables or
subscripted variables declared to be of type real or integer but the
result must be assigned to a real variable (see below).
In evaluating a real expression, the compiler will work to single
precision unless a double precision variable (i.e. long real) is
encountered; the working will then be in double precision. Hence,
double precision should only be used where an estimate of the accuracy
attainable relative to the input data requires it. Double precision
working is time and space consuming. Nevertheless, it should be noted
that floating point arithmetic does not guard against loss of accuracy
due to cancellation of significant figures in addition and subtraction.
This loss of accuracy is reduced by use of double precision, although
in the case of the 4/75 this is slightly less effective than in the
case of the 370 computer.
Exponentiation in real expressions is carried out as for integer
expressions except that the exponent must be an integer expression with
a value in the range -255<=n<=255.
A real expression which contains only integer operands and the
operators +, -, *, is evaluated in integer mode and subsequently
converted to real. Otherwise, each integer is converted to real before
being used.
SUB-EXPRESSONS
Generally, a bracketed sub-expression is treated as an expression in
its own right and the rules of precision given above apply. Therefore,
a real sub-expression containing only single precision variables will
be evaluated single precision and the result converted to double
precision if necessary.
ARITHMETIC ASSIGNMENTS
The two assignment operators are:
1. =
Here, the RHS is evaluated and the value is assigned to the
destination given by the LHS provided that the lengths are
compatible. The Run Time Fault 'CAPACITY EXCEEDED' will occur if an
attempt is made to assign too large a value to a variable using
this operator.
2. <-
Here, the least significant 8 or 16 bits of the RHS are assigned
respectively to the byte integer or short integer location on the
LHS. The remaining bits of the RHS are ignored. For assignment to
32 or 64 bits, <- is treated exactly as =.
The general arithmetic assignment instruction assigns the result of
evaluating an arithmetic expression to a variable. An integer variable
may only have assigned to it the result of an integer expression but
either an integer or real expression may be assigned to a real
variable.
Examples of valid assignments:
A(P,Q) = 1 + 2*cos (2 * N * (X + Y))
X = (U + V)/(Z + W) + F(M,N)
I = I+1
where A, F are real arrays
X, Y, U, V, Z, W are real variables
I,P,Q,M,N are integer variables
THE INTRINSIC REAL FUNCTION 'FRAC PT'
This built in function returns as its result the fractional part of a
real expression. Note that the fractional part is always treated as
being greater than or equal to zero. Hence:
FRAC PT(-4.6) is .4
MODULUS OF EXPRESSIONS
Two methods are provided for calculating the modulus or absolute value
of an expression. Modulus signs (!) used before and after an expression
bracket the expression and calculate the modulus without changing its
type:
%INTEGER I, J
%LONGREAL X, Y
I=!J+I!
X=3.4*!Y+SIN(Y)!
In the first example the expression is left as an integer expression
and in the second as a real expression. The alternative method is to
use the built in %LONGREALFN MOD. This always returns a real result,
hence can only be used in a real expression.
ASSIGNMENT OF SYMBOLS
Instructions to assign symbols to integer variables are written in a
form very similar to those which assign numbers, but the symbol
concerned is written between a pair of quotation marks:
%INTEGER I, J, K
I = '*'
J = M'ABCD'
K = '7'
Note that the last two instructions assign the SYMBOLS ABCD and 7 to J
and K respectively. On the other hand, the instructions:
J = ABCD
K = 7
assign to J the NUMERICAL value currently stored in the variable named
ABCD, and to K the NUMBER 7.
SECTION 3 - LOGICAL OPERATIONS
LOGICAL OPERATORS
The logical operators are as follows:
left shift <<
right shift >>
and &
or |
exclusive or ||
not ¬ (or~)
assignment <-
Logical operations are performed on bit patterns stored in integer
variables, including elements of integer arrays, but not in real
variables.
The IMP programmer may specify these operations on, by, or between byte
integer, short integer or integer variables and may similarly so assign
the results, but he must take precautions to understand the
implications.
The IMP Compiler always makes up the bit pattern to 32 bits before
carrying out the operation, thus:
Byte Integers - the left hand 24 bits are filled with zeros
Short Integers - the left hand 16 bits are filled with copies
of the sign bit (the most significant bit of
the %SHORTINTEGER
As with Arithmetic operations both '=' and '<-' are available as
assignment operators but care should be taken on the assignment of the
result of a logical operation.
1. The assignment operator '=' treats the result of the logical
operation as a 32 bit signed integer and attempts to perform an
arithmetic assignment to the designated variable. Hence it is not
always possible to put the result back in a variable of the same
type as that in which the operand was originally held, (if this was
a byte or short integer).
2. The assignment operator '<-', however, simply copies the requisite
bit pattern to the designated variable so that 32 bits are assigned
to an integer; the 16 least significant bits to a short integer;
the 8 least significant bits to a byte integer.
The choice of assignment operator depends on the context of the
program.
SETTING UP BIT PATTERNS IN INTEGER VARIABLES
A bit pattern is normally specified in the program as a hexadecimal
constant.
1. The compiler sets up the pattern right justified and makes it up to
32 bits by padding with zeros at the most significant end of the
location and stores it in a table of constants in the User's
program. Assignment of a constant to a short integer or byte
integer location therefore needs care.
2. The arithmetic assignment operator = will always copy a constant
(set up as in 1.) into a 32-bit integer variable.
3. The arithmetic operator = will only copy from the 32-bit constant
location into a short integer or byte integer if by so doing the
numerical value remains unchanged during the operation:
%SHORTINTEGER I
I = X'F000'
will fail, 'CAPACITY EXCEEDED' (Fault 30)
4. The assignment operator <- will treat the constant as a 32-bit
pattern (form of (1) above) and will copy the 32, 16, or 8 least
significant bits to the designated integer variable. Thus, contrary
to the example in 3:
%INTEGER J
%SHORTINTEGER I
I <-X'F000'
J = I
The first instruction will not fail, but will set up in I the bit
pattern:
1111 0000 0000 0000
The second instruction will set up in J the bit pattern:
1111 1111 1111 1111 1111 0000 0000 0000
SHIFT OPERATORS
The IMP programmer may specify a first operand (I) to be shifted by a
second operand (N) and the result to be placed either back in the
location of the first operand or in a new location (J). He may declare
I, N or J to be byte, short or integer variables but he must check that
these are meaningful.
The Compiler makes the operands (I) and (N) up to a 32 bit pattern (as
described above) before the operation takes place, and then selects the
six least significant bits of the second operand (N) to determine the
amount of shift. The remaining 26 bits of N are ignored, thus the shift
will be positive in the range 0 to 63.
I >> N has the effect of I>>(N &63)
NOTES
Left Shift
1. Any bit positions vacated at the right-hand of the 32-bit pattern
are filled with zeros.
2. Any bits shifted off the left-hand end of the 32 bit pattern are
lost.
Right Shift
1. Any bit positions vacated at the left-hand end of the 32-bit
pattern are filled with zeros.
2. Any bits shifted off the right-hand end of the 32 bit pattern are
lost.
The explicit library function SHIFTC is provided for shifting a bit
pattern cyclically. It takes two integer expressions as parameters and
returns as a result the bit pattern in the first expression shifted by
the number of places specified by the second parameter. Any bits
shifted off one end of the 32 bit pattern re-appear at the other end. A
positive shift is to the left and vice versa.
THE OPERATOR 'NOT'
This is represented by ¬ and operates on a single operand (I). The IMP
programmer may declare I to be a byte, short or integer variable. The
compiler expands this to 32 bits in the computer location before the
operation is carried out.
The operator 'not' inverts the values of the bits:
0's are changed to 1's
1's are changed to 0's
If I contains the bit pattern
0.........01 00 11 00 11
then ¬I gives 1.........10 11 00 11 00
i.e. ¬I + 1 = -I
THE OPERATORS 'AND', 'OR', 'EXCLUSIVE OR'
These operations are carried out between the bit patterns stored in two
integer variables. Whether the IMP program has declared these as byte,
short or integer variables the compiler expands each bit pattern to 32
(as explained above) and the result, a single bit pattern, is held in a
32 bit location. The programmer must choose an integer of suitable
length in to which to assign the result, and should note the effects of
the '=' and '<-' operators in this context.
'and' (&) result pattern contains a 1-bit where the two source
patterns both have 1-bits and contains 0-bits elsewhere.
'inclusive or' (!) result pattern contains a 0-bit where the two source
patterns both have 0-bits and contains 1-bits elsewhere.
'exclusive or' (!!) result pattern contains a 1-bit where the bits in
the source patterns are different and contains 0-bits
elsewhere.
These rules may be summarised thus:
& ! !!
0 : 0 0 0 0
0 : 1 0 1 1
1 : 0 0 1 1
1 : 1 1 1 0
PRECEDENCE FOR MIXED ARITHMETIC AND LOGICAL OPERATIONS
Arithmetic and logical operators may be mixed in an integer expression.
The rules of precedence are then:
¬ (most binding)
** >> <<
* / // &
+ − ! !! (least binding)
Example of use of operators:
To 'unpack' the contents of an integer location I, into four sections
each of 8 bits length and store them in the positions of a byte integer
array B:
%INTEGER I,J
%BYTEINTEGERARRAY B(0:3)
......
I=.........
......
%CYCLE J=0, 8, 24
B(J/8)= I>>(24-J)& X'FF'
%REPEAT
......
......
NOTES
1. X'FF' represents a 'bit pattern' of eight ones in the least
significant end of a location and zeros elsewhere.
2. The shift, having a higher precedence than the &, is effected
first.
THE FUNCTION 'BITS'
The explicit library function BITS takes one parameter which must be an
integer expression. It returns as a result the number of bits in the
evaluated expression. For example if the integer IN contained a
character read from a binary paper tape and it was required to check
whether it had odd parity one could write:
->ODD %IF BITS(IN)&1=1
SECTION 4 - CONTROL OF SEQUENCE OF INSTRUCTIONS
INTRODUCTION
All programs require facilities to control the order in which
instructions are obeyed. A variety of facilities is provided in IMP.
1. Routines and Functions: these are used to group instructions
together and give them a name - READ and SIN are examples of
Routines and Functions (see Section 6).
2. Conditional Statements: these are used to make the execution of
single instructions or groups of instructions, dependent on the
result of one or more tests (see below).
3. Conditional Repetition and Cycles: these are used to execute a
sequence of instructions repeatedly. The number of repetitions can
be controlled by a variable or by a condition.
4. Jumps to Switch Labels: these are used where a program is required
to take one of many different paths depending on the value of an
expression.
5. Jumps to Simple Labels: these are available as alternatives to 2, 3
and 4 above.
CONDITIONS
Conditions are described here in the context of a simple conditional
statement for reasons of clarity but they can also be used in more
complex conditional statements and cycles as described later. An
example of a simple conditional statement is:
%IF A>2 %THEN PRINT(A,5,3)
which can be represented as:
%IF %THEN
The following types of statement can be made the subject of a condition
and are known as 'unconditional instructions'. The phrase
'unconditional instruction' is used to denote a single instruction
which is executed once each time it is reached. Examples of
instructions in this group are:
Type Example Notes
Assignments A = 27
Routine Calls Print (A,2,3)
Jumps ->27 See below
Special Jumps %RETURN See Section 6
%RESULT= See Section 6
%STOP See below
%MONITORSTOP See Section 11
%MONITOR See Section 11
%EXIT See below
The part is made up of two expressions separated by a relational
operator. The relational operators and their meanings are:
= equal
> greater than
< less than
>= greater than or equal
<= less than or equal
# not equal
A double sided condition may be used, in which case the whole condition
is true only when both sides of the condition are true, for example:
%IF 9>=I>=0 %THEN %PRINTTEXT'IN RANGE'
The %PRINTTEXT instruction will only be executed if I is less than or
equal to 9 and at the same time I is greater than or equal to 0.
More generally multiple conditions may be linked using the %AND and %OR
operators. These take their logical meanings; example:
%IF A=1 %OR A=10 %THEN NEWLINE
Note that if both %AND and %OR are used in the same conditional
statement, then in order to avoid ambiguity the conditions they link
must be separated from each other by brackets
%IF A=10 %AND (S='NOW' %OR S='SOON' %OR S='LATER') %THEN A=0
In future examples implies any of the above forms.
FURTHER USE OF CONDITIONS
The unconditional instruction which was made conditional in the first
example can be replaced by a sequence of unconditional instructions
enclosed in the bracket pair %START and %FINISH. In this case the %THEN
may be omitted, if preferred.
%IF [%THEN] %START
A = 1
NEWLINE
.
.
.
.
%FINISH
Alternatively where a small number of instructions is involved they can
be linked with the operator %AND. Note that here %AND is as in common
usage, and the linked instructions are obeyed in the sequence in which
they appear in the text of the statement.
Example: %IF %THEN NEWPAGE %AND LINE = 0
ALTERNATIVE PATHS
The %ELSE operator can be used to indicate the path to be taken when
the condition is found to be not true
%IF %THEN A=1 %ELSE A=0
and hence
%IF [%THEN] %START
........
........
%FINISH %ELSE %START
........
........
%FINISH
USE OF %UNLESS
In all the examples above %IF can be replaced by %UNLESS. This has the
effect of testing that the condition is not true. Hence
%IF A#B %THEN A=0 and
%UNLESS A=B %THEN A=0
will have the same effect.
FURTHER SIMPLIFICATIONS
The simple condition can be written with the unconditional instruction
first if preferred; example:
A=0 %IF A=B
Note that %THEN is no longer needed, but note also that neither %START
%FINISH, %ELSE nor linking of instructions with %AND can be used with
this form.
REPEATED EXECUTION OF INSTRUCTIONS AND CYCLES
In many situations it is useful to execute a single instruction or
group of instructions repeatedly, the number of repetitions being
controlled by a condition or by a control variable.
CONDITIONAL REPETITION
The simplest form is
%WHILE %THEN
The condition is tested and if found to be true then the unconditional
instruction is executed. The whole operation is repeated until the
condition ceases to be true. For example
%WHILE NEXTSYMBOL= ' ' %THEN SKIPSYMBOL
has the effect of skipping any space characters on the input stream.
The inverse form is
%UNTIL %THEN
In this case the unconditional instruction is executed first and then
the condition is tested. The whole operation is repeated until the
condition is found to be true. Note that when using %UNTIL the
unconditional instruction is always obeyed at least once whereas when
using %WHILE the condition is tested before executing the unconditional
instruction and may be false at the first test.
EXTENSIONS TO CONDITIONAL REPETITION
The unconditional statement in the above examples can be replaced by a
group of unconditional statements linked by %AND, or enclosed by %CYCLE
and %REPEAT; examples:
%UNTIL J=999 %THEN READ(HOLD(J)) %AND J=J+1
%WHILE NEXTSYMBOL#NL [%THEN] %CYCLE
READSYMBOL (I)
S=S.TOSTRING(I)
%REPEAT
An alternative form where only one unconditional instruction is
involved is
%WHILE
for example SKIPSYMBOL %WHILE NEXTSYMBOL=NL
%CYCLES WITH CONTROL VARIABLES
Instead of using a condition to control the number of repetitions of a
%CYCLE a control variable may be used. The control variable must be a
variable declared to be an %INTEGER. (A %SHORTINTEGER or %BYTEINTEGER
may not be used).
The cycle is written:
%CYCLE = ,,
where ,, and are all integer expressions; example:
%CYCLE I=1, 1, 10
IN(I)=0
IN1(I)=0
%REPEAT
On entry to the %CYCLE statement a check is made that #0 and that
( - )/ is a positive integer.
If the test fails the fault 'INVALID CYCLE' will occur which will
normally cause the program to terminate (see Section 13). Otherwise the
control variable is set to the value . The instructions between %CYCLE
and %REPEAT are executed, a test is made for equality between the
control variable and and if unsuccessful the control variable is
incremented by and the sequence is repeated until the
control variable reaches the value .
The control variable can be used in expressions within the cycle but it
should not have anything assigned to it. The effect of doing so is
undefined.
THE %EXIT INSTRUCTION
This may be used at any point within a %CYCLE - %REPEAT block. The
effect is to go to the instruction following the %REPEAT, preserving
the current value of the %CYCLE variable.
%CYCLE N=4, -1, -100
.
.
.
%IF IN(N)=' ' %THEN %EXIT
.
.
.
%REPEAT
INDEFINITE CYCLES
The delimiters %CYCLE and %REPEAT may also be used without a condition
or a control variable. The effect is to repeat the instructions between
the %CYCLE and %REPEAT indefinitely. An %EXIT or a jump should be
included among the instructions.
NESTING CONDITIONS AND CYCLES
Conditions and Cycles can be nested to any depth so long as all of the
instructions relating to the nested condition or cycle are contained
between the %START - %FINISH or %CYCLE - %REPEAT of the outer condition
or cycle; example:
READSTRING(TEST)
%WHILE TEST # 'END' %CYCLE
!CHECK FOR NON-ALPHA CHARACTERS IN NAMES
%CYCLE I=1, 1, LENGTH(TEST)
%UNLESS 'A'<= CHARNO(TEST,I)<='Z' %START
%PRINTTEXT'INVALID NAME'
NEWLINE
%STOP
%FINISH
%REPEAT
NAME(POINTER) = TEST
POINTER=POINTER+1
READSTRING(TEST)
%REPEAT
SWITCH VECTORS
Switch vectors are used in situations where it is necessary for a
program to take one of several paths depending on the value of an
expression. Switch vectors must be declared at the beginning of the
block or routine in which they are used, together with declarations of
variables. The declaration consists of a name followed by a pair of
integer constants which define the range of vectors to be used, for
example:
%SWITCH SWA(1:10)
At the point at which the branching is to take place a statement such
as
->SWA (I+J)
should be used. The expression I+J can be replaced by any suitable
integer expression which has a value in the range declared for SWA.
Finally at the points to which control is to pass the label should be
written, example
SWA(3): PRINT(N,3,4)
Note that the maximum range allowed for switch vectors is -32767 to
+32767. It is not necessary to include labels for all positions
declared. If an attempt is made to jump to a non-existent label a run
time fault 'SWITCH VECTOR NOT SET' occurs.
JUMPS TO SIMPLE LABELS
Simple labels may be used in IMP. EitherIMP NAMES or unsigned positive
integers in the range 1 to 16383 may be used. In order to improve the
legibility of programs the use of meaningful names for labels is
recommended. The label declaration comprises the identifier followed by
a colon, for example:
ENDFILE:
27:
2222:
Note that if NAMES are used they do not conflict with names of
variables, routines etc, because they are held in a seperate list by
the compiler.
Jumps may be made to labels from anywhere in the same block; examples:
->ENDFILE
->2222 %IF FLAGS=1
The following restrictions exist in relation to the use of labels and
jumps.
1. All declarations of variables, arrays etc., must precede any labels
or jumps in the same block.
2. No attempt should be made to enter a %CYCLE - %REPEAT block other
than through the %CYCLE.
3. When using the sequence:-
....%START
. . . . .
%FINISH %ELSE......
Then no attempt should be made to jump into the block between %START
and %FINISH.
%STOP AND %MONITORSTOP
The Unconditional Instruction %STOP can appear at any point in a
program. When it is reached the program is terminated and control is
returned to the operating system. A %STOP statement is effectively
compiled at the statement %ENDOFPROGRAM. The statement %MONITORSTOP has
the same effect as %STOP with the added feature of printing a trace of
the program and values of scalar variables before termination. (see
Section 11)
SECTION 5 - STORAGE ALLOCATION AND BLOCK STRUCTURE
THE STACK
At compile time the Compiler translates the user's IMP program into
machine instructions and this object code is loaded by the Loader which
then passes control to the user's program. The data space which is
required by the user's program is then allocated in a dynamic fashion
as the program proceeds. The following simplified description of the
data store (the stack) illustrates the principles of storage
allocation.
| STACK POINTER (ST)
v
+------------------+--------------+-----------+-----------------+
| PROGRAM | CONSTANTS | CELLS IN | FREE CELLS |
| (FIXED IN SIZE) | & TEXT | USE | |
+------------------+--------------+-----------+-----------------+
Each cell represents a unit of computer store and can be used to hold
an arithmetic or string variable or a %RECORD. A cell may be imagined
as being of variable size from 8 bits upwards, appropriate to the
length of the entity being held.
At any time during the running of a program the stack pointer (ST)
points to the next available location - that is, it contains the
address of the next free cell.
In the following examples shaded areas represent locations which hold
information essential to the program, such as array dimensions, but of
no interest to the user since he cannot access them. Cells which are
allocated to variables are indicated by the name given to the variable.
STORAGE ALLOCATION DECLARATIONS
The following declarations are typical of those which allocate storage
space:
%REAL %INTEGER %REALARRAY %INTEGERARRAY
To illustrate the stack mechanism the following example is considered:
%BEGIN
%REAL A, B, C ; %INTEGER I, MAX
%REALARRAY X(1:3),Y(1:4)
After the above declarations the stack would be:
| ST2
ST1 v
+-------------++----------------++---------------------+
| A B C I MAX || X(1) X(2) X(3) || Y(1) Y(2) Y(3) Y(4) |
+-------------++----------------++---------------------+
ST1 is the position of ST before %BEGIN and ST2 its position after the
declarations. Any further declarations advance ST by the appropriate
amount, likewise any activity initiated by the instructions in the body
of the block may cause ST to be advanced (either explicitly or
implicitly) still further. Finally when %RETURN (in routines) or %END
or %ENDOFPROGRAM is executed, ST reverts to ST1.
Variables declared by %REAL and %INTEGER (and associated types) are
called FIXED VARIABLES, because the amount of storage space required is
determined at compile time. Array declarations, however, may have
general integer expressions as the parameters and hence have dynamic
significance.
For example, the space allocated by a declaration such as
%REALARRAY X,Y (1:M, 1:N)
will depend on the computed values of M and N and cannot be determined
at compile time. The stack pointer, ST, is thus advanced in several
stages following the initial step which reserves space for all the
fixed variables.
BLOCK STRUCTURE OF PROGRAMS
This is illustrated by the following example:
%BEGIN
%REAL A,B,C
A=1 ; B=2 ; C=A+B
%BEGIN
%REAL A,B,D
A=2; D=1; B=C; C=4
%END
A=A+B+C
%END
The associated stack is:
| ST1 | ST2 | ST3
v v v
--++++-------++-------+----------------
|||| A B C || A B D |
--++++-------++-------+----------------
1 2 3 4 5 6
Before the first %BEGIN, ST is at ST1 and moves to ST2 on entering the
outer block. After the second %BEGIN, ST is at ST3 and reverts to ST2
when %END is executed. At the second %END, corresponding to the first
%BEGIN, ST assumes its original position, ST1.
In the diagram, positions 1,2,3 correspond to the declarations of the
outer block and 4,5,6 to those of the inner block. After the
instruction C=A+B, the value 3 is left in position 3; while the inner
block instructions leave the values 2,1,3,4 in the positions 4,6,5,3
respectively. The last instruction of the outer block leaves the value
7 in position 1. This example indicates the importance of understanding
the scope of influence of the declarations made in the inner and outer
blocks.
The variables A,B of the inner block do not conflict with A,B of the
outer block and are termed LOCAL names; a reference to C in the inner
block is taken to refer to the variable of that name declared in the
outer block and is a NON-LOCAL or GLOBAL name to the inner block.
Note also that the information stored in the variables of the inner
block is lost, when the block is left, unless it is a variable of type
%OWN, and that one cannot refer in the outer block to any variable
declared in the inner block.
These simplified concepts are amplified in the following notes:
1. Blocks may contain any number of sub-blocks and blocks may be
nested to a depth of 10.
2. Names declared in a block take on their declared meaning in the
block and in any sub-blocks unless re-declared in the sub-block.
Thus global variables must be used to communicate between blocks.
3. Declarations must appear at the start of a block before any
instructions which may cause a jump to occur or any labels.
4. Labels and switch labels, unlike variables, are always local to a
block. Thus a block may only be entered through its head and it is
impossible to jump from one block to another.
5. Each loop control pair, e.g. %CYCLE - %REPEAT must be in the same
block as must %START - %FINISH pairs.
6. The outermost block of a program is terminated by %ENDOFPROGRAM
which causes the process of compilation to be terminated and
transfers control to the next stage.
USE OF BLOCK STRUCTURE
It is often convenient to regard a complete block as one compound
instruction. With this view of an inner block in mind, the following
are among the reasons for nesting blocks of program.
1. It is often necessary to use an array whose effective bounds are
not known until some stage in the execution of the program. Rather
than declare an array whose size will always be adequate the
following example indicates an economical use of available storage:
%BEGIN
%INTEGER N
%CYCLE
READ(N)
%BEGIN
%INTEGER I
%INTEGERARRAY A(1:N)
%CYCLE I=1,1,N
READ (A(I))
%REPEAT
......
......
%END
%REPEAT
%ENDOFPROGRAM
Here, the required size of the array is read in the outer block and the
necessary array declared in the inner block. Note that the space used
by any one set of data will be recovered when the inner block is left,
thus allowing us to repeat the process without incurring successively
increasing demands for space.
It might be imagined that a simpler solution is to declare an array,
after all other declarations, which uses the whole of the remaining
space in the machine. While this is probably true on a system where the
user has the whole machine to himself, core store is the most expensive
form of memory on a computer system and operating systems on large
general purpose machines normally attempt to optimise its use by a
variety of techniques. Thus on such systems, a requirement for large
amounts of core storage (which is often largely unused) will incur
penalties both in priority and cost.
2. Since the declarations at the head of a block are cancelled on
executing the %END of the block it is often possible to economise
on storage space if a program consists of several distinct tasks,
each requiring large amounts of store. The general procedure is
illustrated in the following example in which each task is written
as a distinct block.
%BEGIN
......
......
%BEGIN
%REALARRAY XYZ(1:5000)
......
......
%END
......
......
%BEGIN %INTEGERARRAY IJK(1:20, 1:250)
......
......
%END
......
......
%END
3. In developing a complicated program it is often a great advantage
if each sub-block can be developed separately. A program is
generally much clearer if its sub-blocks are related to the blocks
of its flow diagram. A closely related method of breaking a program
into sub-units is by the use of routines which are discussed in
Section 6.
SECTION 6 - ROUTINES AND FUNCTIONS
INTRODUCTION
There are many occasions when it is necessary to perform a similar
operation several times in different sections of a program, or even in
distinct programs (perhaps written by different people). It has already
been explained that a block may be regarded as a single compound
instruction. Instead of writing out this block in full every time it is
required one may give it a name which is then written (as a single
instruction) each time the block is to be executed. Such a named block
is called a ROUTINE and this Section contains a discussion of this
basic concept and its extensions.
ROUTINES WITHOUT PARAMETERS
There are three operations involved in incorporating a routine into a
program:
1. Declaration (or specification)
2. Calling
3. Description
Consider the example which uses a routine to interchange the values of
two variables X and Y.
1. Declaration
%ROUTINESPEC INTERCHANGE The name INTERCHANGE is to be
the title for a routine (a block
of declarations and instructions)
which will be described later.
2. Call
INTERCHANGE Carry out the routine which
has the title INTERCHANGE
3. Description
%ROUTINE INTERCHANGE The routine INTERCHANGE consists
%REAL Z of the single declaration and
Z=X ; X=Y ; Y=Z three instructions.
%END
NOTES
1. A Routine description has the same structure as a block except that
%BEGIN is replaced by %ROUTINE followed by its name.
2. In the example X and Y are global variables.
3. The first line of the description is always the same as the
declaration but with %SPEC omitted.
4. A routine may be called in any block interior to the one in which
it is declared (and described). In this way one can think of local
and global routines, in just the same way as local and global
variables.
5. The compiler inserts instructions to jump round a routine
description at run time. Thus the instructions constituting the
routine are only obeyed as the result of a call on that routine.
6. A routine call is an instruction and may be made conditional:
%IF P = 10 %THEN INTERCHANGE
7. Normally, instructions in the routine are obeyed in sequence until
reaching %END. If it is desired to return from the routine at some
other point, the instruction %RETURN may be used. This is
equivalent to jump to %END and hence cannot be used in an inner
block of the routine. %RETURN may be made conditional.
8. Declaration of a %ROUTINE is not required if the description
precedes the call.
Example: Interchange X and Y and square them if they are both positive.
%ROUTINE INTERCHANGE AND SQUARE
%INTEGER Z
Z = X; X = Y; Y = Z
%IF X <= 0 %OR Y <= 0 %THEN %RETURN
X = X*X; Y = Y*Y
%END
NOTE
A second %RETURN could be written immediately before %END, but would be
redundant.
GLOBAL VARIABLES IN ROUTINES
When using global variables within routines, it is necessary for them
to be global to the routine description. It is not sufficient for them
to be global to the call, as shown by the following example:
%BEGIN
%INTEGER A
%ROUTINESPEC SQUARE
..........
A = 10
%BEGIN
%INTEGER A
A = 5
SQUARE
%END
%ROUTINE SQUARE
A = A**2
%END
%END
NOTES
1. It is the variable A of the outer block which is global to the
routine description, so the result of the SQUARE instruction above
will be to set A = 100.
2. The above remarks apply equally to other global names e.g. routine
and function names.
ROUTINES WITH PARAMETERS
The previously described routine 'INTERCHANGE' will exchange the values
of X and Y, but will be of no use to interchange any other pair of
variables.
In IMP, to facilitate the use of the same routine in different contexts
within a program, the user is permitted to write the routine using
formal (or dummy) names for some or all of the variables global to it.
In each call of the routine, these formal names are replaced by the
appropriate actual names.
If formal names are used in the writing of a routine, then the
following modifications must be made to the procedures for declaring,
describing, and calling the routine:
1. In the declaration and description of the routine, its name must be
followed by a bracketed list of the formal parameters used,
together with a statement of their type.
2. In calling the routine, the name must be followed by a bracketed
list of the actual parameters which are to replace the formal
parameters on this occasion.
The designation 'parameter' has been used above in anticipation of
facilities which permit quantities other than names (for example,
elements of arrays and arithmetic expressions) to be passed on to
routines.
Example 1: %REAL U,V
%INTEGER I
%REALARRAY A(1:10)
%ROUTINESPEC INTERCHANGE (%REALNAME X,Y); ! DECLARATION
..........
..........
INTERCHANGE (U,V) ; ! CALL 1
%CYCLE I = 1,1,5
INTERCHANGE (A(I), A(11-I)) ; ! CALL 2
%REPEAT
..........
%ROUTINE INTERCHANGE (%REALNAME X,Y); ! DESCRIPTION
%REAL Z
Z = X; X = Y; Y = Z
%END
NOTES
1. Here X and Y are the formal parameters.
2. The actual parameters must be placed in the same order as the
formal parameters to which they correspond. In call 1, X is
replaced by U and Y by V. In call 2, X is replaced by A(I) and Y by
A(11-I).
3. In the example the type %REALNAME was used. In an analogous fashion
any valid type may be specified as formal parameters. The actual
parameters must, of course, correspond in type to the formal
parameters.
4. The statement of parameter type is omitted in calling the routine
but the compiler checks the actual parameters listed and will
generate a compile time fault message if they do not correspond to
the declaration (see Section 12).
Parameter N in the example below illustrates the use of a different
type of formal parameter, that called by value.
Example 2: ..........
%INTEGER SHRIEK
%ROUTINESPEC FACTORIAL (%INTEGERNAME Y, %INTEGER N)
..........
..........
FACTORIAL (SHRIEK, 10)
..........
..........
%ROUTINE FACTORIAL (%INTEGERNAME Y, %INTEGER N)
%INTEGER I
Y = 1; I = 1
%WHILE I<=N %THEN Y=Y*I %AND I=I+1
%END
The difference between the formal parameter types used in Examples 1
and 2 is important and must be carefully noted.
In Example 1 the formal parameters X, Y are of type %REALNAME and are
the names of the variables to which the results are assigned, and the
corresponding actual parameters must be names, in this case the names
of %REAL variables.
A reference to Y inside the routine is essentially a reference to the
non-local variable named by the actual parameter.
In Example 2, on the other hand, the formal parameter %INTEGER N can be
replaced by an integer arithmetic expression, which is evaluated and
assigned to the local variable N which is specially created in addition
to any local variables declared in the routine. N is an essentially
local quantity which is lost on exit from the routine. Consequently the
routine should place the information it produces in variables which are
called by NAME (such as X and Y), or in variables which are global to
the routine. The formal parameter N is said to be called by VALUE in so
far as it is only the value of the corresponding actual parameter which
is of interest.
Note that a value is assigned to the local variable N by use of the '='
operator. Thus a CAPACITY EXCEEDED error could occur if the formal
parameter is of type %SHORT (or %BYTE) %INTEGER, or %STRING.
However, when it is necessary to pass complete arrays to routines these
may only be passed by means of NAME parameters. This is because the
creation of local arrays and the necessary copying of them is both time
and space consuming. Example 3 illustrates the use of %REALARRAYNAME
parameters:
Example 3: %ROUTINE MATMULT (%REALARRAYNAME A,B,C %INTEGER P,Q,R)
%INTEGER I,J,K ; %REAL T
%CYCLE I = 1,1,P
%CYCLE J = 1,1,R
T = 0
%CYCLE K = 1,1,Q
T=T+A(I,K)*B(K,J)
%REPEAT
C(I,J)=T
%REPEAT
%REPEAT
%END
This forms the product of a 'P x Q' matrix A and a 'Q x R' matrix B.
The result, a 'P x R' matrix, is accumulated in C. The routine assumes
that the first element of each matrix has the suffix (1,1). A typical
call sequence might be:
%REALARRAY H(1:20,1:20),X,Y,(1:20,1:1)
.
.
MAT MULT (H, X, Y, 20, 20, 1)
In IMP, parameters called by name are completely determined by the
actual values of all relevant quantities (including global variables)
at the time of call. For example, it may happen that a routine with a
parameter list containing say
...........(%REALNAME X, %INTEGERNAME I...........)
is called with the actual parameters
...........(A(J), J, ..........)
where A is the name of a previously declared real array. If the value
of J at the time of the call is, say, 10 then in the execution of the
routine the formal parameter X is replaced everywhere by A(10) no
matter how J varies during execution of the routine.
The reader is warned that the alternative convention whereby, in the
above example, the array element replacing X would be determined by the
current value of J during the execution of the routine is used in some
other programming languages (e.g. Algol).
The following table is a complete list of formal parameters together
with the permissible forms for the actual parameters:
Formal Parameter: Corresponding Actual Parameter:
%BYTE %INTEGER %NAME Name of a %BYTEINTEGER variable
%SHORT %INTEGER %NAME Name of a %SHORTINTEGER variable
%INTEGER %NAME Name of an %INTEGER variable
%REAL %NAME Name of a %REAL variable
%LONG %REAL %NAME Name of a %LONGREAL variable
%STRING %NAME Name of a %STRING variable
%BYTE %INTEGER %ARRAY %NAME Name of a %BYTEINTEGERARRAY
%SHORT %INTEGER %ARRAY %NAME Name of a %SHORTINTEGERARRAY
%INTEGER %ARRAY %NAME Name of an %INTEGERARRAY
%REAL %ARRAY %NAME Name of a %REALARRAY
%LONG %REAL %ARRAY %NAME Name of a %LONGREALARRAY
%STRING %ARRAY %NAME Name of a %STRINGARRAY
%BYTE %INTEGER \
%SHORT %INTEGER } An integer expression
%INTEGER /
%REAL \ A general expression
%LONG %REAL / (i.e. a real or integer expression)
%STRING (n) A string expression
%ROUTINE \ Sometimes it is required to pass on
%BYTE %INTEGER %FN | the name of a routine, or function
%SHORT %INTEGER %FN | (see below) as a parameter. The actual
%INTEGER %FN | parameter is the name of a routine or
%REAL %FN | function which must correspond in type
%LONG %REAL %FN | and specification with the formal
%STRING %FN / parameter, the specification of which
will be found in the routine body.
%BYTE %INTEGER %MAP \ The name of a map function (see
| Section 7).
%SHORT %INTEGER %MAP | The name of a map function may be
%INTEGER %MAP | passed to a routine in the same
%REAL %MAP | context as a routine or function name.
%STRING %MAP /
%RECORD %NAME The name of a %RECORD
%RECORD %ARRAY %NAME The name of a %RECORDARRAY
FUNCTION ROUTINES
When a routine has a single output value it may be written as a
function routine and then used in an arithmetic expression in the same
way as the permanent functions (COS, SIN etc.).
The declaration, call and description of routine and functions are
compared in the following table:
Routine: Function:
Declaration: %ROUTINE %SPEC.... %FN %SPEC....
Result of Call: Execution of an A value of the appropriate
instruction type and length
Description: %ROUTINE.... %FN....
where the type of function may be any one of the allowed real or
integer types, i.e. %SHORTINTEGER, %LONGREAL etc., or of type %STRING.
For example, the routine FACTORIAL described earlier may be rewritten
as a function routine as follows:
%INTEGER SHRIEK
%INTEGERFNSPEC FACT 1 (%INTEGER N)
..........
SHRIEK = FACT 1 (10)
..........
%INTEGERFN FACT 1 (%INTEGER N)
%INTEGER PROD,I
%IF N=1 %THENRESULT = 1 ; %COMMENT NOTE 1. BELOW
PROD = 1
%CYCLE I = 2, 1, N ; %COMMENT NOTE 1. BELOW
PROD = I * PROD
%REPEAT
%RESULT = PROD
%END
NOTES
1. The reader should study carefully the two occurrences of the
assignment of the value of the function to %RESULT. Depending on
the value of N, either is a possible exit point. The two lines
marked with a %COMMENT could be combined, as in the routine FACT,
but the similarity to the example later in this Section on
recursion would be lost.
2. Both the routine call FACTORIAL (SHRIEK, 10) and the assignment
SHRIEK=FACT1(10) produce identical results.
FUNCTIONS AND ROUTINES AS PARAMETERS
This is illustrated by the following example involving an integration
routine:
%ROUTINESPEC INTEGRATE(%REALNAME Y, %REAL A,B, %INTEGER N, %REALFN F)
which integrates a function F(X) over the range (A, B) by evaluating
Y = (F(0) + 4*F(1) + 2*F(2) + ... + 4*F(2N-1) + F(2N))*(B-A)/(6*N)
where F(I) = F(A + I*(B-A)/(2*N))
An auxiliary function is required to evaluate F(X) and details of it
must be passed on to the integration routine. This is done by means of
the routine type parameter and the body of the routine might then be:
%ROUTINE INTEGRATE (%REALNAME Y, %REAL A, B, %INTEGER N,%C
%REALFN F)
[%REALFN] %SPEC F(%REAL X)
%REAL H; %INTEGER I
H = (B-A)/(N*2)
Y = 0
%CYCLE I = 0,2,2*N-2
Y = Y+2*F(A+I*H)+4*F(A+(I+1)*H)
%REPEAT
Y = (Y-F(A)+F(B))*H/3
%END
To enable instructions such as:
Y = Y+2*F(A+I*H)+4*F(A+(I+1)*H)
to be translated, a specification of the formal parameter F is
required. In this case the delimiter %REALFNSPEC can be abbreviated to
%SPEC since the type of the function is given explicitly by the formal
parameter itself. Now consider a program to evaluate
Z = EXP(-Y)*COS(B*Y)
for various values of B read from a data file, the last value being
followed by 1000, using for N the integer nearest to 10B.
%BEGIN
%ROUTINESPEC INTEGRATE (%REALNAME Y,%REAL A,B,%INTEGER %C
N,%REALFN F)
%REALFNSPEC AUX (%REAL Y)
%REAL Z, B
%COMMENT SIMPSON RULE INTEGRATION
%CYCLE
READ (B)
%IF B = 1000 %THEN NEWLINES(10) %ANDSTOP
INTEGRATE (Z, 0, 1, INT(10B), AUX)
NEWLINE
PRINT (B, 1, 2);SPACES(2);PRINT (Z, 1, 4)
%REPEAT
%REALFN AUX(%REAL Y)
%RESULT = EXP(-Y)*COS(B*Y)
%END
%ROUTINE INTEGRATE (%REALNAME Y,%REAL A,B,%C
%INTEGER N,%REALFN F)
.
.
%END
%ENDOFPROGRAM
NOTES
1. The names given to the auxiliary routine and its parameters need
not be the same in the integration routine as in the main program
but they must correspond in type.
2. Since the result of the integration is a single quantity, the
routine could be rewritten as a %REALFN:-
%REALFNSPEC INTEGRATE(%REAL A,B, %INTEGER N, %REALFN F)
and called by:
PRINT(INTEGRATE(0,1,INT(10B),AUX),1,6)
LANGUAGE LIBRARY
A complete list of the routines and functions in the IMP Language
Library is given in Section 16. Note that certain of the 'routines',
those described as intrinsic, for example READ and WRITE, are not
strictly routines and their names cannot be substituted as actual
parameters in place of formal parameters of routine type. They would
first have to be re-defined as formal routines. For example the
intrinsic routine write could be re-defined thus:
%ROUTINE MYWRITE (%INTEGER A,B)
WRITE(A,B);!THIS IS INTRINSIC ROUTINE WRITE
%END
%ROUTINE WRITE (%INTEGER A,B)
MYWRITE (A,B)
%END
This solution involving two routines MYWRITE and WRITE is needed when
it is necessary to use intrinsic routines as parameters to other
routines or functions, and to preserve their usual names or when one
wishes to alter the effect of an intrinsic routine.
SCOPE OF NAMES
In general all names are declared at the head of a routine, or
function, either in the routine heading or by the declarations
%INTEGER, %REAL, %INTEGERARRAY etc., and the various routine
specifications. They are local to that routine and independent of any
names occurring in other routines. However, if a name appears in a
routine which has not been declared in one of the above ways, then it
is looked for outside i.e. in the routine or block in which it is
embedded. If it is not declared there it is looked for in the routine
or block outside that and so on until the main block is reached.
Now the main block is itself embedded in a hypothetical outer block, so
that if a name is not found in the main block it is looked for here.
This outer block effectively contains all the implicit and intrinsic
library routines, functions and maps which have preassigned names.
These preassigned names may in fact be redeclared locally at any level,
but clearly it would be unwise to assign new meanings to such routines
as LOG, PRINT etc. Very often, the only non-local names used in a
routine will be the preassigned names.
Routines and functions themselves have the property of being global to
any block interior to the one in which they have been declared and
described.
USE OF %OWN VARIABLES
When a routine or block is left, any information stored in variable
corresponding to local declarations in that routine is normally lost,
and no further reference may be made to it. In some cases it may be
desireable to retain some of this information and be able to refer to
it on a subsequent entry to the routine. This may be accomplished by
prefixing the relevant declaration by %own as described in Section 1.
RECURSIVE USE OF ROUTINES AND FUNCTIONS
Routines and functions have the property of being global to any block
interior to the one in which they are declared. In particular, a
routine or function can be used within the description of that routine
or function itself. This process is called RECURSION. Such a routine
may also call itself indirectly by invoking other routines which make
use of it. On each activation of the routine a fresh copy of the local
working space is set up in the stack, so that there will be no
confusion between variables on successive calls. (This does not apply
however to %own variables. See above). Some criterion within the body
of the routine must eventually inhibit the calling statement and allow
the process to unwind.
Example: A function RECFact equivalent to the function FACT described
earlier can be defined recursively as follows:
RECFact(1) = 1
RECFact(N) = N * RECFact(N-1)
This is easily programmed:
%INTEGERFN RECFact (%INTEGER N)
%IF N = 1 %THENRESULT = 1
%RESULT = N * RECFact (N-1)
%END
Note, however, that in this example it would have been more efficient
to use recurrence rather than recursive techniques.
The following example, however, cannot be easily rewritten as a cycle:
QUICKSORT: Quicksort is an elegant method of sorting numbers (or any
other quantities) into order.
The basic routine,
1. Selects some member of the set to be sorted, and uses this as the
'partition bound'.
2. Partitions the remainder of the set into two groups, one containing
members not greater than the partition bound, and the other
containing members not less than it. These groups are positioned to
the left and right of the bound.
3. Calls itself recursively to sort each of these two groups.
A possible description of this routine, in which the partitioning
bound, D, has been arbitrarily chosen to be right-hand member, and in
which the elements to be sorted are members of a string array, is:
%ROUTINE STRINGSORT (%STRINGARRAYNAME X, %INTEGER A, B)
! SORTS ELEMENTS OF STRINGARRAY X FROM X(A) TO X(B)
%INTEGER L, U
%STRING(255) D
%RETURNIF A >= B
L = A; U = B ; !SET POINTERS
D = X(U) ; !DUMP PARTITION BOUND
-> FIND
UP: L = L +1 ; !THIS SECTION MOVES
-> FOUND %IF L = U ; !L FORWARD UNTIL
FIND: -> UP %UNLESS X(L) >= D ; !FIND A MEMBER >= D
X(U) = X(L)
DOWN: U = U - 1 ; !THIS SECTION MOVES
-> FOUND %IF L = U ; !U BACK UNTIL WE
-> DOWN %UNLESS X(U) <= D ; !FIND A MEMBER <= D
X(L) = X(U)
-> UP
FOUND: X(U) = D ; !PARTITIONING COMPLETE
STRINGSORT (X, A, L - 1) ; !SORT FROM X(A) TO X(L-1)
STRINGSORT (X, U + 1, B) ; !SORT FROM X(U+1) TO X(B)
%END
INCLUSION OF ROUTINES IN LIBRARY FILES
A user who has developed and tested a set of routines may wish to save
these, in their compiled state, for use by subsequent programs. The
required commands or JCL statements to create such files are described
in the appropriate User's Guide.
The Language requirement is as follows.
1. There must be no %BEGIN at the start of the text.
2. Each routine must be prefaced by %EXTERNAL.
3. The text must be closed by %ENDOFFILE rather than by %ENDOFPROGRAM.
4. Variables which are global to the set of routines must be declared
as %OWN or %CONST variables.
5. External routines may call any other external routine in the same
file provided it has been compiled first, or a routine spec has
been given for it.
Example %OWNINTEGER A
%OWNREAL X
%STRINGMAPSPEC THIRD(%STRING S)
%EXTERNALROUTINE FIRST(%INTEGER I)
.
.
! These routines may reference A and X as global variables
%END
%EXTERNALREALFN SECOND(%INTEGER J,%REAL Y)
.
.
.
! SECOND may call FIRST as FIRST has already been compiled
! SECOND may call THIRD as a routine spec has been given
%END
%EXTERNALSTRINGMAP THIRD(%STRING S)
.
.
.
%END
%ENDOFFILE
A program which wishes to call these routines must include the
appropriate %EXTERNALROUTINESPEC statement - as for system library
routines. It is essential that the parameter list in the
%EXTERNALROUTINESPEC statement is identical to that for the
%EXTERNALROUTINE itself, except that the names of the parameters are
not significant. If the number or type of parameters differ the program
may still compile apparently successfully, but at run time obscure
faults may occur.
%EXTERNAL VARIABLES
An alternative method of communicating between %EXTERNAL routines and
the programs and other routines that call them involves the use of
%EXTERNAL variables. These are declared as global variables in a
program or file of %EXTERNAL routines and functions, as are %OWN
variables. They have all the attributes and restrictions of %OWN
variables i.e. they retain their values between calls and they can be
initialised in the same way as %OWN variables. Additionally they can be
accessed by the calling program or by other %EXTERNAL routines by
declaring them as %EXTRINSIC variables. The %EXTRINSIC declaration does
not result in any space being allocated, instead it generates a link to
the %EXTERNAL variables of the same name. For example:
%EXTERNALINTEGER FLAG
%EXTERNALBYTEINTEGERARRAY LINE(1:72)=' '(72)
%EXTERNALROUTINE INPUT
.
.
.
%END
%ENDOFFILE
%BEGIN
%EXTERNALROUTINESPEC INPUT
%EXTRINSICINTEGER FLAG
%EXTRINSICBYTEINTEGERARRAY LINE(1:72)
.
INPUT %UNTIL FLAG=1
%STOP %IF LINE(1)= '*'
.
%ENDOFPROGRAM
It is important to ensure that the name and type of the %EXTRINSIC
declaration is identical to that of the %EXTERNAL declaration, and that
the bounds of arrays are the same.
LENGTH OF %EXTERNAL NAMES
The names given to %EXTERNAL routines, functions and variables can be
up to 255 characters, as for names of other entities in IMP programs.
However only the first 8 characters are used for linking separately
compiled object files. Thus two %EXTERNAL routines called TWEEDLEDEE
and TWEEDLEDUM for example, would give a fault at run time 'DUPLICATE
ENTRIES'. This problem can be avoided by ensuring that names of
%EXTERNAL entities differ in their first 8 characters.
SECTION 7 - STORE MAPPING FACILITIES
INTRODUCTION
Facilities are provided in IMP to allow the programmer to use
alternative names for the same variables. This is useful for the
following reasons:
1. to save space in core
2. to access a variable both as declared, and as a set of
sub-variables, for example an %INTEGER can be accessed as four
separate %BYTEINTEGERs
3. to access a particular array member as a scalar with consequent
saving of machine time
4. to improve the clarity of a program
5. to access a %RECORD using different formats.
Store mapping facilities are very powerful. On the other hand by
allowing the user to operate on addresses they increase the chance of
causing program errors which can be very hard to diagnose.
STORE MAPPING FUNCTIONS
The store mapping function can facilitate the storage of large but
partially redundant arrays. For example, if a two-dimensional array is
symmetrical, X(i,j) = X(j,i), only the values of X(i,j) with i>=j need
be stored. By keeping only these values in the one-dimensional array,
A(p), and providing alternative location names, X(i,j) for the elements
of A through a store map, we can have the most economical use of store
without losing the symmetrical appearance of the array X.
The store mapping function is declared by:
%MAP %SPEC
where type depends on the nature of the variable to be renamed and may
be %BYTEINTEGER, %SHORTINTEGER, %INTEGER, %REAL, %LONGREAL or %STRING.
The general form of a store mapping function W is written:
%MAP W(%INTEGER I,J,...)
%RESULT== A(exp1(I,J,...),exp2(I,J,...)...)
%END
In this case the array A is to be given the alternative name W, and the
suffices of A, exp1, exp2 etc. are general expressions in terms of the
suffices of W - I, J, etc. There is no restriction on the number of
suffices that can be associated with W. It is assumed above that A is
global to the description of the mapping function, but A could have
been declared as a formal parameter in the function heading, thus:
%SHORTINTEGERMAP W(%INTEGER I,J, %SHORTINTEGERARRAYNAME A)
As an example, the map for the case of the symmetrical two-dimensional
array X stored in A described above is:
%INTEGERMAP X(%SHORTINTEGER I,J)
%RESULT== A(I*(I-1)/2 + J) %IF I>J
%RESULT== A(J*(J-1)/2 + I)
%END
Like functions, mapping functions can appear in arithmetic expressions
but have the added property that they can appear on either the left or
right-hand side of an assignment statement. On either side, the result
of a mapping function is an address from which, or to which a value is
fetched or stored according to context.
The saving in storage space achieved by using mapping function is
obtained by sacrificing speed in the execution of the compiled program.
For this reason mapping functions are not recommended in situations
where they would be called frequently.
THE BUILT IN MAPPING FUNCTIONS
There are seven built in mapping functions available to the user, for
simple variables:
%INTEGERMAPSPEC INTEGER (%INTEGER N)
%SHORTINTEGERMAPSPEC SHORT INTEGER(%INTEGER N)
%BYTEINTEGERMAPSPEC BYTE INTEGER (%INTEGER N)
%REALMAPSPEC REAL (%INTEGER N)
%LONGREALMAPSPEC LONG REAL (%INTEGER N)
%STRING (255) %MAPSPEC STRING (%INTEGER N)
%RECORDMAPSPEC RECORD (%INTEGER N)
They all give locations of a particular byte having as its absolute
address in the main store the value N. BYTE INTEGER picks up only the
byte; SHORT INTEGER picks up 2 bytes; REAL and INTEGER pick up 4 bytes;
LONG REAL picks up 8 bytes; and STRING picks up the number of bytes
determined by the string length given in the first byte. An address
error occurs if SHORT INTEGER attempts to pick up two bytes which are
not correctly halfword aligned, if REAL or INTEGER attempts to pick up
four bytes not correctly fullword aligned, or if LONG REAL attempts to
pick up eight bytes not correctly double word aligned.
In contrast to user defined maps the above built in maps are very
efficient in terms of speed and space. For example an %INTEGER can be
unpacked into its four component %BYTEINTEGERs thus:
%INTEGER I,J
%BYTEINTEGERARRAY B(0:3)
......... .
I=........
%CYCLE J=0,1,3
B(J) = BYTEINTEGER (ADDR(I)+J)
%REPEAT
...........
It is sometimes necessary to do the reverse of that shown above; say to
reform a long real variable, X, from two components stored in %INTGERS
J1 and J2. The following example shows the use of a mapping function on
the LHS of an expression.
%LONGREAL X
%INTEGER I,J1,J2
......
INTEGER(ADDR(X))= J1
INTEGER(ADDR(X)+4)=J2
POINTER VARIABLES
Pointer variables provide an additional mapping facility. A pointer
variable is declared in the same way as a normal scalar variable except
that %NAME is added to the type.
Example: %INTEGERNAME I,J,K
%LONGREALNAME P1
The declaration does not result in any space being allocated for the
variables, it merely causes the compiler to record the names. Before
being used the pointer variable has to be equivalenced to a declared
variable using the == operator. From then on both the original name and
the name of the pointer variable can be used to access the variable.
For example if a three-dimensional array is being accessed in such a
way that frequent reference is made to its first element it would
improve the efficiency of the program to equivalence the first element
to a pointer variable.
%INTEGERARRAY TABLE(1:10,1:10,1:10)
%INTEGERNAME BASE
BASE==TABLE(1,1,1)
Additionally pointer variables can be used in conjunction with the
built in maps to provide a more elegant solution in the situation where
it is required to reference the same space in two different ways. For
example if it is required to reference a %BYTEINTEGERARRAY as a %STRING
the following code could be used:
%BYTEINTEGERARRAY IN(0:80)
%STRINGNAME LINE
LINE==STRING(ADDR(IN(0)))
From this point onward the array can be referenced either as an array
or as the string, LINE. Obviously the length byte, IN(0), will have to
be set to an appropriate value.
ARRAY MAPPING
Apart from mapping for individual variables it is possible to use the
built in map ARRAY. This takes two parameters: an address and the name
of an %ARRAYFORMAT. In the following example the two-dimensional array
ATWO is mapped on to an array AONE which is declared as a one dimension
array:
%INTEGERARRAY AONE(1:10000)
%INTEGERARRAYNAME ATWO
%INTEGERARRAYFORMAT AFORM(1:100,1:100)
ATWO==ARRAY(ADDR(AONE(1)),AFORM)
ATWO(27,27)=928
.
.
The %ARRAYFORMAT statement is used to describe the characteristics of
the array ATWO - i.e. number of dimensions and bounds for each
dimension. As an alternative to using the name of an %ARRAYFORMAT for
the second parameter, the name of another %ARRAY can be used, if one
with suitable characteristics has been defined in the program.
RECORD MAPPING
This is described in Section 9.
SECTION 8 - STRINGS
INTRODUCTION
A 'string' in the IMP language is a string of between 0 and 255
characters. Space and newline characters may be included.
Strings in IMP are declared and manipulated in ways largely analogous
to those for the arithmetic entities in IMP. They can be declared
singly or in arrays of one or more dimensions. They are declared at the
head of blocks or routines. The space which they occupy can be
allocated dynamically, or they can be declared as %OWN, %CONST,
%EXTERNAL or %EXTRINSIC. The same scope rules apply as for the names of
arithmetic types. Strings may appear as the results of functions, and
may be written into programs as constants. They may be referenced as
elements of records and through mapping functions and pointer
variables. They may be passed as parameters to routines, functions and
mapping functions by 'value' and by 'name', and these modes are
analogous to those for the arithmetic types.
String expressions may be tested in conditions. The elaboration of a
string condition is sometimes markedly different from that of an
arithmetic condition, but a set of IMP statements can be made
conditional by prefixing or suffixing a string condition in a manner
similar to prefixing or suffixing an arithmetic condition, and the
lexicographical forms are similar.
Finally, the IMP run-time diagnostic package treats strings in
essentially the same way as other IMP variables and provides for
detection of run-time faults such as 'unassigned variable' and the
listing of string type variables in the diagnostic routine trace-back.
String manipulation fault conditions may be trapped using the standard
fault-trapping mechanism. (see Section 14)
This section describes features of string declaration and manipulation
in so far as they differ from those of the arithmetic entities in IMP,
and in particular describes string operations and conditions.
TERMINOLOGY
The 'value' of a string means the sequence of characters forming the
string. In the context of this section, 'value' and 'string' are
practically synonymous, except that a 'value' normally describes the
result of evaluating a 'string expression'. The value of a string is
denoted where necessary by the characters of the string enclosed in
single quotes, except that each single quote within the string is
denoted by two single quotes. The 'length' of a string is the number of
characters forming the string. It may be zero, when the string is (has
value) null.
Within this section except where otherwise stated,
'location' means 'string location'
'constant' means 'string constant'
'variable' means 'string variable'
'function' means 'string function'
'mapping function' means 'string mapping function'
'record element' means 'string-type element of a record'
'expression' means 'string expression'
'value' means 'value of a string or string expression'
'assignment' means 'string assignment using
the "=" or "<-" operator'
All these terms are defined in the text.
STRING LOCATIONS
A 'string location' is a portion of storage which a program accesses
using string operators. Thus string declarations cause space to be
allocated as a set of one or more locations. A location has an
associated 'maximum length', which may be specified as part of a
declaration, or in defining a function or mapping function. The number
of bytes occupied by a location is one greater than this maximum
length. A location has no special alignment.
When a location holds data (a string, or 'value'), the data format in
the location is as follows. The first byte of the location holds the
length of the string. Successive bytes (so far as necessary) hold the
characters of the string as a sequence of ISO character values. Clearly
the length of the value held cannot exceed the maximum length of the
location.
A location may be referenced in the following ways:
1. using the name of a variable,
2. using a subscripted array name,
3. using a mapping function name (possibly subscripted with
parameters), (see Section 7).
4. using a record name subscripted with a record element name,
(Section 9), or
5. using a pointer variable name (Section 7).
A reference to a location implies using the address of (the first byte
of) the location, and this is the address produced by the built-in
function ADDR when applied to a location (Section 7).
STRING CONSTANTS
A 'string constant' is denoted by its value enclosed in single quotes,
except that each single quote contained within the string is denoted by
two single quotes. Examples are:
'IT''S MINE'
'TESTING
'
''
The second example denotes a constant whose value has eight characters
(whose length is eight), the eighth being newline. The third example
(two adjacent single quotes) denotes a null constant.
Constants may appear in 'expressions', and in declarations where
initialization is permitted.
STRING VARIABLES
A 'string variable' is an unsubscripted name used to reference a
location. A declaration of a variable causes (either static or dynamic)
allocation of space for the location which it references. The
declaration must specify the maximum length of the location by
enclosing this in parentheses after the delimiter '%STRING' e.g.
%STRING(255) U
%STRING (20) LH,RH
%OWN, %CONST and %EXTERNAL variables may be initialized explicitly by
specifying an initializing constant, thus:
%OWNSTRING(19) FILENAME='ERCC00.TEST'
If the explicit initialization is omitted, the variable is given an
initial value of null.
STRING ARRAYS
A 'string array' is an array of one or more (maximum seven) dimensions
of locations which may be referenced using the array name and one or
more subscripts. All locations of a given array must have a common
maximum length, which should be stated in the array declaration or
array format statement. Examples of array declarations are:
%STRING(63) %ARRAY FIELDS(1:5)
%STRING(63) %ARRAY NAMES1,TAGS(0:9,-1:0)
%OWN, %CONST and %EXTERNAL arrays may be explicitly initialized by
giving a list of constants, possibly with repetition factors, as for
comparable arithmetic type arrays. For example:
%OWNSTRING(6) %ARRAY F(0:4)= 'FRED','A',''(3)
If the explicit initializations are omitted, each location is
initialized to null.
STRING FUNCTIONS
Analogously with arithmetic functions (Section 6), a 'string function'
may appear in a 'string expression' (see below). A string function is
declared in exactly the same way as an arithmetic function, except that
the maximum length of the value which the function can yield is stated
in the declaration. Thus:
%STRING(20) %FN FIELD (%INTEGER I)
Execution of a string function terminated at a %RESULT statement must
assign a 'string expression', described below, to %RESULT, which causes
this value to be used in the 'string expression' at the place the
function was called.
Assignment to %RESULT does not at present cause the 'CAPACITY EXCEEDED'
run-time fault, though later compilers may take note of the maximum
length included in the function declaration.
STRING MAPPING FUNCTIONS
String mapping functions provide a means of referencing an area of
storage as a string location. A map name (possibly subscripted with
parameters) is a synonym for a location whose address is the %RESULT of
the mapping function. For example, if the mapping function:
%STRING(3)%MAP XA (%INTEGER I)
%RESULT = ADDR(A(I))
%END
is declared, where A is a (0:5) %INTEGER array, then XA(I) is synonymous
with the string location which has the same address as the Ith element of A.
The declaration of the mapping function includes the maximum length of
the locations which it is to reference, but assignments to such
locations cannot cause the 'CAPACITY EXCEEDED' run-time fault (see
below). Thus, as always with mapping functions, care is required to
ensure that a program does not unintentionally overwrite data not
directly being referenced.
The intrinsic mapping function STRING may be of particular use. Its
effect is that of the following:
%STRING(255) %MAP STRING (%INTEGER ADDRESS)
%RESULT = ADDRESS
%END
STRING EXPRESSIONS : CONCATENATION
A 'simple operand' is a constant, a string function or one of the
denotations for referencing a location (listed above in the section
defining locations).
A 'string expression' is a simple operand or a denotation composition
of one or more operations on simple operands. It has a value, namely
that of the simple operand or that which results from performing the
operations on the simple operands.
Only one kind of operation is permitted in string expressions:
concatenation, denoted by dot (.). This is a binary operator, and its
two operands are written on either side of it, thus:
A.B
The result of concatenating two operands is the string comprising the
value of the first operand followed by the value of the second operand.
Thus the expression:
'HASTINGS'.'1066'
has value denoted:
'HASTINGS1066'
It is not commutative (A.B#B.A).
Unlike arithmetic expressions, string expressions may not contain
sub-expressions. Thus a string expression must always be written as a
sequence of say N simple operands separated by N-1 dots (N>0). For
example, the following is an expression:
'CONST'.VAR.TOSTRING(I+J)
where VAR is a variable and TOSTRING is a function.
When an expression comprises more than one concatenation of simple
operands, the concatenations are performed starting from the left of
the expression. If a concatenation results in a value (intermediate or
final) whose length exceeds 255, the 'CAPACITY EXCEEDED' run-time fault
may occur (see Section 13).
STRING ASSIGNMENTS
The value of an expression may be assigned to a location (referenced in
one of the ways listed in the section above defining string locations)
or, in a function, to %RESULT.
There are two types of assignment, analogous to the arithmetic
assignments, denoted by '=' and '<-'. The former is called simply
'(ordinary) assignment' and the latter is called 'jam transfer'.
Examples are:
SARR(J)=S
S<-A.B.C
where A,B,C,S are string variables, J is an integer variable and SARR
is an array.
For the '=' assignment, the value of the expression on the right-hand
side is assigned to the location denoted by the left-hand side. The
'CAPACITY EXCEEDED' run-time fault may occur (see Section 13).
The '<-' assignment operates exactly as the '=' assignment except that
the 'CAPACITY EXCEEDED' run-time fault cannot occur: if the length of
the value denoted by the right-hand side exceeds the maximum length N
of the left-hand side location, assignment only of the N left-most
characters of the right-hand side value occurs. This assignment may be
used intentionally to truncate the value being assigned.
STRING RESOLUTIONS
A further type of operation provides a powerful tool for analysing
strings and assigning 'substrings'. Explicitly, a string S is a
'substring' or a string T if it can be concatenated with two other
(possibly null) strings to form the string T.
A 'string resolution' is a left-to-right operation denoted by '->'.
Its left-hand operand must be a location (referenced in one of the ways
listed above defining string locations). Its right-hand operand must be
a sequence alternately of locations and expressions. The locations and
expressions must each be separated by a dot (.) separator, and the
expressions must further be enclosed in parentheses. For example:
L->M.(E).N.(F).P
where L,M,N,P are locations and E,F are string expressions.
To describe the effects of resolution, we take the simple case of the
following resolution:
L->M.(E).N
When executed, the resolution may 'succeed' or 'fail'. It 'succeeds' if
the value of the expression E is a substring of the value at the
location L. This value is now considered as three substrings: that part
which precedes the left-most occurrence of E in it; that part which is
the left-most occurrence of E; and that part which follows the
left-most occurrence of E. The location L remains unchanged, but the
first substring above is assigned to M and the value of the third
substring above is assigned to N. (M or N may be assigned null values
in the resolution). The 'CAPACITY EXCEEDED' run-time fault may occur
during these assignments (see below). Otherwise the resolution always
succeeds if the value of E is null.
If the value of E is not a substring of the value at location L, the
resolution 'fails' and no assignments take place. In this case (unless
the resolution forms part of a 'string condition', described below) the
'resolution fails' run-time fault (Fault number 26) occurs. This fault
may be trapped, see Section 14.
The following is an example of the simple resolution so far described.
If location L contains 'HASTINGS1066' then
L->M.('10').N
succeeds and causes 'HASTINGS' to be assigned to M and '66' to N.
Consider now the more complex resolution:
L->M.(E).N.(F).P
This is executed exactly as though a private location PRIV, of maximum
length 255, existed and the resolutions:
L->M.(E).PRIV
PRIV->N.(F).P
were performed. The resolution succeeds if both of these resolutions
would succeed; otherwise it fails.
The general resolution is executed in an analogous way, hypothetically
using further 'private' locations to split the resolution into simple
resolutions. Note that in the general resolution some of the
intermediate assignments or other consequent actions (such as the
execution of functions or mapping functions) may have been effected
before the resolution fails or before a possible 'CAPACITY EXCEEDED'
run-time fault occurs.
The following is an example of a more complex resolution. If location L
contains value 'ERCC00INDEX2' and E has value 'INDEX' then
L->M.(.'ERCC').N.(E).P
succeeds and causes M to be assigned a null value, '00' to be assigned
to N and '2' to be assigned to P.
Finally, in a resolution the initial or final locations, or both, with
their associated separator operators ('.'), may be omitted, provided
that the right-hand side of the resolution still contains at least one
expression in parentheses and at least one location. Examples are:
L->(E).M L->M.(E)
The first example succeeds if the value of E is a substring of L and
there is no non-null substring of L to the left of the occurrence of E
in L. The second succeeds if the value of E is a substring of L. Note
that there is asymmetry between the cases of these examples: the second
is equivalent to
L->M.(E).SINK
where SINK is an unwanted location of length 255. However, the first
example is not equivalent to
L->SINK.(E).M
Explicitly, if location L contains 'HASTINGS' then
L->('HA').M succeeds
L->('TING').M fails
L->M.(.'TING') succeeds
L->M.(.'TINGS') succeeds.
STRING CONDITIONS
'String conditions' are analogous to arithmetic conditions in that %IF,
%UNLESS, %WHILE and %UNTIL may cause tests to be made on locations and
cause the sequence of execution of statements to depend on the outcome
of the tests. A set of IMP statements may be made conditional by adding
string conditions and the lexicographical forms are essentially the
same.
The tests performed may be of two kinds. The first kind is a relational
test, analogous to an arithmetic test, in which two (or three)
expressions are compared, specifying one (or two) of the relational
operators <,<=,=,>=,>,#. (Three expressions with two relational
operators form a double-sided condition, whose effect is analogous to
that of a double-sided arithmetic condition). The second kind is a test
of a resolution, as described above.
Examples of the two kinds are:
%IF S<'WATER' %THEN ->LAB
%IF L->M.(.'INGS').N %THEN ->LAB
RELATIONAL STRING CONDITIONS
The expressions to be tested are first evaluated (the order of
evaluation is not defined). A test of a relationship between the two
values commences with up to M character comparisons, where M is the
minimum of the lengths of the two values. The comparisons are based on
the internal codes for the characters of the strings, namely the ISO
character codes. The test may continue with a comparison of the lengths
of the two values.
If the relational operator is '=', the relationship is TRUE if and only
if the values are identical, that is:
1. the lengths L of the two values are equal, and
2. if L>0, the i-th characters of each are equal for 00, the i-th character of the left-hand value has internal code
less than that of the i-th character of the right-hand value for
0='. Analogous comparisons
are made for the relational operators '>' and '<='.
Thus:
'AB'<'C' is TRUE
'AB'<'ABC' is TRUE.
'IMP'<'FORTRAN' is FALSE
'Double-sided' conditions are permitted. An example where S and T are
string expressions is: %IF 'AB' < S < T %THEN -> LAB
RESOLUTION STRING CONDITIONS
The resolution which is the subject of the condition is elaborated
exactly as described in the section concerned with 'string
resolutions', except that the 'resolution fails' run-time fault cannot
occur. If the resolution succeeds the condition is TRUE, and if it
fails the condition is FALSE.
The statements of the following example remove all 'leading' space
characters from the string S.
%WHILE S->(' ').S %CYCLE; %REPEAT
THE 'CAPACITY EXCEEDED' RUN-TIME FAULT
The 'CAPACITY EXCEEDED' run-time fault (Fault number 30) is a
'trappable' fault which is normally 'enabled'. For assignment
operations only it may be 'disabled' (that is, execution will be
allowed to proceed without diagnostic message), in a program by
specifying the compiler option NOARRAY when the program is compiled. If
the fault is disabled it cannot be 'trapped'. Disabling the fault
enables shorter and faster object code to be produced by the compiler,
but should be used with discretion.
The fault occurs during expression evaluation when the length of an
intermediate or final result exceeds 255. It also occurs, when enabled,
during assignment (by the '=' operator or during resolution but not by
the '<-' operator) when the length of the value being assigned exceeds
the maximum length of the location being assigned to.
Note that when this fault occurs during the evaluation of a complex
expression or during the elaboration of a resolution, some of the
intermediate assignments or other consequences (such as execution of
functions or mapping functions) may already have been effected.
If the 'CAPACITY EXCEEDED' condition arises during assignment when the
fault is disabled, the results will be unpredictable (for example
through consequent over-writing of locations not intentionally
referenced). It is therefore very undesirable that this fault be
disabled before a program is well-proved to execute without the
condition arising, or that adequate cognisance has been taken of the
consequences.
Note that the '<-' assignment (described above) can be used to
circumvent the 'capacity exceeded' condition in a controlled way.
STRING MANIPULATION FUNCTIONS
The following functions are either in the intrinsic or implicit
category and hence can be called without being specified in the program
(see Section 16).
%INTEGERFN CHARNO (%STRINGNAME S,%INTEGER N)
This returns the internal
code value of the Nth character of string S. If N is greater than the
current length of S then the result is undefined.
%STRING(255)%FN FROMSTRING(%STRINGNAME S,%INTEGER I,J)
The result is
the sub-string of S comprising the Ith to Jth (inclusive) characters of
S. The fault 'STRING INSIDE OUT' will occur unless i<=I<=J and J is not
greater than the current length of S.
%INTEGERFN LENGTH (%STRINGNAME S)
The result is the current length of
the string, for example if S currently contains the string 'FIRE' then
the result of a call of LENGTH(S) would be four.
%STRING(1)%FN TO STRING(%INTEGER I)
The result is a string of length 1
whose value is the character defined by the least significant 7 bits of
the integer I.
STRING INPUT/OUTPUT ROUTINES
The routine provided for the input and output of strings are all in the
implicit or intrinsic category, so do not need to be specified. They
operate on the currently selected input and output streams. (See
Section 10).
%ROUTINE READSTRING(%STRINGNAME S)
This routine which takes the name of
a %STRING variable as its parameter and is used to read a string into
the variable. The string should be written as described under the
heading 'STRING CONSTANTS', above. Any spaces and newlines are ignored
before the first quote character of the string. The trappable faults
'CAPACITY EXCEEDED' will occur if an attempt is made to read a string
into a variable which has not been defined to be sufficiently long.
Also 'INPUT ENDED' and 'SUBSTITUTE CHARACTER IN DATA' faults can occur.
(See Section 10).
%ROUTINE READITEM(%STRINGNAME S)
This routine takes the name of a
string variable as its parameter. It is used to read the next symbol
from the current input stream and to put it into the variable as a
string of length 1. Faults appropriate to READSYMBOL can occur.
%STRINGFN NEXTITEM
This is a string function which takes no parameter.
It returns as its result a string of length 1 whose value is that of
the next symbol on the current input stream. As with the function
NEXTSYMBOL the pointer to the input stream is not moved by this
function. Faults appropriate to NEXTSYMBOL can occur.
%ROUTINE PRINTSTRING (%STRING(255)S)
This routine takes a string
expression as its parameter, of maximum length 255 characters. The
expression is evaluated and the resulting string of characters is
printed on the current selected output stream. PRINTSTRING effectively
uses PRINTSYMBOL to output characters so all the characteristics of
PRINTSYMBOL apply.
SECTION 9 - RECORDS
INTRODUCTION
'Records' in the IMP language provide a means of handling collections
of data types as single entities. Like an array, a 'record' has an
identifier which can be used to refer to the whole collection of data
within it. Unlike an array, however, the sub-fields (elements) of it
may have different types. Whereas an array element is referenced using
the array identifier subscripted with an expression which evaluates a
numerical index, an element of a record is referenced by subscripting
the record identifier with the required sub-field identifier. The
syntactic form of the subscript also is different for a record element,
as will be made clear below.
The content of this section of the manual may be subject to
change in matters of detail with later versions of the IMP compiler.
RECORD FORMATS
A 'record format' defines the collection of objects which are to form a
record. An IMP record format statement comprises a format identifier
followed by a list of sub-field identifiers enclosed within
parentheses.
Each sub-field identifier must have a 'type' which is one of the types
of entities in IMP, namely
%BYTE or %SHORT %INTEGER, %INTEGER, %REAL, %LONGREAL, or %STRING,
Also arrays (but with single dimension and constant bounds) of the
above types, %NAMEs and %ARRAYNAMEs ('pointers') of the above types may
be used.
Additionally, a sub-field type may be %RECORD, %RECORDARRAY or
%RECORDNAME and these are discussed below.
An example of a record format statement is:
%RECORDFORMAT F(%BYTEINTEGER A, %STRING(8) S, %C
%INTEGERARRAY M,F(1:100), %REAL Y)
Record format statements do not cause allocation of storage (Section
5). Sub-field identifiers need not be distinct from identifiers of
other entities in the program, block or routine, since identifiers of
sub-fields always occur in conjunction with the name of a record, as
described below. Record format statements are placed at the head of a
block or routine along with the storage-allocating declarations, and
the same scope rules apply for these identifiers as for those of other
entities in IMP.
Sub-fields named in record formats have 'lengths' and 'alignments'
equal to those of the corresponding types of IMP entities; the record
format likewise has a 'length' which is implied by the lengths and
alignments of its sub-fields. This is discussed more fully below.
RECORDS
Records are declared in the same way as the arithmetic and string types
of entities in IMP. They are declared at the heads of blocks or
routines. The space which they occupy can be allocated dynamically, or
they can be declared as %OWN, %CONST, %EXTERNAL or %EXTRINSIC. However,
the space occupied by these latter types may not be initialized
explicitly, and will be initially all zeros (all bits will be zero).
The same scope rules apply for record identifiers as for arithmetic and
string type identifiers. Space is allocated, and subsequently
referenced, according to the record format whose identifier forms part
of the record declaration. The required record format identifier, which
must be previously declared and in scope, is written in parentheses
following the record identifier. Several records of a given format may
be declared in a single statement, as in the following examples:
%RECORDFORMAT F(%INTEGER A, %STRING(8) S)
%RECORD R(F)
%RECORD PP, QQ, RR(F)
The amount of space allocated is equal to the length of the record
format. The first sub-field of the record is double-word aligned. A
fuller discussion of lengths and alignments is given later in this
section.
Each sub-field of a record can be referenced as an IMP location of
appropriate type by subscripting the record identifier with the
sub-field identifier: the record identifier is followed by the
underline '_' character followed by the sub-field identifier. Thus,
following the above format and record declarations, one may write:
%IF R_S='INC' %THEN R_A=R_A + 1
A further example follows:
%RECORDFORMAT PE(%INTEGER I, %REALARRAY X(0:10))
%RECORD P(PE)
%INTEGER J
P_X(J+1) = .P_X(J) * 2
RECORD ARRAYS
'Record arrays' are entirely analogous to the arithmetic and string
types of arrays. Each element of a record array is a record of format
specified in the record array declaration. The identifier of the format
which is to be applied to each element is written in parentheses
following the record array identifier and bounds. Thus:
%RECORDFORMAT F(%INTEGER A, %REALARRAY X(1:5))
%RECORDARRAY RA(1:100) (F)
Then the fifth element of sub-field X in the 100th record array element
may be referenced:
RA(100)_X(5)
As with other types of array, several record arrays having the same
bounds and format may be declared in a single statement. Thus:
%RECORD %ARRAY RR1, RR2 (1:100) (F)
The space for a record array may be allocated dynamically, or the array
may be %OWN, %CONST, %EXTERNAL or %EXTRINSIC. These latter types may
not be initialized explicitly, but all bits will be initially zero. The
first sub-field of the first element of the array is double-word
aligned, but subsequent elements are given an alignment which provides
the closest packing of the elements of the array consistent with the
format of each element.
RECORD 'POINTER' VARIABLES
Analogously with the %NAME ('pointer') variables for the arithmetic and
string entities, (see Section 7) 'record names' and 'record array
names' may be declared; they must be given an associated format by
writing a record format identifier (previously declared and in scope)
in parentheses following the pointer variable being declared. For
example:
%RECORDFORMAT F(%INTEGER A, %REALARRAY X(0:5))
%RECORDNAME F1(F)
%RECORDARRAYNAME Z,W(F)
These pointer variables are assigned to using the '==' operator, the
right-hand operand of which must be a reference to a record location
having the same format as that specified for the pointer variable which
is the left-hand operand. Following the assignment, the pointer
variable identifier is synonymous with that of the location reference
which was assigned to it.
Thus, taking the declarations of the previous example, one may write
%RECORD Q,R(F)
%RECORDARRAY A(1:10) (F)
Then
F1==Q makes F1 a synonym for record Q,
F1==A(10) makes F1 a synonym for the 10th element of A,
Z==A makes Z synonymous with A.
A reference to a record location which is of particular value is the
built-in special record mapping function RECORD, whose single parameter
is a suitably-aligned address. This function may appear as the
right-hand operand of an '==' assignment to a %RECORDNAME variable,
which then provides a means of accessing sub-fields of the area
starting at the address given as parameter (even though that area may
not previously have had a format applied to it, or if it had previously
been referenced as a location of different format). The following
example illustrates both these points.
%INTEGER J
%INTEGERARRAY II(1:100)
%RECORDFORMAT A(%BYTEINTEGER I,J,K,L)
%RECORDFORMAT B(%SHORTINTEGER P,Q)
%RECORDNAME X(A)
%RECORDNAME Y(B)
X==RECORD(ADDR(II(J)))
Y==RECORD(ADDR(II(J)))
Now for example
X_I is a reference to the left-most byte of II(J)
Y_P is a reference to the left-most half-word of II(J).
SUB-FIELDS OF TYPE '%RECORD'
A sub-field in a record format statement may itself be of type %RECORD.
The format for the sub-field identifier is written after it in
parentheses as in the following examples:
%RECORDFORMAT P(%INTEGERARRAY X(0:4), %INTEGER I)
%RECORDFORMAT FT(%INTEGER A,B, %RECORD D(P))
%RECORDFORMAT F2(%RECORD J,K(P))
%RECORD ENT(F1)
%RECORD JAK(F2)
An arbitrary 'depth' of subscription can thus obtain, depending only on
the scope rules for the declarations. With the above declarations, the
following are valid references to record elements:
ENT_D_X(1)
JAK_J_1.
SUB-FIELDS OF TYPE '%RECORDNAME': '%RECORDSPEC'
Additionally a sub-field of a format may be of type %RECORDNAME but in
this case a format is given to the sub-field identifier not in the
format statement itself, but in a separate and subsequent %RECORDSPEC
statement, which is analogous to the %SPEC statement requirement for a
%ROUTINE or %FN parameter (Section 6). For example:
%RECORDFORMAT F(%INTEGER I, %RECORDNAME J)
%RECORDFORMAT K(%REAL X,Y)
%RECORDSPEC F_J (K)
The following example is interesting in that the recursive nature of
the format and sub-field format definitions facilitates the creation of
a list structure:
%RECORDFORMAT F(%INTEGER DATA, %RECORDNAME LINK)
%RECORDSPEC F_LINK(F)
%RECORDARRAY P(1:1000)(F)
The structure may be initialised as follows so that the 'link' field of
each element of the array P 'points' to the subsequent element:
%INTEGER J
J=1
%WHILE J<1000 %CYCLE
P(J)_LINK==P(j+1)
J=J+1
%REPEAT
The 'link' field of the last element may be set zero using the built-in
special record mapping function RECORD with a parameter of 0. Thus:
P(1000)_LINK==RECORD(0).
RECORDS AS PARAMETERS TO ROUTINES: '%RECORDSPEC'
Records may be passed as parameters to routines, functions and mapping
functions only by 'name'. Where a routine is declared having a
%RECORDNAME parameter, the identifier in the formal parameter list as
usual has scope which is the textual extent of the routine but
excluding contained blocks in which the identifier is re-declared. But
the record location to be referenced by that identifier has no format
implicitly associated with it within that routine. Before the formal
parameter identifier can be used, it is necessary to include within the
routine a '%RECORDSPEC' statement, which associates a record format
identifier, in scope at that textual position, with the %RECORDNAME
formal parameter identifier. The format thus associated with the
parameter need not be identical with any format used outside the
routine to reference locations outside the routine, although great care
should be used in the use of different formats for the same record.
The record format identifier is written in parentheses following the
identifier with which it is to be associated. Thus:
%ROUTINE R(%RECORDNAME P)
%RECORDFORMAT F(%BYTEINTEGER A,B,C,D)
%RECORDSPEC P(F)
RECORD ASSIGNMENTS
Whilst sub-fields of records may be assigned and manipulated exactly as
if they were IMP entities of corresponding type, it is possible
additionally to assign a whole record from one location to another. As
with arithmetic and string assignment two assignment operators are
permitted, namely '=' and '<-'. Both require that the left and
right-hand operands are references to record locations, except that in
the case of '=' a right-hand operand of zero is permitted, which has
the effect of setting all bits in the left-hand location to zero. The
'=' operator further requires that the formats associated with the left
and right-hand operands have the same length; the '<-' effects a
transfer of the number of bytes which is the smaller of the lengths of
the two record formats. In both cases the transfer is without regard to
considerations of format within either record.
The following example shows uses of the '=' assignment:
%RECORDFORMAT F(%INTEGER X,Y,Z,A)
%RECORDFORMAT Q(%BYTEINTEGERARRAY B(0:15))
%RECORD J(F)
%RECORDARRAY K(1:100) (Q)
J=K(1)
K(1)=0
LENGTH AND ALIGNMENT
The length of a record format, and the amount of space occupied by a
record of given format, is the total number of bytes occupied by all
the sub-fields, with the sub-fields, with the first sub-field
double-word aligned and a minimum number of 'spacing' bytes inserted
between adjacent sub-fields where necessary to achieve alignments
appropriate to their types.
For example, the record format
%RECORDFORMAT F(%BYTEINTEGER B, %INTEGER I)
has length 8. Three bytes (not referenced explicitly through this
format statement) must follow the sub-field B when the format is
applied to an area of storage having double-word alignment in order
that sub-field I is properly aligned. The requirement to double-word
align a record may also result in up to 7 non-referenceable bytes being
assigned.
The alignments and lengths of possible sub-fields of records formats
are shown in the following table.
Type Alignment Length
%BYTEINTEGER (and array) byte 1 (and N*1)
%SHORTINTEGER (and array) half-word 2 (and N*2)
%INTEGER (and array) word 4 (and N*4)
%REAL (and array) word 4 (and N*4)
%LONGREAL (and array) double-word 8 (and N*8)
%STRING (and array) byte L+1 (and N*(L+1))
%RECORD double-word R
%ARRAY %NAME word 8
other %NAME word 4
where N is the number of elements in the array,
L is the length of the string,
R is the length of the record.
In the case of %RECORDARRAYS the first record in the array is double
word aligned. Any subsequent records are aligned as necessary for the
elements therein.
SECTION 10 - INPUT/OUTPUT FACILITIES
INTRODUCTION
Input/Output (I/O) facilities are provided to enable programs to read
data from input devices and files and to output data to output devices
and files. This section describes the routines and functions provided
by the IMP System in terms of their program characteristics. All the
routines refer in some way to logical I/O CHANNELS. These channels are
assigned numbers in the range 0 - 99, of which channels 0 and 81-99 are
reserved for system defined devices. Channel numbers in the range 1 -
80 can be used for purposes defined by the user, subject only to the
rule that there must be no conflict between channel numbers used for
different types of file. Each implementation of the language provides
facilities for linking these logical channels to particular files or
devices and information on this subject is contained in the User Manual
for the appropriate computer.
CHARACTER AND BINARY INFORMATION
The primary I/O facilities in IMP use character information, that is
information which can be represented in sequences of printable
characters. A variety of routines is provided to handle individual
characters, or to interpret sequences of characters as numeric values,
or string values.
Additionally I/O routines are provided to handle binary information, as
a direct copy of the internal representation of values held in the
computer's core store. Two types of binary I/O are provided -
Sequential for use when data is accessed in the order in which it is
held in the file, and Direct Access for use when data is accessed
randomly from all parts of the file.
All the routines associated with character I/O are intrinsic or
implicit - that is no declaration of them is needed before they are
called. All the binary I/O routines are explicit, that is they must be
declared in each program in which they are used.
CHARACTER CODES
All the character handling routines in IMP use an Internal Character
Code based on the ISO Code for the Interchange of Data, see Section 16
of this manual. Some implementations of IMP may use other codes e.g.
EBCDIC to represent characters on storage devices but this need not
concern the IMP programmer since the necessary translation to and from
the Internal Code will be carried out by the operating system.
CHARACTER STREAMS
All character handling routines and functions operate with respect to
either the currently selected INPUT STREAM or the currently selected
OUTPUT STREAM. On entry to a program the system selects default streams
for input and output. At any point in the program it is possible to
redirect character input or output by a call of
%ROUTINE SELECTINPUT(%INTEGER I)
or %ROUTINE SELECTOUTPUT(%INTEGER I)
Each of these routines takes one integer parameter which should have
the value of the logical channel number required.
Examples: SELECTOUTPUT (3)
SELECTINPUT (I + 17)
After a call of SELECTINPUT all calls of character input routines will
operate on the selected input stream, until another call of SELECTINPUT
is made, or the end of the program is reached. The same rule applies to
SELECTOUTPUT and character output routines.
Both input and output characters are buffered by the operating system
into lines. This has the following effects on the use of SELECTINPUT
and SELECTOUTPUT. If an input stream is re-selected later in a program
the first character read after re-selection will be the first character
in the line following that last accessed. Thus it is possible that part
of a line will be lost. When an output stream is re-selected output
will continue after the output that has already been put out.
Additionally when SELECT OUTPUT is called a newline character is output
on the current output stream if there is anything in the line buffer,
before selecting the new stream.
CHARACTER INPUT ROUTINES
The following routines and functions operate on the currently selected
input stream.
%ROUTINE READSYMBOL(%NAME I)
This routine is used to transfer the
internal value of the next symbol from the current input stream into an
%INTEGER, %SHORTINTEGER or %BYTEINTEGER variable.
Example: READSYMBOL (IN)
%INTEGERFN NEXTSYMBOL
This integer function which takes no parameter,
returns the internal value of the next symbol on the current input
stream. It does not move the pointer to the stream so the next call of
this or any other character input routine will access the same
character again.
Example: %IF NEXTSYMBOL='A' %THEN ......
%ROUTINE SKIPSYMBOL
This routine, which takes no parameter, moves the
pointer to the current input stream along one symbol without
transferring any information to store. In the following example
SKIPSYMBOL and NEXTSYMBOL are used together to skip over a series of
space characters.
%WHILE NEXTSYMBOL=' ' %THEN SKIPSYMBOL
%ROUTINE READ(%NAME I)
This routine is used to read numeric data into
arithmetic variables. The single parameter should be a variable of type
%INTEGER, %SHORTINTEGER or %BYTEINTEGER if the number being read is
known to be integral or of type %REAL or %LONGREAL if the number being
read is likely to include a fractional part. The numbers being read
should be written as described under the heading 'DECIMAL CONSTANTS',
in Section 1. Note the following points:
1. READ will skip over any SPACE or NEWLINE characters which precede
the number. Thus space or newline characters can readily be used as
separators between numbers.
2. On returning from READ the input pointer will be left pointing to
the character immediately following the number.
3. The fault 'REAL INSTEAD OF INTEGER IN DATA' will occur if an
attempt is made to read a real number, or a number with an
exponent, into an integer variable.
4. The fault 'SYMBOL IN DATA' will occur if the first character of a
number is neither a sign, a decimal point or a decimal digit.
%ROUTINE READSTRING(%STRINGNAME S)
This routine, which is described in
Section 8 is used to read a value into a %STRING variable.
%ROUTINE ISOCARD(%BYTEINTEGERARRAYNAME B)
This routine, which is
intended for use with fixed format data, is used to read a card image
into a %BYTEINTEGERARRAY. The parameter should be the name of the
array, and the card image will be read into elements 1-80 of it.
Example: %BYTEINTEGERARRAY INCARD(1:80)
ISO CARD (INCARD)
LINE RECONSTRUCTION
All the above routines except ISOCARD operate on data which has
undergone a process known as line reconstruction. The main features of
this are:
1. All characters before the left hand margin and after the right hand
margin are suppressed. (See SET MARGINS below).
2. All space characters at the right hand end of the line are
suppressed.
3. Double quote deletion is performed - that is each double quote ("")
character and the character preceeding it is suppressed, as far
back as the beginning of the line.
4. All marked characters (see Section 16) are suppressed.
5. All illegal characters are translated to SUB (decimal value 26). In
addition, when an attempt is made to read the first character of a
line containing a SUB character the fault 'SUBSTITUTE CHARACTER IN
DATA' occurs. This fault may be trapped (See FAULT TRAPPING) in
which case the next attempt to read the first character of the line
will be successful although the user must be prepared for it, or at
least one character in the line, to be a SUB.
AVOIDING LINE RECONSTRUCTION
It is occasionally useful to be able to read all characters from the
input stream before line reconstruction has been performed. The routine
READCH is provided for this purpose.
%ROUTINE READCH(%NAME I)
This routine, like READSYMBOL requires one
parameter which must be a variable of type %INTEGER, %SHORTINTEGER or
%BYTEINTEGER. A call of READCH will transfer the next character from
the input stream to store in internal code, without regard for Margin
Settings, double quote deletion, trailing space, or Marked Character
suppression or illegal character conversion.
INPUT ENDED
All of the above input routines cause the fault 'INPUT ENDED' if an
attempt is made to read beyond the end of a file. This fault can be
trapped (See FAULT TRAPPING).
CHARACTER OUTPUT ROUTINES
A number of routines are provided to write individual characters or
sequences of characters to the output stream. Although most routines
only output part of a line it is important to appreciate that the
characters are initially put in a line buffer which is only output on
the file or device when a NEWLINE or NEWPAGE character is output. This
fact is particularly relevant when using a TELETYPE or other terminal
as an output device. The basic character output routine is PRINTSYMBOL;
most of the other output routines operate via this routine.
%ROUTINE PRINTSYMBOL(%INTEGER I) This routine takes one parameter which
should be an integer expression. The expression is evaluated and the
least significant 7 bits only are used by the routine. If the value of
this corresponds to a symbol in the IMP extended character set (see
Section 16) it is sent to the output stream. If not, the character SUB
(decimal 26) is sent.
Examples: PRINTSYMBOL ('A')
PRINTSYMBOL (I+J+32)
TEXT OUTPUT ROUTINES
The following routines are provided to simplify the output of text:
SPACE - no parameter - outputs one space
SPACES(n) - where n is an integer expression - outputs n spaces
NEWLINE - no parameter - outputs one newline character
NEWLINES(n) - where n is an integer expression - outputs n spaces
PRINTSTRING(s) - where s is a string expression - outputs the string.
See Section 8.
%PRINTTEXT'TEXT' - This is not a routine call, it is a built in phrase
known to the compiler. Any characters may be included
in the quotes following %PRINTTEXT. Note that all
characters included within the quotes will be printed
including spaces and newlines. Note that the routine
PRINTSTRING has a similar effect and is a preferred
alternative to %PRINTTEXT. However since a PRINTSTRING
is a routine its parameter must be contained within
brackets. Hence, for example the two following lines
would have the same effect:
PRINTSTRING('MY PROGRAM')
%PRINTTEXT'MY PROGRAM'
OUTPUT OF NUMBERS
Three routines are provided for the output of numeric information.
WRITE is used to output the value of integer expressions, PRINT and
PRINTFL are used to output the value of real expressions, the latter in
floating point form.
%ROUTINE WRITE(%INTEGER I,J)
This routine takes two parameters, both
should be integer expressions. The first is the value to be output, the
second is the number of positions to be used. To simplify the alignment
of positive and negative integers an additional position is allowed by
the routine for a sign, which is only printed for negative numbers. If
the value being output is too large for the number of positions
specified more positions are taken.
Examples: WRITE(I,4)
WRITE(TOTAL+SUM+ROW(I),6)
WRITE(SNAP,POS+4)
%ROUTINE PRINT(%LONGREAL X,%INTEGER I,J)
This routine takes three
parameters. The first should be the real expression whose value is to
be printed, the second and third should be integer expressions
specifying the number of places to be allowed before and after the
decimal point. The same arrangements apply for the sign and for
insufficient space for the integer part as for WRITE. If necessary the
fractional part will be rounded.
Examples: PRINT(A,2,3) PRINT(COS(A-B),1,10)
%ROUTINE PRINTFL(%LONGREAL X,%INTEGER I)
This routine takes two
parameters; the first is a real expression whose value is to be
printed, the second is an integer expression specifying the number of
digits to be printed after the decimal point. The printed number takes
up the specified number of places plus 7 additional places.
Example: PRINTFL(X,4)
If X has the value 17.63584 this would be printed as 1.7636@ 1. The
number is standardised in the range 1<=x<10, and as for WRITE a space
is allowed for a sign for both the mantissa and the exponent.
PRINTING NON-STANDARD CHARACTERS
Occasionally it is useful to print characters that do not appear in the
extended IMP character set. The routine PRINCH has the same effect as
PRINTSYMBOL except that any character whose internal code value is in
the range 0-127 can be output.
OUTPUT EXCEEDED
If an attempt is made to output more data than can be accommodated on
the current output stream then the fault 'OUTPUT EXCEEDED' will occur.
This cannot be trapped.
CLOSING STREAMS
All input and output streams are closed automatically at the end of a
job. If it is necessary to close a stream during a job the routine
CLOSE STREAM can be used. It takes one parameter which should be an
integer expression whose value is the number of the stream to be
closed. Note the following points.
1. An attempt to close the currently selected input or output stream
will fail.
2. If a stream is closed and selected later using SELECTINPUT the
pointer to the stream will be positioned at the start of the file.
This makes it possible to re-read a file, or to read a file which
has been written earlier in the program.
3. If a stream is closed and selected later for output, the output
will be written from the start of the file. Any other output in the
file will be lost.
SET MARGINS
Associated with each input and output stream are settings for the left
hand and right hand margins. Some of these settings are defined by the
IMP system and this information will be found in the relevant User
Manual. All other streams use default settings of 1 and 80. Margin
settings can be altered by a call of the routine SET MARGINS. This
routine takes three parameters, all being integer expressions. The
first is the stream number, in the range 1 - 80, which must be that of
either the currently selected output stream or the currently selected
input stream. The second and third should be the left hand margin
setting and right hand margin setting required.
For input streams the margins must be in the following range:
1<=LHM<=RHM<=160
The characters on a line to the left of the left hand margin and those
to the right of the right hand margin will be ignored.
For output streams the margins must be in the following range:
1<=LHM<=RHM<=132
The effect of altering the left hand margin will be to tabulate the
output, for example if the left hand margin is set to 10 all output
lines will be preceded by 9 spaces. The right hand margin is used to
limit printing on a line. If an attempt is made to print beyond the
right hand margin then a newline character is inserted and printing
continues on the next line.
If a stream is reselected its margins should be set again using SET
MARGINS.
BINARY FILES
Binary files can be used for storing intermediate results of
computations, either during the execution of one program, or for use by
subsequent programs. The data stored is a direct copy of the contents
of the core store. The file handling routine calls all make explicit
references to the logical channel being used, there is no equivalent to
the currently selected stream used for character I/O. The variables
accessed by binary I/O calls are normally held in arrays and the read
and write routines each require a specification of the area of core
store to be accessed. For example the WRITESQ routine uses its second
and third parameters to specify the area of the store to be output.
Example: %INTEGERARRAY IN(1:1000)
WRITESQ(CHAN,IN(1),IN(500))
In this example the first 500 elements of the array IN will be written
out to the sequential file defined for channel CHAN.
The following notes refer to all the binary file handling routines.
1. Each routine call should reference only one array.
2. The type of an array used in a call of a binary input routine
should be the same as that used for the call of binary output
routine that created the file.
3. When using multi-dimensional arrays the whole array should be
written and read, unless the full implications of the layout in
store of the array are understood.
SEQUENTIAL BINARY FILES
Sequential binary files (SQFILES) are accessed by the routines OPENSQ,
WRITESQ, READSQ and CLOSESQ. All these routines are in the explicit
category, that is they must be declared at the head of the program or
routine in which they are used. The specifications of the routines are
given below. The precise characteristics of the file handling routines
may vary from one implementation to another, and further information
should be sought from the User Manual for the appropriate computer.
%EXTERNALROUTINESPEC OPENSQ(%INTEGER I)
This routine takes one
parameter, the channel number of the file to be opened. It must be
called before READSQ or WRITESQ is called for that channel. If a file
is closed in a program and then re-opened it will be reset to the
start. By this means it can be reread or information that had been
written earlier in the program can be read. In the case of writing
after re-opening, since the file is positioned at the start all
information in it will be lost.
%EXTERNALROUTINESPEC CLOSESQ(%INTEGER I)
All files are closed
automatically at the end of a job. CLOSESQ is only required if it is
necessary to re-open a file.
%EXTERNALROUTINESPEC WRITESQ(%INTEGER I,%NAME A,B)
Each call of the
WRITESQ outputs one logical record. The operating system may store
records in a variety of ways on its storage device but this need not
concern the programmer. The routine takes three parameters; the channel
number and two %NAME parameters to define the area to be written out
(see above).
Example: WRITESQ(2,A(27),A(426))
%EXTERNALROUTINESPEC READSQ(%INTEGER I,%NAME A,B)
This routine reads in
one record, normally written out by a call of WRITESQ. The first
parameter defines the channel to be used and the second and third the
area of store into which the record is to be read.
Example: READSQ(2,A(1),A(400))
%EXTERNALINTEGERFNSPEC LENGTHSQ
This function returns as its result the
length, in bytes of the last record read by a call of READSQ. It is
useful in situations where the length of records vary. Note that the
length is that of the user data read into the program variables. It
does not include any system information which is sometimes appended to
the record.
SEQUENTIAL FILE FAULTS
The fault 'INPUT ENDED' will occur if an attempt is made to read beyond
the end of a file. This fault can be trapped. None of the following
faults resulting from use of sequential file handling can be trapped.
1. Attempting to use READSQ, WRITESQ or CLOSESQ for a file which is
not open.
2. Attempting to OPEN a file which is already open.
3. Attempting to write or read an area such that the address of the
first element is higher than that of the last element, for example:
WRITESQ(1,IN(100),IN(1))
4. Attempting to mix READSQ and WRITESQ calls for the same channel,
without the use of an intermediate CLOSESQ and OPENSQ.
DIRECT ACCESS BINARY FILES
Direct Access Files (DAFILES) are used for similar purposes to SQFILES.
There are two main differences in the method of use.
1. Records can be accessed in a random order.
2. Calls of both WRITEDA and READDa are legitimate on an open channel.
All the DAFILE routines are in the explicit category, that is they must
be declared before they are used. The specifications of the routines
are given below. Each record of a DAFILE contains a maximum of 1024
bytes. Records are referenced by their position in the file, starting
at 1.
%EXTERNALROUTINESPEC OPENDA(%INTEGER I)
This routine takes one
parameter, the channel number of the file being opened. It must be
called before a call of READDa or WRITEDa for the file. When OPENDA is
used for the first time with a particular file it initialises the file
by writing the unassigned pattern to all the records. Thus, if an
attempt is made to read from a record to which nothing has been written
an 'UNASSIGNED VARIABLE' failure will occur when the data which has
been read is accessed.
%EXTERNALROUTINESPEC CLOSEDA(%INTEGER I)
All DAFILEs are closed
automatically at the end of a job so this routine is rarely needed. It
may be required to minimise the number of files which are concurrently
open.
%EXTERNALROUTINESPEC WRITEDA(%INTEGER I,%INTEGERNAME J,%NAME A,B)
This
routine is used to write data from an area of core store to a file. A
call of WRITEDA will result in one or more records being written,
depending on the number of bytes in the area defined. For example if
256 elements of an %INTEGER array are written out then only one record
will be used, whereas if 1024 %INTEGERs are written four records will
be used. If the area written is not an exact multiple of 1024 bytes
then the end of the last record written will be filled with rubbish.
The first parameter is an integer expression which defines the channel
number, the second is the name of a %INTEGER variable. On entry this
should contain the number of the first record to be written. On exit it
will contain the number of the last record written by this call, which
may be used for checking purposes. The third and fourth parameters
define the area of store to be written, as for SQFILES.
%EXTERNALROUTINESPEC READDA(%INTEGER I,%INTEGERNAME J,%NAME A,B)
This
routine is used to read data written by WRITEDA. The parameters are
used in the same way and if an attempt is made to read into an area
which is not an exact multiple of 1024 bytes, the area is filled and
the rest of the last record is ignored.
DIRECT ACCESS FILE FAULTS
None of the following faults associated with the use of DAFILES can be
trapped:
1. Attempting to use READDA or WRITEDA before opening a file.
2. Attempting to access a record with a number that is less than 1 or
greater than the number of the last record in the file.
3. Attempting to access an area such that the address of the first
element is higher than that of the last.
SECTION 11 - AIDS TO PROGRAM DEVELOPMENT
INTRODUCTION
The IMP compilers normally operate in diagnostic mode. This means that
when compiling a source program, additional code is planted to enable
the program to give useful diagnostics in the event of an error
occurring at run time. The type of checks which are made are listed
below, under their standard compiler options. The User Manual for the
computer being used will provide information about selecting suitable
compiler options.
CHECK (Unassigned checking)
Checks are made that all variables, except byte and short integers, are
assigned to, before being used. Parameters passed to routines by value
are checked at time of passing but those passed by name are not checked
at all at present. Unassigned checking can be suppressed by use of the
compile time option 'NOCHECK'.
ARRAY (Array bound checking)
Checks are made to ensure that the declared bounds of arrays are not
exceeded. Checks are also made to prevent either too large an entity
being assigned to a byte or short integer variable, or too many
characters being assigned to a string variable. Additionaly checks are
made for attempts to jump to %SWITCH labels that are not set, or are
outside the bounds declared for the %SWITCH. These checks can be
suppressed by using the compile time option 'NOARRAY'. Note that the
current release of the IMP compiler suppresses array bound checking on
all arrays when 'NOARRAY' is used. This was not the case with earlier
releases.
TRACE (Routine traceback)
Code is planted to allow a routine trace back to be given. This
facility can be suppressed by 'NOTRACE'.
DIAG (Line number updating and local variable values)
Code is planted to save the line numbers of IMP statements and thereby
link any diagnostics to a specific line of IMP code. Code is also
planted to enable the local scalar variables to be printed during a
routine traceback, unless 'NOTRACE' has been selected. These
diagnostics can be suppressed by use of 'NODIAG'.
Should a program fail, the diagnostics package is entered after the
cause of the failure has been reported. It is also entered on execution
of the instructions, %MONITOR and %MONITORSTOP. The function of the
diagnostics package is as follows:
1. To identify (subject to TRACE being operative) the logical block
i.e. routine, function, map or block in which the failure occurred
by printing out its name, in the case of a routine, function or
map, and the number of its first line if in a block. For example:
ROUTINE/FN/MAP FRED STARTING AT LINE 31
BLOCK STARTING AT LINE 6
2. To print out (subject to DIAG being operative) the values at the
time of failure of all the scalar variables (up to a maximum of
100) declared in the logical block. If no value has been assigned
to a variable, this is indicated. Records and arrays are not
printed.
LOCAL SCALAR VARIABLES
J= 10
TABLEOFC= 4001
SHOLD='THIS IS'
K= NOT ASSIGNED
Note that the names of scalar variables are truncated at eight symbols,
and that string values are enclosed in quotes.
3. If the logical block is a routine, function or map, to print out
the number of the line from which it was called. This may be in the
current routine, function or map if the call was recursive.
4. To repeat the above three functions for the logical block from
which the previous logical block was entered. Thus routines,
functions or maps, which are used recursively, will have the values
assigned to the variables in each occurrence printed out.
There is one overall restriction on the amount of diagnostics given.
After 400 lines of diagnostics the output is terminated and the message
DIAGS OUTPUT EXCEEDED
is given.
Certain source statements which are indicated below may also be
included in a program under development to provide further information
for de-bugging purposes.
PROGRAM LISTING
A line by line transcript of all statements in an IMP program is
automatically given for each compilation unless the compiler option
'NOLIST' has been specified in the job control when a program is
compiled. Then a short listing in which only the start and finish of
each 'begin', 'routine', 'function' or 'map' block is produced.
Selective listing of statements in particular sections of a program may
be obtained by enclosing each required section between the statements
%LIST and %ENDOFLIST and giving the compiler option 'NOLIST' in the job
control or command language. Note that apart from saving paper the
'NOLIST' option will result in faster compilation, and hence should be
used unless a full listing is really required.
EFFICIENCY
The following suggestions are given to enable a programmer to program
in a way which will make more efficient use of machine time.
1. The parts of a program in which efficiency is particularly
important are those which are executed many times.
%CYCLE I=1,1,100
%CYCLE J=1,1,100
%REPEAT
%REPEAT
In the above example, any minor improvement made in the code in the
inner cycle will result in a total saving in time of 10,000 times that
small amount.
2. Whenever some part of an expression which is a constant factor, is
required many times, it should be evaluated once and stored as
shown in the right hand version of the example below.
K=K*22/7
%CYCLE I=1,1,100 %CYCLE I=1,1,100
A(I)=A(I)*K*22/7 A(I)=A(I)*K
%REPEAT %REPEAT
3. It takes longer to move numbers in and out of array elements than
to access simple variables. The right hand version of the example
given below is the more efficient.
A(I,J)=0 X=0
%CYCLE K=1,1,15 %CYCLE K=1,1,15
A(I,J)=A(I,J)+B(K) X=X+B(K)
%REPEAT %REPEAT
A(I,J)=X
4. Integer to real conversion is costly and it is often worthwhile to
use brackets to separate out integer sub-expressions, as shown
below on the right.
%REAL X %REAL X
%INTEGER I,J,K %INTEGER I,J,K
X=X+I+J-K X=X+(I+J-K)
5. If an arithmetic expression contains a mixture of real and long
real variables then it is evaluated double length. It is slow to
stretch real variables to long real variables and brackets can
often be used to minimise the cost of conversion, as shown below on
the right.
%REAL X,Y,Z %LONGREAL A,P
P=X*A/COS(Z)*Y/Z
%REAL X,Y,Z %LONGREAL A,P
P=(X*Y/Z)*A/COS(Z)
It is particularly important to note this effect when making a call on
library routines such as SIN, COS etc., which are all double length,
from a program having mostly single length real variables.
6. When array bound checking has been suppressed, array suffices of
the form (I+constant) are more efficient than (I-constant). The
example given below left may be reprogrammed more efficiently as
shown on the right.
%CYCLE I=1,1,N B(I)=X+C(I-2)*C(I-3) %REPEAT
%CYCLE I=-1,1,N-2 B(I+3)=X+C(I+2)*C(I) %REPEAT
7. Output should be reduced to the minimum which is really useful to
the programmer in the interest of saving machine time and money. To
this same end, answers should be printed across the line printer
page where possible as the cost is proportional to the number of
lines printed.
8. Once a program has been thoroughly tested, its efficiency can be
greatly increased by turning off certain or all of the diagnostic
checks made by the compiler. This results in a great saving in
space as well as time. All programs which are past the initial
testing stage should be compiled without the unassigned checking
option. As more production experience with the program is obtained
it may be possible to compile without some of the other options,
array bound checking for example. Programs should be made as
efficient as possible by other means, however, before removing any
of the checks.
9. There is a compile time option 'OPT' which has the effect of
switching off array bound checking, unassigned checking and
diagnostics for line numbers and values of local variables.
Additionally some optimisation of the program is carried out and
other checking is suppressed. Although the result is a program that
executes more efficiently this facility should be used with
caution. It should not be used on programs which have Compile Time
Faults since the error messages that are produced may be
misleading. Further it should only be used for programs or
%EXTERNAL routines which have been thoroughly tested. Much time may
be wasted trying to diagnose faults which result from the use of
'OPT' with incorrect programs.
SECTION 12 - COMPILE TIME FAULTS
INTRODUCTION
As the compiler processes a source program and produces a map or
listing, it may encounter errors in the syntax or the semantics of
certain statements. If this occurs, the compiler issues a message to
describe the situation of the error and as far as possible, its nature.
Two main types of error are defined; syntactic errors and semantic
errors.
SYNTACTIC ERRORS
These are errors which cause the form of the statement to be
unrecognisable, since the strict rules of syntax have not been obeyed.
Mistakes such as omission of statement separators or misspelling of key
words are examples. This type of error is indicated by the message
* 111 SYNTAX
where 111 is the line number of the incorrect statement. A copy of the
offending source statement is output on the next line of the program
map or listing.
Where possible, the compiler indicates the exact position of the SYNTAX
error by outputting a marker (!) under the character where the analysis
failed. Sometimes, however, this marker can only be approximate as, for
example, in the following case:
If the statement %ROUTINE SPECIFY ORBITALS is mistyped as
%ROUTINESPECIFY ORBITALS the failure message would be
* 111 SYNTAX ROUTINESPECIFY ORBITALS !
The marker is misplaced to the right as the erroneous line more nearly
corresponds to a '%ROUTINESPEC' statement than the intended '%ROUTINE'
statement.
The compiler will continue to process the remainder of a program after
detecting such an error, but will not allow the program to be executed.
SEMANTIC ERRORS
These occur when a statement is syntactically correct, but causes
ambiguity in meaning or is totally meaningless. Examples are the
declaration of a name for two uses in the same context, or the use of a
name which has not been declared at all.
The following list describes the semantic errors detected by the
compiler and diagnosed by messages of the type
* 125 FAULT n
where 125 is the number of the faulty line and n the number of the
fault. The fault number will be followed by an abbreviated description
of the fault which will usually be sufficient for the programmer to
identify his mistake. Fuller descriptions of current Compile time
faults are given below. If a program produces any fault not listed
below then the user should contact the Advisory Service for further
information. All will cause rejection of the offending program at the
end of compilation.
FAULT 1 (Too Many %REPEATS)
A %REPEAT instruction is encountered for which no %CYCLE statement
earlier in the same block can be matched uniquely.
FAULT 2 (Label Set Twice)
The current instruction bears a label which has already been used to
identify a statement in the same block. This will clearly cause
ambiguity. Also occurs if a numeric label is not within the permitted
range of 1<=label<=16383.
FAULT 3 (%SPEC Faulty)
The offending statement is a %SPEC in the short form, within a routine,
function or map, which specified a name not appearing in the formal
parameter list of the current block, or which appears in a %BEGIN block
context.
FAULT 4 (%SWITCH Vector Not Declared)
A name used in the context of a switch label has not been declared as a
%SWITCH name in the current block or routine.
FAULT 5 (%SWITCH Label Error)
The subscript appended to the name used as a %SWITCH label is not a
single integer constant or is outside the range defined by the
declaration of the switch. (See also FAULT 18).
FAULT 6 (Switch Label Set Twice)
The current instruction is identified by a switch label which has
already been used to label a statement in the same block.
Fault 7 (Name Set Twice)
A declaration statement declares 'name' which is already set in the
current block, except when the name is that of a %ROUTINE, %FN or %MAP
description which has been previously specified but not described
within that block.
If the statement declared a number of names, any of these not already
set is set in the normal fashion. The diagnostic will appear once for
each name which is already set.
FAULT 8 (Too Many Parameters in Routine Type Description)
A routine type description is encountered for which a declaration
already exists, and the number of parameters declared in the
description exceeds that in the declaration.
FAULT 9 (Parameter Fault in Routine Type Description)
The type of a formal parameter name appearing in a routine type
description differs from the corresponding parameter appearing in an
earlier declaration.
FAULT 10 (Too Few Parameters in Routine Type Description)
A routine type description is found to declare fewer parameters than
the corresponding specification.
FAULT 11 (Label Not Set)
On encountering an %END statement, it is found that the label, , has
been referenced in a jump instruction in the current block, but has not
been identified with any statement in that block. This message appears,
therefore, immediately before the 'END OF BLOCK' message. Note that
%ROUTINE, %FN or %MAP descriptions are treated as separate blocks. (On
'END OF PROGRAM' this also refers to labels appearing in %FAULT
statements that are unset).
FAULT 12 (Type General Parameter Misused)
An attempt has been made to store or fetch into a type general
parameter (e.g. %NAME). These are only used by the input/output
routines and this fault should not normally be encountered.
FAULT 13 (%REPEAT Missing)
This diagnostic appears at the end of a block, and indicates that a
%CYCLE has been opened in that block but has not been matched uniquely
with a %REPEAT instruction in the same block.
FAULT 14 (Too Many %ENDS)
An %END statement is encountered which matches logically with the
opening %BEGIN of the program. It should rightfully be an
%ENDOFPROGRAM. Compilation ceases and the job terminates. Any
subsequent text is not scanned.
FAULT 15 (Too Few %ENDs)
An %ENDOFPROGRAM statement is found to correspond to the opening of a
block internal to the main program level, showing a lack of block ends.
FAULT 16 (Name Not Set)
A name employed in the offending instruction has not been declared. The
name quoted is artificially declared as an %INTEGER so that this
diagnostic is suppressed on later appearances of the name. However,
other faults may occur later if the 'name' is used subsequently, in any
other context e.g. as a %REAL name which will cause FAULT 24.
FAULT 17 (Not a %ROUTINE Name)
A statement having the form of a routine call is encountered. The name
quoted in this statement is that of an item declared as something other
than a routine. (FAULT 16 will indicate the case where the name has not
been declared at all).
FAULT 18 (%SWITCH Vector Error)
In a %SWITCH declaration, the upper or lower subscript bound quoted for
any switch named is outside the range -32767 to +32767. Both bounds are
set to zero. The offending switchname(s) will be valid in the present
block, but any reference may generate a diagnostic. (See FAULT 5).
FAULT 19 (Wrong Number of Parameters or Subscripts)
A reference to the name of an array is made, but the number of
subscripts appended to it does not agree with the dimensionality
declared for that array.
This diagnostic also occurs when the number of actual parameters
attributed to a routine call is not equal to the declared complement of
formal parameters.
FAULT 20 (%SWITCH Vector or %RECORDFORMAT name in Expression)
A name appearing in an arithmetic expression has been found to identify
a %SWITCH in which circumstances it is patently illegal. Also occurs if
a %RECORDFORMAT name is found in an expression.
FAULT 21 (Routine Type or %RECORD Name Not Yet Specified)
A %ROUTINE, %FN or %MAP named as a formal parameter of another routine
type block is referenced in that block before the parameter has been
specified (by a %SPEC statement). Hence its own parameter list is
unknown. Also occurs if a %RECORDNAME variable is used before being
specified.
FAULT 22 (Actual Parameter Fault)
In a reference to a routine type name, an actual parameter is of
incorrect type as defined in the declaration of that routine.
FAULT 23 (%ROUTINE Name in Expression)
A name appearing in an arithmetic expression has been found to identify
a %ROUTINE, in which circumstances it is patently illegal.
FAULT 24 (Real Quantity in Integer Expression)
In any expression assigned to an %INTEGER variable or otherwise
expected to have an %INTEGER value, a %REAL constant, variable or
function name has been employed illegally. If the expression occurs in
an array declaration, as a dimension bound, the array name remains set.
Also occurs if a logical operator is found in a real expression.
FAULT 25 (%CYCLE Variable Not Integer Type)
The control variable named on the left-hand side of a %CYCLE assignment
is not an %INTEGER variable. N.B. %BYTEINTEGER and %SHORTINTEGER
variables are not permitted as control variables.
FAULT 26 (Fault Statement Not at Basic Textual Level)
The %FAULT statement is allowable only in the outermost block of the
program, and must refer to labels existing in that block only.
Appearance of a %FAULT statement in any internal block will result in
this message.
FAULT 28 (%ROUTINE Body Not Described)
Occurs at the end of a block when a specification appears in that block
for a routine type name which is not described, whether referred to or
not. The name given is that quoted in the offending %ROUTINESPEC.
FAULT 29 (LHS Not a Destination or Name is Not an Address)
In an assignment statement, the name appearing on the left-hand side of
the assignment is not a variable name.
FAULT 30 (%RETURN Out of Context)
A %RETURN statement occurs in a block other than a %ROUTINE in which
circumstances it is meaningless.
FAULT 31 (Result Out of Context)
A %RESULT statement occurs in a block other than a %FN or %MAP body in
which circumstances it is meaningless.
FAULT 34 (Textual Level > 8)
This occurs immediately after the opening statement of a new begin
block or routine type description which causes nesting of blocks to 8
levels (the main program being at level 1, allowing for the compiler
level). The compiler is unable to monitor this depth of nesting during
execution, and hence subsequent object code produced is lost. However,
the compiler contrives to scan subsequent text in the normal way for
further syntactic or semantic errors.
FAULT 35 (Routine Level > 5)
The routine level (initially one) is increased every time a %ROUTINE
%FN and %MAP statement is encountered and decreased when the
corresponding %END is found. Insufficient addressing registers are
available on Systems 4 and 370 to allow more than five routine levels.
The compiler will continue to check subsequent text for errors.
FAULT 36 (Attempt to Trap an Untrappable Fault)
This diagnostic occurs if an untrappable fault number appears in a
%FAULT statement.
FAULT 37 (Array Has Too Many Dimensions)
In this implementation, arrays are restricted to a maximum of seven
dimensions.
FAULT 38 (Overflow)
Overflow has occurred while compiling the statement. This is caused by
using a constant that is too large for the type of variable involved.
FAULT 39 (Real Quantity as Exponent)
A %REAL constant, variable or parenthesised expression appears
immediately to the right of an exponentiation symbol, in which position
it is illegal. This diagnostic replaces the diagnostic 'FAULT 24' in
these circumstances.
FAULT 40 (Declarations Misplaced)
Declarations must be placed at the head of the block in which they
occur. In particular they must come before any labels, %FAULT
statements, jumps, conditional statements or cycles in the same block.
FAULT 42 (%STRING Variable in Arithmetic Expression)
In any expression deemed by context to be arithmetic, a %STRING
variable or the concatenation operator ,(.), has been found.
FAULT 43 (Bound pair inside out)
In a declaration, a bound pair consisting of two constants has the
lower bound greater than the upper bound. Both bounds are set to the
lower bound and the declaration is accepted, in order to reduce the
number of subsequent error messages.
FAULT 44 (Const Error)
A constant of incorrect type has been used to initialise an %OWN
variable. May be a %REAL constant for an %INTEGER variable or too large
a constant for the variable.
FAULT 45 (%OWN Array Error)
An own array has been declared where the number of constants does not
correspond with the bounds.
FAULT 46 (%EXTRINSICS)
An attempt has been made to initialise an %EXTRINSIC variable.
Extrinsic variables exist in a separately compiled module and thus
cannot be initialised.
FAULT 47 (Dangling %ELSE)
An %ELSE has been found after a %FINISH which is not associated with a
condition.
FAULT 48 (Substitute Character in Program)
The substitute character has been found in a line of program which is
listed. No attempt is made to analyse the offending line as this would
merely result in a SYNTAX fault.
FAULT 51 (Spurious %FINISH)
A %FINISH has been found for which no %START exists.
FAULT 52 (Missing %REPEAT Inside %START/FINISH)
This diagnostic occurs at a %FINISH and indicates that a %CYCLE has
been started within a %START- %FINISH block but the corresponding
%REPEAT has not been found.
FAULT 53 (%FINISH Missing)
Within a block or routine there exist more %START statements than
%FINISH statements.
FAULT 54 (%EXIT out of context)
An %EXIT statement has been found which is not within a %CYCLE-%REPEAT
context.
FAULT 55 (%EXTERNALROUTINE in Program)
An %EXTERNALROUTINE has been found in a program. %EXTERNALROUTINES are
only allowed in library files (see Section 6).
FAULT 56 (%ENDOFFILE Out of Context)
An %ENDOFFILE statement has been found in a program. %ENDOFFILE is only
allowed when compiling library files. This fault also occurs if
%ENDOFPROGRAM occurs when compiling a library file (see Section 6).
FAULT 57 (Level 0 Used)
Statements have been found at level 0. The first %BEGIN has probably
been omitted. When compiling library routines, %OWN, %CONST, %EXTERNAL
and %EXTRINSIC variables may be declared at level 0 and used to
communicate between routines.
FAULT 62 (Wrong Format)
An attempt has been made to declare an entity of type %RECORD by
reference to a name which is not currently declared as a %RECORDFORMAT.
FAULT 63 (%RECORDSPEC in Error)
An attempt has been made to assign a format to an entity not of type
%RECORD or to a %RECORD whose format is already known.
FAULT 64 (Subname Omitted)
A reference to a %RECORD element does not specify a subname.
FAULT 65 (Wrong Subname)
The indicated subname cannot be found in the %RECORDFORMAT statement
referenced by the %RECORD declaration.
FAULT 66 (Record assignment)
An attempt to assign one record to another cannot be compiled as the
records are of different sizes.
FAULT 69 (Subname Out of Context)
A subname has been attached to an entity which is not of type %RECORD.
FAULT 70 (Invalid Length in String Declaration)
The maximum length of the string being declared has either been omitted
or lies outside the range 1 to 255.
FAULT 71 (String Expression Contains a Variable)
A variable of type other than %STRING has been found in a string
expression.
FAULT 72 (String Expression Contains Invalid Operator)
An operator other than '.' has been found in a string expression.
FAULT 73 (Resolution Comparator Out of Context)
The resolution comparator, ->, has been used with a variable which is
not a string or else in a double sided condition.
FAULT 74 (Resolution Format Incorrect)
The bracket expression is not correct. This is usually caused by the
omission of the brackets themselves.
FAULT 75 (String Expression Contains Subexpression)
Bracketed subexpressions are neither required nor permitted in string
expressions. Brackets may only occur in string expressions as described
under resolution, (see Section 8).
FAULT 81 (Item == )
The address assignment operation '==' has been used to equivalence a
variable to an expression, which is patently absurd.
FAULT 82 (Not an Address)
The address assignment operator has been used to assign an address to a
variable that is not of %NAME type.
FAULT 83 (Non Equivalence)
The '==' operator has been used to equivalence operands that are not of
identical type.
FAULT 84 (RECORD Misused)
The special mapping function RECORD has been misused.
FAULT 98 (Addressability)
The program or one of its data areas exceeds the limit of
addressability (at present 1/4 megabyte).
CATASTROPHIC COMPILE TIME FAULTS
Some errors which exceed the physical limits imposed on the compiler by
its particular operating environment are catastrophic and result in
compilation ceasing at the point the error occurred. These faults have
numbers greater than 100.
FAULT 101 (Source Line Too Long)
The line of source text to be analysed is larger than the input buffer
(currently 300 characters). The statement should be broken down into
several simpler statements.
FAULT 102 (Long Analysis Record)
The current statement requires too many compiler recursions in its
analysis. The statement should be broken down into several simpler
statements.
FAULT 103 (Dictionary Overflow)
FAULT 104 (Too Many Names)
Too many or too long names are currently declared. The remedy is either
1. To use the block structure so that names are undeclared when not
required. or
2. Use shorter names and replace name labels by integer labels.
FAULT 105 (Too Many Levels)
Textual level 10 has been reached.
FAULT 106 (String Constant > 255 Symbols)
This fault will occur if a string constant contains more than 255
symbols. Note that the text in a %PRINTTEXT statement is treated as a
string constant.
FAULT 107 (ASL Empty)
The compiler tables are full - this is unlikely to occur and the User
should contact the Advisory Service.
FAULT 108 (End Message Character in Program)
The end message character was found in the IMP program. This could be
caused by the omission of the %ENDOFPROGRAM statement.
Faults greater than 200 indicate compiler errors which should be
reported to the Advisory Service.
SECTION 13 - RUN TIME FAULTS
INTRODUCTION
Various faults can occur during the execution of an IMP program. Some
of these are described in the relevant sections of the manual, they are
all described below. Some Run Time faults can be trapped. (See Section
14).
TRAPPABLE FAULTS
INTEGER OVERFLOW
REAL OVERFLOW
On the evaluation of an expression a number has been generated which is
too large to be contained in a register of the appropriate type.
INVALID %CYCLE
A %CYCLE instruction has been executed where it is impossible to reach
the final value of the control variable.
NOT ENOUGH STORE
On executing a declaration, insufficient space is available in the
store to accommodate the variables requested.
SQRT NEGATIVE
LOG NEGATIVE
A negative argument has been passed to the appropriate routine.
%SWITCH VARIABLE NOT SET
An instruction of the form -> SW() has been executed and the required
label cannot be found.
INPUT FILE ENDED
The current file of input data has been exhausted.
NON-INTEGER QUOTIENT
A quotient of two %INTEGER quantities when evaluated in an integer
context is found to have a non-integral value.
%RESULT NOT SPECIFIED
An attempt has been made to exit from a %FN or %MAP via the %END
instruction. Control can only be returned from these blocks via a
%RESULT= statement.
SYMBOL IN DATA S
In executing a read instruction, the non-numeric symbol S has been
found.
REAL INSTEAD OF INTEGER IN DATA
A real value has been found on execution of a read instruction which
expects an %INTEGER value. This will also occur if an integer of
modulus >(2**31-1) is read, or if an exponent is given which is not an
integer.
DIVIDE ERROR
A division has been attempted that would cause overflow (usually
division by zero).
SUBSTITUTE CHARACTER IN DATA
If a line contains the substitute character (placed in the character
stream if an invalid code is read), the above trappable fault occurs on
attempting to read the first symbol of the line. (See Section 10).
(GENERAL GRAPH PLOTTER FAULT)
The details are given in the 'ERCC Graph Plotting Reference Manual'.
ILLEGAL EXPONENT
An exponent greater than 255 (or 63 in an integer context) has been
found. This restriction is to avoid excessive looping required to
complete the evaluation with a probable occurrence of overflow.
TRIG FN INACCURATE
The argument of a SIN, COS or TAN function is so large (>107) that the
results are no longer guaranteed.
TAN TOO LARGE
The argument passed to the TAN function is so near a multiple of
π/2 that an overflow condition would exist.
EXP TOO LARGE
The argument passed to the EXP function is so large that overflow would
be caused by evaluation.
LIBRARY FN FAULT n
This is a general library function fault which may arise from any one
of several different function calls.
n=1 The parameter passed to ARCSIN is not in the range -1 to +1
n=2 The parameter passed to ARCCOS is not in the range -1 to +1
n=3 The parameters passed to ARCTAN are both zero.
n=4 The modulus of the parameter passed to HYPSIN is >=172.694.
n=5 The modulus of the parameter passed to HYP COS is >=172.694
n=10 The value of X**2 or the value of (X**2+Y**2) is greater than the
largest real number allowed.
RESOLUTION FAILS
An unconditional resolution cannot be completed as the string to be
resolved does not contain the symbols being searched for.
INTPT TOO LARGE
The modulus of the required integer is too large for a fixed point
register (2**31-1). Also caused by INT function as this is interpreted
as INTPT ( + 0.5).
ARRAY INSIDEOUT
A dynamic array declaration has been executed in which the lower bound
for any dimension exceeds the corresponding upper bound.
CAPACITY EXCEEDED
Too large an entity has been assigned to a %BYTE or %SHORT integer by
the = operator. (The <- operator can be used to avoid this test and
assign the least significant bits only).
Also caused by %STRING assignments if a string >255 characters is
produced or if the LHS of a string assignment is too small.
UNASSIGNED VARIABLE
An attempt is made to use a variable to which no value has been
assigned. This can also occur on a %REPEAT if the corresponding %CYCLE
has not been executed - in this case, the compiler's copy of increment
and final values are not assigned.
ARRAY BOUND FAULT n
An array suffix (n) has been found to be outside the declared bounds.
NON-TRAPPABLE FAULTS
TIME EXCEEDED
The time for this job as given in the Job Control statements, or
foreground Command (or by default) has been exhausted. The program may
be stuck in an unproductive loop.
OPERATOR TERMINATION
The operator has prematurely terminated the job. A memorandum
explaining the reason should be received, unless the 'operator' is the
user running the program from an interactive terminal.
OUTPUT EXCEEDED
The available amount of output as specified by the Job Control
statements (or by default) has been exceeded.
CORRUPT DOPEVECTOR n (formerly WRONG DIMENSION OF ARRAY)
The dope vector for an array, which is an area of store containing
dimension information about the array, is not as expected. It may have
been overwritten, for example by incorrect use of mapping functions, or
more commonly occurs if the array passed as an %INTEGERARRAYNAME or
%REALARRAYNAME has the dimension, n, which is not the dimension
expected by the called routine.
ADDRESS ERROR
The address error interrupt has occurred. Likely causes include running
a faulty program which has been compiled with the option 'NOARRAY',
wrong use of mapping functions, or incorrect declaration of %EXTERNAL
routines or functions. The user is advised to check these suggested
faults before seeking the assistance of the Advisory Service.
ILLEGAL OPCODE
An illegal instruction has been obeyed. This can be caused by a ->
SW(I) instruction when NOARRAY has suppressed the bound checking.
UNEXPLAINED INTERRUPT
Some other interrupt has occurred - contact the Advisory Service.
SECTION 14 - FAULT TRAPPING
INTRODUCTION
In certain cases when a run time fault occurs, it is not desirable for
the run to be terminated. For example, if a particular program
processes a series of data sets, it may be preferable to continue to
the processing of the next data set rather than terminate the whole job
in the event of, say, FAULT 5(SQRT NEGATIVE) occurring.
An instruction is provided which enables certain faults to be trapped
causing control to be transferred to a preassigned point in the
program:
%FAULT N ->
where N is the number of a trappable fault, see list below, and is a
simple label (a %SWITCH label cannot be used). More than one fault can
be directed to the same label, and groups of faults directed to
separate labels can be combined in one %FAULT statement, for example:
%FAULT 1,2,6 ->99, 3,5 -> FAIL
means, 'if a fault of type 1,2 or 6 subsequently occurs then go to
label 99: and if a fault of type 3 or 5 occurs then go to label FAIL'.
The effect is to preserve all the necessary control data to enable
control to revert to this point in the program (and then jump to label
99 or label FAIL) should one of the specified faults occur at some
lower (or the same) level.
NOTES
1. %FAULT statements can only appear in the outer block of a program;
they cannot appear in %EXTERNAL routines.
2. The label to which the fault refers must also be in the outer
block.
3. %FAULT statements can appear at any point in the block after all
declarations within the block.
4. More than one %FAULT statement can appear in a program for the same
fault. In the following example the fault INPUT ENDED is trapped
twice:
%BEGIN %INTEGER I,J,K SELECTINPUT(1) %FAULT 9 -> INEND1 . INEND1:
%FAULT 9 ->INEND2 SELECTINPUT(2) . INEND2:
LIST OF TRAPPABLE FAULTS
Number Description
1 Integer Overflow
2 Real Overflow
3 Invalid %CYCLE
4 Not Enough Store
5 SQRT Negative
6 LOG Negative
7 %SWITCH Variable Not Set
9 Input Ended
10 Non-integer Quotient
11 %RESULT Not Specified
14 Symbol In Data
16 Real Instead Of Integer In Data
17 Divide Error
18 Substitute Character In Data
19 Graph Plotter Fault
21 Illegal Exponent
22 Trig Function Inaccurate
23 TAN Too Large
24 EXP Too Large
25 Library Function Fault
26 Resolution Fails
27 INTPT Too Large
28 Array Inside Out
30 Capacity Exceeded
31 Unassigned Variable
32 Array Bound Fault
Further information about these faults is given in Section 13.
SECTION 15 - INTERNAL CHARACTER CODE
INTRODUCTION
The IMP internal character code is based on the code for data
interchange defined by the International Standards Organisation (ISO).
This code currently assigns graphical or control characters to code
values 0 - 127. Most of the control characters will only concern users
of special hardware such as graphical display devices, but they are
listed overleaf for convenience.
NOTES
1. In the case of some characters there is a discrepancy between the
graphical representation on different peripherals. For example the
ISO character 33 is printed as either exclamation mark or vertical
bar. The most common alternatives are given below.
2. Characters followed by an asterisk in the table below are 'marked'
during LINE RECONSTRUCTION and hence are ignored by all character
input routines other than READ CH. (See Section 10).
3. IMP programmers should rarely need to refer to the code value of a
particular character. If a comparison is required the preferred
method is to use a character constant. The required character is
enclosed in single quotes and the result is a constant having the
internal code value of that character. For example if it is
required to skip a sequence of letters the following statement
could be used:
SKIP SYMBOL %WHILE 'A'<=NEXT SYMBOL<='Z'
The built in function NL can be used to avoid writing a NEWLINE
character within quotes:
%IF I=NL %THEN ............
4. It should be noted that in this code upper case letters appear in
26 consecutive locations, as do lower case letters. This fact
simplifies sorting and text manipulation. Note also that the
numeric characters have values lower than letters. In these and
other respects this code differs from some other data exchange
codes, e.g. EBCDIC, and programmers involved in converting programs
to IMP from other languages should bear these points in mind.
INTERNAL CHARACTER CODE
0 NUL * 32 SPACE 64 Ø 96 *
1 SOH * 33 1(1) 65 A 97 a
2 STX * 34 " 66 B 98 b
3 ETX * 35 # 67 C 99 c
4 EOT * 36 $(π) 68 D 100 d
5 ENQ * 37 % 69 E 101 e
6 ACK * 38 & 70 F 102 f
7 BEL * 39 ' 71 G 103 g
8 BS * 40 ( 72 H 104 h
9 HT * 41 ) 73 I 105 i
10 LF(NL) 42 * 74 J 106 j
11 VT * 43 + 75 K 107 k
12 FF * 44 , 76 L 108 l
13 CR * 45 - 77 M 109 m
14 SO * 46 . 78 N 110 n
15 SI * 47 / 79 O 111 o
16 DLE * 48 0 80 P 112 p
17 DC1 * 49 1 81 Q 113 q
18 DC2 * 50 2 82 R 114 r
19 DC3 * 51 3 83 S 115 s
20 DC4 * 52 4 84 T 116 t
21 NAK * 53 5 85 U 117 u
22 SYN * 54 6 86 V 118 v
23 ETB * 55 7 87 W 119 w
24 CAN * 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
27 ESC * 59 ; 91 [ 123 *
28 FS * 60 < 92 ¬(~) 124
29 GS * 61 = 93 ] 125 *
30 RS * 62 > 94 (↑) 126
31 US * 63 ? 95 _ 127 *
SECTION 16 - ROUTINES, FUNCTIONS AND MAPS IN THE IMP LIBRARY
INTRODUCTION
The routines, functions and maps provided for the IMP programmer are
listed in the table below. They are divided into three classes
INTRINSIC, IMPLICIT and EXPLICIT. Items in the first two classes can be
used without explicit declaration since their names and characteristics
are known to the compiler. Items in the EXPLICIT class, however, must
be specified before they are used. The specification provides
information to the compiler as to the name and parameter list of the
routine, function or map. It also causes the compiler to generate an
entry in a table to ensure that the necessary module is loaded when the
program is run. It is most important to type the specification
accurately, in particular the number and types of parameters must be
correct (the names of parameters used are not significant). The
specification of an item in the EXPLICIT class is preceded by the
delimiter %EXTERNAL, hence for the routine WRITE SQ the specification
would be:
%EXTERNALROUTINESPEC WRITE SQ(%INTEGER I,%NAME A,B)
There is one restriction in the use of IMPLICIT routines and functions.
Because they are compiled (for efficiency reasons) as part of the
program rather than being proper calls to routines compiled seperately,
they cannot themselves be passed as parameters to routines. This
limitation can be overcome (see Section 6).
The routines etc. listed below are either described in this manual, in
which case an appropriate section number is given, or in the Edinburgh
IMP/FORTRAN System Library Manual, in which case the reference 'LM' is
used.
NAME TYPE CLASS PARAMETERS REF
ADD MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,C,
%INTEGER I,J LM
ADDR %INTEGERFN INTRINSIC %INTEGER I 7
ARCCOS %LONGREALFN IMPLICIT %LONGREAL A
ARCSIN %LONGREALFN IMPLICIT %LONGREAL A LM
ARCTAN %LONGREALFN IMPLICIT %LONGREAL A,B LM
ARRAY %ARRAY MAP INTRINSIC %INTEGER I,%ARRAYNAME J 7
BITS %INTEGERFN EXPLICIT %INTEGER I 3
BYTE INTEGER %BYTEINTEGERMAP INTRINSIC %INTEGER I 7
CHARNO %INTEGERFN INTRINSIC %STRINGNAME S,%INTEGER I 8
CLOSE DA %ROUTINE EXPLICIT %INTEGER I 10
CLOSE SQ %ROUTINE EXPLICIT %INTEGER I 10
CLOSE STREAM %ROUTINE IMPLICIT %INTEGER I 10
COPY MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,
%INTEGER I,J LM
COS %LONGREALFN IMPLICIT %LONGREAL A LM
CPUTIME %LONGREALFN EXPLICIT NONE LM
DATE %STRINGFN EXPLICIT NONE LM
DET %LONGREALFN EXPLICIT %LONGREALARRAYNAME A,
%INTEGER I LM
DIV MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,
%INTEGER I,J,
%LONGREALNAME C LM
ERFN %LONGREALFN EXPLICIT %LONGREAL A,B
NAME TYPE CLASS PARAMETERS REF
ERFNC %LONGREALFN EXPLICIT %LONGREAL A,B LM
EXP %LONGREALFN IMPLICIT %LONGREAL A LM
EXP TEN %LONGREALFN EXPLICIT %LONGREAL A LM
FRAC PT %LONGREALFN INTRINSIC %LONGREAL A 2
FROM STRING %STRINGFN IMPLICIT %STRINGNAME S,%INTEGER I,J 8
HYPCOS %LONGREALFN EXPLICIT %LONGREAL A,B LM
HYPSIN %LONGREALFN EXPLICIT %LONGREAL A,B LM
HYPTAN %LONGREALFN EXPLICIT %LONGREAL A,B LM
IFD BINARY %INTEGERFN EXPLICIT %SHORTINTEGERARRAYNAME I,
%INTEGER J,K,%INTEGERNAME L LM
IFD ISO %INTEGERFN EXPLICIT %BYTEINTEGERARRAYNAME I,
%INTEGER J,K,%INTEGERNAME L LM
INT %INTEGERFN INTRINSIC %LONGREAL A 2
INT PT %INTEGERFN INTRINSIC %LONGREAL A 2
INTEGER %INTEGERMAP INTRINSIC %INTEGER I 7
INVERT %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,
%INTEGER I,%LONGREALNAME J LM
ISO CARD %ROUTINE EXPLICIT %BYTEINTEGERARRAYNAME K 10
LENGTH %INTEGERFN INTRINSIC %STRINGNAME S 8
LOG %LONGREALFN IMPLICIT %LONGREAL A LM
LOGTEN %LONGREALFN EXPLICIT %LONGREAL A LM
LONG REAL %LONGREALMAP INTRINSIC %INTEGER I 7
MOD %LONGREALFN INTRINSIC %LONGREAL A 2
MULT MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,C,
%INTEGER I,J,K LM
MULT TR MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,C,
%INTEGER I,J,K
NAME TYPE CLASS PARAMETERS REF
NEWLINE %ROUTINE INTRINSIC NONE 10
NEWLINES %ROUTINE INTRINSIC %INTEGER I 10
NEWPAGE %ROUTINE INTRINSIC NONE 10
NEXT ITEM %STRINGFN INTRINSIC NONE 8
NEXT SYMBOL %INTEGERFN INTRINSIC NONE 10
NL %INTEGERFN INTRINSIC NONE 15
NULL %ROUTINE EXPLICIT %LONGREALARRAYNAME A,
%INTEGER I,J LM
OPEN DA %ROUTINE EXPLICIT %INTEGER I 10
OPEN SQ %ROUTINE EXPLICIT %INTEGER I 10
PRINT %ROUTINE IMPLICIT %LONGREAL A,%INTEGER I,J 10
PRINT CH %ROUTINE INTRINSIC %INTEGER I 10
PRINT FL %ROUTINE IMPLICIT %LONGREAL A,%INTEGER I 10
PRINT STRING %ROUTINE INTRINSIC %STRING S 8
PRINT SYMBOL %ROUTINE INTRINSIC %INTEGER I 10
RADIUS %LONGREALFN IMPLICIT %LONGREAL A,B LM
RANDOM %REALFN EXPLICIT %INTEGERNAME I,%INTEGER K LM
READ %ROUTINE IMPLICIT %NAME A 10
READ CH %ROUTINE INTRINSIC %NAME I 10
READ DA %ROUTINE EXPLICIT %INTEGER I,%INTEGERNAME J,
%NAME K,L 10
READ ITEM %ROUTINE INTRINSIC %STRINGNAME S 8
READ SQ %ROUTINE EXPLICIT %INTEGER I,%NAME J,K 10
READ STRING %ROUTINE IMPLICIT %STRINGNAME S 8
READ SYMBOL %ROUTINE INTRINSIC %INTEGER I 10
REAL %REALMAP INTRINSIC %INTEGER I 7
NAME TYPE CLASS PARAMETERS REF
RECORD %RECORDMAP INTRINSIC %INTEGER I 9
RFD BINARY %LONGREALFN EXPLICIT %SHORTINTEGERARRAYNAME I,
%INTEGER J,K,%INTEGERNAME L LM
RFD ISO %LONGREALFN EXPLICIT %BYTEINTEGERARRAYNAME I,
%INTEGER J,K,%INTEGERNAME L LM
SELECT INPUT %ROUTINE INTRINSIC %INTEGER I 10
SELECT OUTPUT %ROUTINE INTRINSIC %INTEGER I 10
SET MARGINS %ROUTINE IMPLICIT %INTEGER I,J,K 10
SHIFT C %INTEGERFN EXPLICIT %INTEGER I,J 3
SHORT INTEGER %SHORTINTEGERMAP INTRINSIC %INTEGER I 7
SIN %LONGREALFN IMPLICIT %LONGREAL A LM
SKIP SYMBOL %ROUTINE INTRINSIC NONE 10
SOLVE LN EQ %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,
%INTEGER I,%LONGREALNAME C LM
SPACE %ROUTINE INTRINSIC NONE 10
SPACES %ROUTINE INTRINSIC %INTEGER I 10
SQRT %LONGREALFN IMPLICIT %LONGREAL A LM
STRING %STRINGMAP INTRINSIC %INTEGER I 8
SUB MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,C,
%INTEGER I,J LM
TAN %LONGREALFN IMPLICIT %LONGREAL A LM
TIME %STRINGFN EXPLICIT NONE LM
TO STRING %STRINGFN INTRINSIC %INTEGER I 8
TRANS MATRIX %ROUTINE EXPLICIT %LONGREALARRAYNAME A,B,
%INTEGER I,J LM
NAME TYPE CLASS PARAMETERS REF
UNIT %ROUTINE EXPLICIT %LONGREALARRAYNAME A,
%INTEGER I LM
WRITE %ROUTINE INTRINSIC %INTEGER I,J 10
WRITE DA %ROUTINE EXPLICIT %INTEGER I,%INTEGERNAME J,
%NAME K,L 10
WRITE SQ %ROUTINE EXPLICIT %INTEGER I,%NAME J,K 10
APPENDIX: DIFFERENCES IN 2900 IMP
The following is a list of the differences between the IMP language
implemented on ICL 2900 series computers and the language described in
the body of this Manual. It should be noted that some of these changes
have been incorporated in the System 4 EMAS implementation and, to a
lesser extent, in the NUMAC OS implementation. They are expressed here
as changes to the Manual description.
1. Abolition of the modulus operator '!...!' coupled with the
introduction of a standard integer function IMOD, corresponding to
the existing real function MOD, to yield the absolute value of an
integer.
The change removes a source of ambiguity (e.g. meaning of A!!B!!C).
Examples: I = IMOD(IVALUE) where I and IVALUE are integer variables. R
= MOD(VALUE) where R is a real variable and VALUE is real or integer.
2. Abolition of the use of a special symbol for
π in favour of a standard long real function PI.
The special symbol is not found in standard character sets.
Example: CIR = PI*DIAM where CIR is a real variable and DIAM is real or
integer.
3. Re-specification of the standard procedures LENGTH and CHARNO as
maps rather than functions.
The extension permits a number of string-manipulation operations to be
effected more neatly.
Example: %BEGIN %STRING (255) S, T %INTEGER I S = "FIRST LINE" SECOND
LINE"; ! Note the use of "..." (see item 9 below). T = S ! ! Below, S
is truncated at the first newline. ! %CYCLE I = 1,1,LENGTH(S) LENGTH(S)
= I-1 %AND %EXIT %IF CHARNO(S,I) = NL %REPEAT ! ! Below, each newline
character in T is replaced by a space. ! %CYCLE I = 1,1,LENGTH(T)
CHARNO(T,I) = ' ' %IF CHARNO(T,I) = NL %REPEAT PRINTSTRING(S); NEWLINE
PRINTSTRING(T); NEWLINE %ENDOFPROGRAM
When this program is executed, the following output is produced by it:
FIRST LINE
FIRST LINE SECOND LINE
4. Abolition of numeric labels.
Most current programming languages provide only alphabetic labels, in
order that labels may be meaningful in the same way as other
identifiers. The need to use labels at all in IMP, as compared with
Atlas Autocode, is greatly reduced by the availability of such
program-structuring facilities as compound conditional statements and
loop control clauses.
Example: 233: D=BB-4AC; ! Not valid in 2900 IMP. L233: D=BB-4AC; !
Valid. LAST PART: D=BB-4A*C; ! Valid and more meaningful.
5. Restriction of the division operator '/' to yield a result of type
real in all cases.
The integer-division operator '//' becomes obligatory where an integer
result is intended. The effect of this and items 6, 7 and 9 is to
remove all remaining cases of type ambiguity from the language.
Example: K = I/J where I, J and K are integer variables, would fail
since the right hand side is always a real expression (even when J
divides exactly into I).
6. Restriction of the exponentiation operator '**' to yield a result
of type real in all cases, coupled with the introduction of an
integer-exponentiation operator '****'.
The case of exponentiation becomes exactly parallel to the case of
division.
The reverse slant, \ for real and \\ for integer, is an alternative
notation for these operators.
Examples: K = I**J or K = I\J where I, J and K are integers, is valid.
K = IJ where I, J and K are integers, would fail, since the right hand
side is a real expression.
7. Restriction of the form of integer constants to disallow the
inclusion of decimal points and exponent symbols.
A constant form like 0.1@1 is technically an integer in System 4 EMAS
and NUMAC OS IMP, because it has an integral value. Such forms are not
allowed in 2900 IMP.
8. Abolition of double quote deletion (page 1.1, item 8).
9. Introduction of a distinctive quote symbol for strings
(double-quote in place of single-quote).
The main effect is to make it possible to distinguish a single
character string from a character constant.
Examples: ASTRING = "THIS IS A STRING" where ASTRING is a string
variable. ASYMBOL = 'A' where ASYMBOL is an integer variable.
10. Extension of the set of ranges of integer to include %LONGINTEGER
(64 bits).
Long integers were implemented to allow the easy handling of a systems
software feature of 2900 machines, rather than for manipulating very
large numbers. However, most long integer arithmetic will give the
expected results.
The following characteristics of long integers should be noted:
* A long integer can be assigned a decimal value only in the range
±214783647 (±231-1). If an attempt is made to assign to a long
integer a value outside this range, the fault
REAL IN INTEGER EXPRESSION
will occur. A larger number may however be stored in a long integer by
using an explicit hexadecimal or binary pattern to represent the
number. For example, if L is a long integer variable,
L = X'1FFFFFFFFFFFFFFF' (16 hex digits) will succeed, but L =
9999999999999999 (15 decimal digits) will fail.
* Input/Output: long integer values (i.e. in the range ±263-1) may
be read into long integer variables using the input routine READ.
They may be printed out using the output routine PRINT, with the
third parameter set to 0. However, numbers outside the range
±1015 are floated and printed in exponential form.
* A variable of type %LONGINTEGER can be shifted by up to 63 bits
left or right, using the << and >> operators. However, an attempt
to shift either way 64 bits will have no effect (it might be
expected to clear a long integer to 0).
* In general, integer arithmetic is done with a precision of 32 bits
if all the operands are of 32-bit length. This has some
implications when long integer variables are used. For example:
%INTEGER I,J %LONGINTEGER K K = (I<<32)!J; ! Effect is K = J, since
32-bit working is used. K = I; K=(K<<32)!J; ! This assigns K as
intended.
* If a long integer is set to a negative integer (32-bit) value, the
sign bit is propagated through the long integer, resulting in a
negative long integer. Thus
L = X'FFFFFFFF'
where L is a long integer, sets X'FFFFFFFFFFFFFFFF' (the value -1) in L
and not X'00000000FFFFFFFF'. The latter value may be set by including
the leading zeros in the assignment statement.
11. Changes to the set of ranges of reals.
The 2900 implementation offers three precisions for reals: 32-bit
(somewhat inefficient), 64-bit and 128-bit. These are specified as
%REAL, %LONGREAL and %LONGLONGREAL, respectively. Working is either in
64 bits or in 128 bits. Thus type %REAL is only effective in storing
values in scalars and arrays: a variable of type %REAL will have its
value lengthened when used in any calculation.
12. Additions to the built-in mapping functions:
%LONGINTEGERMAP LONGINTEGER(%INTEGER ADDRESS)
%LONGLONGREALMAP LONGLONGREAL(%INTEGER ADDRESS)
13. Abolition of type %SHORTINTEGER.
14. Abolition of the functions IFD BINARY and RFD BINARY.
15. Provision of functions for changing lengths of reals and of
integers:
LENGTHENI(K) Parameter of type %INTEGER, result of type
%LONGINTEGER. SHORTENI(K) Parameter of type %LONGINTEGER, result of
type %INTEGER. LENGTHENR(S) Parameter of type %LONGREAL, result of
type %LONGLONGREAL. SHORTENR(S) Parameter of type %LONGLONGREAL,
result of type %LONGREAL.
These functions need only be used when it is desired to change the
length of an operand in an expression.
16. Change in the interpretation of grave sign ().
The grave sign stands for itself; i.e. it is not mapped onto @ on
input.
17. Abolition of the %MONITORSTOP statement.
It is now necessary to give the two statements %MONITOR; %STOP.
18. Abolition of the %PRINTTEXT statement.
19. Abolition of implied multiplication.
In System 4 EMAS and NUMAC OS IMP, constructions such as 23A(6) are
allowed, i.e. constant followed, without an asterisk, by a variable or
array element. This is not allowed in 2900 IMP, and would have to be
written as 23*A(6).
20. Abolition of fault trapping in favour of an event mechanism.
It has long been agreed that the structure of fault trapping in System
4 EMAS and NUMAC OS IMP is inadequate, especially in respect of the
forced return to the main program and the inability to trap faults in
external routines. The architecture of the 2900 Series has enabled a
more structured approach to be adopted and the following notes describe
it.
The term %EVENT is introduced to describe the class of conditions which
may be detected or signalled. It is broader than the %FAULT concept, in
that it may include user-defined events as well as the conventional
'faults', such as division by 0.
The following list groups certain faults to provide a set of events, of
which 1-10 are predefined and events 11-14 may be user defined.
Event Classes Fault Numbers
No. Name Fault Numbers
1 Arithmetic overflow 1,2,17,22,23,24,27
2 Excess store (or other resource) 4
3 Substitute character in data 18
4 Invalid data 14
5 Invalid arguments 3,5,6,7,21,28
6 Out of range 30,32
7 Resolution failure 26
8 Unassigned variable 31
9 Input ended 9
10 Library subroutine error 25
*11-14 GENERAL PURPOSE
*11 is also used by the Graph Package (EMAS/NUMAC fault 19)
Within an event class, the individual faults are assigned different
sub-event numbers. The faults are thus categorised as follows:
Fault Number Description Event/Sub-event no.
1 Integer Overflow 1/1
2 Real Overflow 1/2
3 Invalid %CYCLE 5/1
4 Not Enough Store 2/1
5 SQRT Negative 5/2
6 LOG Negative 5/3
7 %SWITCH Variable Not Set 5/4
9 Input Ended 9/1
Fault Number Description Event/Sub-event no.
10 Non-integer Quotient *
11 %RESULT Not Specified *
14 Symbol in Data 4/1
16 Real Instead of Integer in Data *
17 Divide Error 1/3
18 Substitute Character in Data 3/1
19 Graph Plotter Fault 11/n
21 Illegal Exponent 5/5
22 Trig Function Inaccurate 1/4
23 TAN Too Large 1/5
24 EXP Too Large 1/6
25 Library Function Fault 10/n
26 Resolution Fails 7/1
27 INTPT Too Large 1/7
28 Array Inside Out 5/6
30 Capacity Exceeded 6/1
31 Unassigned Variable 8/1
32 Array Bound Fault 6/2
The following System 4 EMAS/NUMAC OS IMP faults are omitted from the
event classes:
* Non-integer quotient (10) - redundant in 2900 IMP.
* Result not specified (11) - redundant because of a compile-time
check.
* Real instead of integer in data (16) - in 2900 IMP an integer
'read' terminates on a ':' sign or '@' sign, in addition to its
EMAS/NUMAC definition.
The syntactic structure is:
%ON %EVENT nlist %START e.g. %ON %EVENT 1,7,12 %START : : : %FINISH
%FINISH
This structure must follow the declarations at the head of a block
(routine) and may be regarded as the last declaration of the block. The
code within the %START .. %FINISH is not executed on entry through the
head of the block but is jumped to should an event which is contained
within the list occur. The flow of control then depends on the contents
of the %START .. %FINISH.
An event may be forced by the unconditional instruction:
%SIGNAL %EVENT n, exprn.
where n is the event required and 'exprn' is an optional integer
expression which may be used to specify sub-event information. n must
be given as a constant, and 'exprn' must yield an integer in the range
0-255.
%SIGNAL %EVENT statements are the only way of causing user-defined
events to occur, although they can also be used with the predefined
events (1-10).
If an event is forced by a %SIGNAL %EVENT statement in an %ON %EVENT
%START/%FINISH block which includes the occurring event in its event
list, a branch is not made to the head of that block, since such a
branch would probably cause looping. Instead the event is traced up the
stack through each superior block until either a suitable %ON %EVENT
statement is found or the user environment is left.
In parallel with these language statements two implicit integer
functions are introduced which enable the programmer to determine
further information when an event occurs. They may only be meaningfully
called in a block which has an %ON %EVENT statement within it:
%INTEGERFN EVENT INF
returns (event no<<8)!sub-event no for the last event which has
occurred. Fault 16 occurs at compile time if the function is called in
a block with no %ON %EVENT statement, and an unassigned variable will
result at run time if no event has in fact occurred when the function
is called.
%INTEGERFN EVENT LINE
returns the program line number at which the last event occurred during
execution of the block in question (provided the program was compiled
with line number updating; otherwise 0 will be returned). If no event
has occurred, an unassigned variable will result.
If an event is not trapped in the block in which it occurs then it is
traced up the stack through each superior block until either a suitable
%ON %EVENT statement is encountered or the user environment is left,
the diagnostic package being entered in the latter case. When a
suitable %ON %EVENT statement is encountered in a superior block,
program control is transferred to its %START/%FINISH block.
As a result of these facilities it follows that, for example, 'input
ended' may be detected and dealt with from within an external routine
or a routine within a main program.
Two examples of the use of the event mechanism are given on the next
page.
System defined events
%INTEGER SUBCLASS, EVENTNO %CONSTSTRING(21)%ARRAY
MESSAGE(1:2)="CAPACITY EXCEEDED", "ARRAY BOUNDS EXCEEDED"
%ON %EVENT 6 %START SUBCLASS = EVENT INF&X'FF' EVENTNO = EVENT INF>>8 &
15 %IF 1<=SUBCLASS<=2 %THEN PRINTSTRING(MESSAGE(SUBCLASS)) %ELSE %C
PRINTSTRING("INVALID SUBCLASS") NEWLINE ->ERROR EXIT %FINISH . . ERROR
EXIT: ......
User defined events
%INTEGER EVENT, SUBEVENT %ON %EVENT 12 %START PRINTSTRING("EVENT 12 HAS
BEEN TRAPPED"); NEWLINE ->EVENT 12 %FINISH . . SUBEVENT = 2 . % SIGNAL
%EVENT 12, SUBEVENT . EVENT 12: ......
COMPATIBILITY OF SYSTEM 4 EMAS IMP WITH 2900 IMP
The IMP compiler on System 4 EMAS will issue a warning for each of the
first 30 statements in any compilation that are acceptable to System 4
IMP but not to 2900 IMP.
The IMP compiler on System 4 EMAS will accept an %ON %EVENT statement
as described above, provided it occurs in a main program block only.
The statement is not compiled but is transposed into %FAULT statements
which are compiled. This arrangement enables the majority of programs
that use fault trapping to be written in a way that is acceptable to
both System 4 IMP and 2900 IMP.
The System 4 compiler, however, does not accept the %SIGNAL %EVENT
statement, or calls on EVENT LINE or EVENT INF.
ADDRESSING ON 2900 SERIES MACHINES
On 2900 series machines, all the 32 bits of the address field are
significant. Thus a 'negative' address is not necessarily invalid.
WRITING PORTABLE IMP PROGRAMS FOR EMAS AND ICL 2900 SERIES MACHINES
For several years many users have found it useful to transfer IMP
programs between EMAS and IBM 360 series machines. By this means they
have been able to exploit the convenient program development
environment provided by EMAS and the powerful batch job environment
provided on our local 370 and more recently at NUMAC.
While only batch facilities are available on the ICL 2980 at the Bush
Estate, it is likely that some users will have a requirement to write
IMP programs which can be run without change at NUMAC, on EMAS and on
the 2980.
This note indicates areas of difference between the IMP compilers on
the three machines. These areas must be avoided if compatible IMP
programs are to be written for running unchanged on more than one
machine. Note that, in general, the NUMAC and EMAS compilers are the
same (the two exceptions are noted in the text).
Constants
* Integer constants
Integer constants which contain decimal points or exponents must be
avoided.
* Use of π
The read-only variable PI should be used. The use of the ISO currency
symbol for this purpose must be avoided.
* Strings
Both single quote (') and double quote (") are permissible string
constant delimiters. At some date, to be announced, only double quote
string delimiters will be accepted.
N.B. ONLY single quotes are allowed in NUMAC IMP.
%PRINTTEXT must not be used.
Arithmetic operators
* Division operators '/' and '//''
The use of '/' must be restricted to expressions which yield a real
result. '//' should be used in all cases where the result must be of
type %INTEGER, e.g. where the result is being assigned to an integer
variable.
* Multiplication
Implied multiplication must be avoided.
* Exponentiation operator '**'
The '**' operator gives a result of type %REAL. If an integer result
is required then INT can be used; for example, K = INT(I**J).
* Modulus functions
The intrinsic functions MOD (for reals) and IMOD (for integers) must
always be used.
Variable types
The following variable types can be used:
%BYTEINTEGER %LONGREAL %INTEGER %STRING %REAL %RECORD
Labels
Labels must be standard IMP names, i.e. the first character must be a
letter; e.g. L100:
Control statements
* %MONITOR STOP
This must be coded as two separate statements: %MONITOR; %STOP
* Fault trapping
In implementing IMP on the 2900 series the opportunity has been taken
to redesign the fault trapping mechanism, in the light of frequent
complaints of inadequacy of the %FAULT facility. In order to be
completely portable, programs must not use fault trapping.
N.B. The EMAS compiler does allow limited use of the 2900 %ON %EVENT
statement by translating it into a standard EMAS IMP %FAULT statement.
The following restrictions apply:
a. The %ON %EVENT statement may only appear in the outermost block of a
main program. b. Only a simple jump statement may be placed within the
%ON %EVENT ..... %START; ....; %FINISH block.
For example: %ON %EVENT 9 %START -> INPUT END %FINISH
Conclusion
It is hoped that users will keep these suggestions in mind when writing
programs which are likely to have a lifetime of more than a few months.
By so doing they will minimise the work needed to transfer them to a
2900 series machine should this become necessary or desirable.
M.D. Brown R.R. McLeod
September 1977
accuracy of real arithmetic 2.3 actual parameters 6.3 addition 2.1
ADDRESS ERROR 13.4 alignment 7.3 of record sub-fields 9.1 %AND 4.2
arithmetic assignment 2.4 division 2.2 expressions 2.2 operations 2.1
operators 2.1 variables 1.3 array bound checking 11.1 array bound fault
1.6 ARRAY BOUND FAULT 13.3 ARRAY INSIDEOUT 13.3 array mapping 7.3 ARRAY
7.4,11.1 %ARRAYFORMAT 7.4 arrays declaration of 1.6 dynamic 1.6 %RECORD
9.2 %STRING 8.3 with variable bounds 1.6 assignment of arithmetic
expressions 2.4 of logical expressions 3.1 of records 9.6 of strings
8.6 of symbols 2.5 to pointer variables 7.3
%BEGIN 5.4 binary files 10.8 bit patterns 3.2 BITS 3.5 block structure
5.2,5.4 built in maps 7.2 %BYTEINTEGER 1.3 BYTEINTEGER 7.2
%BYTEINTEGERMAP 7.1
calling routines 6.1 CAPACITY EXCEEDED 13.3 in arithmetic operations
2.4 in logical operations 3.2 in string assignment 8.5 in string
expressions 8.5 in string functions 8.4
using strings 8.10 character code 10.1,15.1 input routines 10.2 marked
10.4,15.1 output routines 10.5 streams 10.2 SUB 10.4 CHARNO 8.10 CHECK
11.1 CLOSE STREAM 10.7 CLOSEDA 10.10 CLOSESQ 10.8 comments 1.2 compiler
options 11.1 concatenation of strings 8.5 condition string 8.8
conditional repetition 4.4 conditional routine calls 6.2 conditional
string resolution 8.9 conditions 4.1 %CONST records 9.2 string
variables 8.3 %CONST variables declaration of 1.7 constants 1.4 binary
1.5 decimal 1.4 hexadecimal 1.5 quotes in 1.4 spaces and newlines in
1.4 string 8.3 symbol 1.4 CORRUPT DOPE VECTOR 13.4 cycles 4.3
conditional 4.4 with control variables 4.5
declaration location of 5.3 of arrays 1.6 of routines and functions 6.1
of variables 1.6 delimiters 1.2 rules for typing 1.1 DIAG 11.1
diagnostics 11.1 DIAGS OUTPUT EXCEEDED 11.2 direct access files 10.10
DIVIDE ERROR 13.2 division in integer expressions 2.2
in real expressions 2.2 double quote deletion 1.1 double sided
conditions 4.2 dynamic arrays 5.4
EBCDIC 15.1 efficiency 11.3 %ELSE 4.3 %END 5.4,6.1 %ENDOFFILE 6.13
%ENDOFLIST 11.2 %ENDOFPROGRAM 5.3 exclusive or 3.4 %EXIT 4.6 EXP TOO
LARGE 13.2 exponentiation 2.1 in integer expressions 2.2 in real
expressions 2.3 %EXTERNAL records 9.2 string variables 8.3 %EXTERNAL
routines 6.13 %EXTERNAL variables 6.14 declaration of 1.7
%EXTERNALROUTINESPEC 6.13,16.1 %EXTRINSIC records 9.2 %EXTRINSIC
variables 6.14
%FAULT 14.1 faults compile time 12.1 run time 13.1 trappable 14.2
trapping 13.1,14.1 files character 10.1 direct access 10.10 library
6.13 sequential 10.8 %FINISH 4.2 formal parameters 6.3 FRACPT 2.4
FROMSTRING 8.10 functions 6.1 in system library 16.1 string 8.4
global variables 6.1 GRAPH PLOTTER FAULT 13.2
%IF 4.2 ILLEGAL EXPONENT 13.2 ILLEGAL OPCODE 13.4 implicit routines
6.10 implied multiplication 2.1 inclusive or 3.4 indefinite cycle 4.6
initialisation of const% variables 1.7 of %OWN variables 1.7 of strings
8.3 INPUT ENDED 10.4,10.9,13.1 input/output 10.1 INT 2.3 integer
division 2.2 integer expressions 2.2 INTEGER OVERFLOW 13.1 %INTEGER 1.3
INTEGER 7.2 %INTEGERMAP 7.1 INTPT TOO LARGE 13.3 INTPT 2.3 intrinsic
routines 6.10 INVALID CYCLE 4.5,13.1 ISO 15.1 ISOCARD 10.3
jumps 4.7
labels 4.7 length of record sub-fields 9.7 of variables 1.3 LENGTH 8.10
LENGTHSQ 10.9 library 6.10 files 6.13 list of contents 15.1 LIBRARY FN
FAULT 13.2 line number 11.1 line reconstruction 10.4 %LIST 11.2 LIST
11.2 listing of programs 11.2 LOG NEGATIVE 13.1 logical and 3.1,3.4
assignments 3.1 channels 10.1 not 3.1,3.3 operations 3.1 operators 3.1
or 3.1,3.4 %LONGREAL 1.3 %LONGREALMAP 7.1
mapping of arithmetic variables 7.1 of records 9.4 of strings 7.1,8.4
maps 7.1 in system library 16.1
margins input 10.4,10.7 output 10.7 marked character 10.4 MOD 2.5
modulus 2.5 modulus signs 2.5 %MONITOR 11.1 %MONITORSTOP 4.8,11.1
multiplication 2.1
names 1.2 of %EXTERNAL entities 6.14 scope of 5.3 used for labels 4.7
nesting of blocks 5.3 of conditions 4.6 of cycles 4.6 NEWLINE 10.5
NEWPAGE 10.5 NEXT ITEM 8.11 NEXTSYMBOL 10.2 NOARRAY 11.1 NOCHECK 11.1
NOLIST 11.2 NON INTEGER QUOTIENT 13.1 NOT ENOUGH STORE 13.1 NOTRACE
11.1
OPENDA 10.10 OPENSQ 10.8 OPERATOR TERMINATION 13.4 OPT 11.4 %OR 4.2
OUTPUT EXCEEDED 10.6,13.4 %OWN records 9.2 string variables 8.3 %OWN
arrays 1.7 %OWN variables declaration of 1.7 in routines 6.11
initialisation of 1.7
parameters 6.3 actual 6.3 formal 6.3 of type %RECORDNAME 9.6 to maps
7.2 pointer variables 7.3 of type %RECORD 9.3 precedence of arithmetic
operators 2.1 of logical operators 3.4 PRINT 10.6 PRINTCH 10.6 PRINTF
10.6 PRINTSTRING 8.11,10.5 PRINTSYMBOL 10.5 %PRINTTEXT 10.5 programs
continuation of statements 1;1 efficiency of 11.3 listing of 11.3
testing 11.4 typing conventions 1.1
READ ITEM 8.11 READ STRING 8.11 READ 10.3 READCH 10.4 READDA 10.10
READSQ 10.9 READSTRING 10.3 READSYMBOL 10.2 real expressions 2.3
precision of variables 1.3,2.3 REAL INSTEAD OF INTEGER IN DATA
10.3,13.2 REAL OVERFLOW 13.1 %REAL 1.3 REAL 7.2 %REALMAP 7.1 %REALSLONG
1.7 %REALSNORMAL 1.7 %RECORD 9.1 arrays 9.2 %RECORDFORMAT 9.1
%RECORDMAP 7.1 %RECORDNAME 9.5 records sub-fields of 9.1 %RECORDSPEC
9.5 recursive routines 6.11 %REPEAT 4.3 resolution conditional 8.9 of
strings 8.6 RESOLUTION FAILS 13.2 RESULT NOT SPECIFIED 13.1 %RESULT 6.8
of maps 7.2 %RETURN 6.2 routines 6.1 explicit 16.1 %EXTERNAL 6.13
implicit 6.10,16.1 in system library 16.1 intrinsic 6.10,16.1 recursive
6.11 with parameters 6.3 %ROUTINESPEC 6.1
scope of names 5.3
SELECTINPUT 10.2 SELECTOUTPUT 10.2 semantic errors 12.2 sequential
files 10.8 SET MARGINS 10.7 shift operators 3.1,3.2 SHIFTFC 3.3
%SHORTINTEGER 1.3 SHORTINTEGER 7.2 %SHORTINTEGERMAP 7.1 SKIPSYMBOL 10.3
SPACE 10.5 %SPEC 6.1 SQRt NEGATIVE 13.1 stack 5.1 stack pointer 5.1
%START 4.2 %STOP 4.8 storage allocation 5.1 store map functions 7.1
store mapping 7.1 string resolution 8.6 %STRING conditional resolution
8.9 constants 8.3 STRING 7.2,8.4 %STRINGMAP 7.1 strings 8.1
sub-expressions 2.4 sub-fields 9.1 of type %RECORD 9.4 of type
%RECORDNAME 9.5 SUB 10.4 SUBSTITUTE CHARACTER IN DATA 10.4,13.2
subtraction 2.1 SWITCH VECTOR NOT SET 13.1 switch vectors 4.7 %SWITCH
4.7 SYMBOL IN DATA 10.3,13.1 syntactic errors 12.1
TAN TOO LARGE 13.2 %THEN 4.2 TIME EXCEEDED 13.4 TO STRING 8.10 TRACE
11.1 trappable faults 14.2 TRIG FN INACCURATE 13.2
unassigned checking 11.1 UNASSIGNED VARIABLE 13.3 UNEXPLAINED INTERRUPT
13.4 %UNLESS 4.3 %UNTIL 4.3
variables 1.3 arithmetic 1.3
%CONST 1.7 declaration of 1.6 %EXTERNAL 6.14 %EXTRINSIC 6.14 %OWN 1.7
pointer 7.3 string 8.3
%WHILE 4.3 WRITE 10.6 WRITEDA 10.10 WRITESQ 10.9
The second edition of the IMP Language Manual was published in May 1974
and until now there have been no updates. It is still largely accurate
for the System 4 EMAS and NUMAC OS implementations of IMP, but the
implementation on ICL 2900 series machines contains a number of
important departures from what is described in the Manual. It has
therefore been decided to issue an Appendix detailing these differences
(attached); it should be inserted between Section 16 and the Index.
A sheet dated September 1977 is also attached: it gives advice on
writing IMP programs to be compatible with NUMAC OS IMP, System 4 EMAS
IMP and 2900 IMP.
It is recommended that this cover note be filed at the end of the
Manual, as a record that it has been updated.
IMP80 on EMAS 2900: Differences from IMP9
Contents
1. Compiler name Page
2. Lower case input 2
3. Continuation 2
4. Comments 2
5. == and ## 3
6. Available types 3
7. Keyword and operator alternatives 3
8. own initialisation 3
9. Switch labels 4
10. Cycles 5
11. start/finish blocks 6
12. Constants 7
13. Strings 8
15. Records 9
15. external items 10
16. Procedures as parameters 11
Introduction
This document is intended for users of the programming language IMP on
EMAS 2900 who wish to know how the new version of IMP, IMP80, differs
from the current version, IMP9.
It should be noted that IMP80 on EMAS 2900 differs in certain respects
from other implementations of IMP80, and that this document should not
be trusted as far as other implementations are concerned.
Some of the features of IMP80 described below exist in IMP9. They are
included here either to help explain some other feature or for
completeness.
1. The command invoking the compiler is IMP80, not IMP.
2. Except within single or double quotes, lower case text is not
distinguished from upper case. Thus
%integer a and %INTEGER A
are both acceptable and treated as equivalent. Note that
%integer Item la
is not distinguished from
%INTEGER ITEM1A
The convention in this document is that IMP keywords are underlined and
given in lower case, with identifiers in upper case. Thus:
integer A
3. Continuation of statements. Statements can be continued on the next
line by terminating the current line with c. The c is not required
if the break comes immediately after a comma. (This applies to all
statement types, not just own array initialisations.)
Examples: if A=23 and K<=14 then c L=17 and M=18 integer A, B, C, D, E,
F, G, H, I, J
A blank line following a line terminated by c is ignored.
4. Comments. A semi-colon does not terminate a comment - it can only
be terminated by a newline. Comment statements can be continued by
use of c, OR BY BEING BROKEN AFTER A COMMA (see 3 above).
A new type of comment is introduced; it is delimited by curly brackets,
'{' and '}'. Such a comment can appear between atoms of a statement (an
atom is an identifier, constant, keyword, operator or delimiting
symbol).
Example: A(I{month}, J{salary}) = 927.4
The comment text can contain any symbols except '}' and newline. The
closing '}' can be omitted, in which case the comment is terminated by
the next newline.
{...} comments are particularly useful for explaining own array
initialisations.
5. == and ## (or ==)
The == operator can be used in conditions:
Example: if A == B then .......
The condition is only true if A and B refer to the same variable; i.e.
address and type equivalence is required. The operator ## (or ==) can
be used to express the inverse condition:
if A ## B then .......
Note that == and ## can only be used to compare references to scalar
variables, not to arrays.
6. Available types
byte integer half integer integer long integer real long real long
long real string (n) record (format)
all of these can be followed by array or name or array name
A half integer variable requires 16 bits (2 bytes) of storage. It holds
an unsigned integer value, in the range 0-65535.
The statements reals long and reals normal are not available in IMP80.
7. Keyword and operator alternatives
! or | for comment fn for function const for constant byte for byte
integer half for half integer \ for ** (real exponentiation) \ for
**** (integer exponentiation) <> or = for # ~ for ( (logical 'not')
== for ##
8. own initialisation
a) The statement
own integer A
declares an own integer variable A and initialises it to 0 (the default
value when no value is specified).
The statement
own integer X, Y, Z=4
declares X, Y and Z and initialises them to 0, 0 and 4 respectively. In
IMP9 this statement causes X, Y and Z to be set to 4, 4 and 4. Note the
difference!
It is bad practice to rely on default initialisation values, especially
in IMP80, where existing implementations do not have the same defaults.
The statements above should have been given as
own integer A=0
own integer X=0, Y=0, Z=4
These are unambiguous, whichever version of IMP is used.
b) For convenience, constants used in own array initialisations can be
followed by a repeat count, in brackets. This repeat count can be given
as '(*)' where * represents the number of remaining array elements to
be initialised.
Example:
own integer array VALUES (1:50) = %c
17, 4, 6(3), 9, 22(17),
100(*) {all the rest}
This also applies, of course, to constant and external array
initialisation.
c) Own arrays can be multi-dimensional. As before, the bounds must be
constants or constant expressions. The order in which array elements
are assigned the initialising values is such that the first subscript
changes fastest. Thus, for an array A(1:2,1:3), the order of assignment
would be A(1,1), A(2,1), A(1,2), A(2,2), A(1,3), A(2,3).
9. Switch labels
Consider the following:
switch LETTER('a':'z')
:
:
LETTER('a'):
LETTER('e'):
LETTER('i'):
LETTER('o'):
LETTER('u'):
! Deal with the vowels here
:
LETTER(*):
! All the rest (i.e. the consonants)
:
Instead of using a constant to specify a specific element of a switch
vector, * can be used. It represents all the elements of the switch
vector not defined elsewhere. Note that it does not have to come after
the specifically defined switch labels.
10. Cycles
The permissible forms of cycle are these:
a) cycle (endless cycle) : repeat
b) while condition cycle : repeat
c) cycle : repeat until condition
d) for var = init, inc, final cycle : repeat
The unconditional instructions continue and exit can be used inside a
cycle of any type. continue causes a branch to the next repeat; exit
causes a branch to the statement following the next repeat.
Notes on the cycle types:
b) while cycles are executed zero or more times. When the cycle body
consists of a single statement, the form
statement while condition
can be used.
Example: SKIP SYMBOL while NEXT SYMBOL=' '
The IMP9 form while condition then statement is not allowed.
c) until cycles are executed one or more times. The simple form is
statement until condition
The IMP9 form until condition then statement is not allowed.
d) for cycles: the cycle variable must be of type integer; it should
not be changed explicitly within the cycle body; (final-init) must be
exactly divisible by inc; the cycle body is executed (final-init)//inc
+ 1 times or zero times, whichever is the greater; if the cycle body is
not executed the cycle variable is set to be unassigned. It follows
from this that a cycle starting
for I=10,1,8 cycle
will not be executed, but it will not be faulted either. This differs
from IMP9, where the equivalent form
cycle I=10,1,8
would be faulted.
The simple form of for is
statement for var = init, inc, final
Example: A(I)=0 for I=20,-1,1
[Going down in steps of -1 to 1 happens to be more efficient on EMAS 2900 than t
he more usual 1,1,20 form.]
11. start/finish blocks
The general form is
if cond 1 then start
:
:
finish else if cond 2 then start
:
:
finish else if cond n then start
:
:
finish else start
:
:
finish
Notes
* Every start matches with the next occurring finish. If they enclose
only one statement then they can be replaced by that statement.
Example: if cond 3 then start statement finish else if ....... can
be expressed as if cond 3 then statement else if .......
* then start can be replaced by start.
* if can be replaced by unless, the effect being to negate the
condition following.
* Any of the statements starting "finish else" in the general form
can be omitted, including the last one.
* If the condition controlling a start/finish block can be determined
at compile-time then the IMP80 compiler may do so, and might not
generate code for statements that cannot logically be executed.
This is known as "conditional compilation".
12. Constants
a) An integer constant of any integer base from 2 to 36 may be
specified. The form is
base_constant
where base is a decimal value and constant is an integer expressed with
respect to the base. The letters A, B, ..., Y, Z can be used to
represent the digits 10, 11, ..., 34, 35 in the integer.
Examples:
2_1010 ten in binary
8_12 ten in octal
16_A ten in hexadecimal
An alternative form is provided for binary, octal and hexadecimal
constants:
B'1010' ten in binary
K'12' ten in octal
X'A' ten in hexadecimal
b) Named constants
Variables of all types can be given the attribute constant. This can be
considered a special form of own variable, which cannot be changed from
its initial value. However it is probably better to consider such
variables as "named constants", since 1) this accords with their
intended use, i.e. for replacing arithmetic or string constants within
code by meaningful names; and 2) they do not have addresses, unlike
other variables (but like constants).
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
Example: constant integer NO=0, YES=1, INPUT=1, CALCULATION=2, OUTPUT=3
switch PHASE(INPUT:OUTPUT) : -> PHASE(OUTPUT) if DONE=YES : :
PHASE(OUTPUT): ! Now print the results :
13. Strings
a) The keyword string may always be followed by a length specification.
Thus string(10)array name ..... and string(255)name ....... are
permitted.
In EMAS 2900 IMP80, no use is made of the maximum length specification
for string name and string array name variables.
[In other IMP80 implementations, however, a string name variable must
have a maximum length specification and can only refer to ("be pointed
at") a string variable of the same maximum length. The forms
string(*)array name .....
string(*)name ............
are also provided, however, to enable declarations of reference
variables which can point at any string variable.]
b) The string function FROMSTRING is renamed SUBSTRING.
c) A string resolution of the form
S -> (A).B
succeeds in IMP9 only if string S starts with string expression A. In
IMP80, however, the resolution is interpreted as being equivalent to S
-> JUNK.(A).B where JUNK is a "hidden" string (255) variable; that is,
the resolution will succeed if A appears anywhere within S.
When converting an IMP9 program to IMP80, the following translation is
recommended:
if S -> (B).C then ... in IMP9
becomes if S -> NS1.(B).NS2 and NS1="" then C=NS2 and ... in IMP80
[NS1 and NS2 are new string (255) variables]
This translation is still valid when the IMP9 statement is
if S -> (B).S
i.e. when C is S.
Unconditional resolutions can normally remain unchanged; they might
succeed in IMP80 where they would fail in IMP9, but this is not
significant unless you are expecting them to fail.
14. Records
a) The syntax of declarations in IMP80 differ from those in IMP9. They
are of the form
record (format) ident, ...
record (format) array ident, ...
record (format) name ident, ...
record (format) array name ident, ...
"format" is either the name of a record format previously described,
the name of a record previously declared, or the actual record format
itself.
Example: record format RF(integer I, J, K) record (RF) R and record
(integer I, J, K) R
are both valid and have the same effect, except that the first version
declares a record format with identifier RF, which can be used
elsewhere, clash with other identifiers, etc. Either of the above forms
could be followed by the statement
record (R) P
which would declare a record with the same format as that of record R.
To summarise: the keyword record in IMP80 must be followed by the
keyword format or by a bracketed format or format reference or record
reference.
[This syntax change can cause difficulties when translating IMP9
programs: a routine spec such as
routine spec NAME1(record name NAME2, ...)
must now be converted to
routine spec NAME1(record (FORM2) name NAME2, ...)
The record format FORM2 is presumably declared somewhere in the
program, since a record of this format is required in order to call the
routine; but it might not be in scope at the routine spec statement,
and may have to be moved so that it is.]
record spec statements are not allowed in IMP80.
b) The syntax of record format statements has been extended to permit
alternative formats, i.e. to enable all or part of a record to be
interpreted in different ways.
Example: record format RF(integer A or byteinteger B, C, D or long real
E) record (RF) R
The record R can be considered to consist of an integer or three byte
integers or a long real. Each alternative starts at the same address.
Thus it follows that in
record format RF2 (byteintegerarray A(0:10) or c string(10) S) record
(RF2) R2
R2_A(i) holds the ith character of string R2_S.
Note that all the sub-fields in a record format must have distinct
identifiers.
In the first example above, the three alternatives were of different
sizes. This is permitted: the alternatives have padding bytes appended
to them to bring them up to the size of the largest. Thus when
calculating the size of a record, use the size of the largest
alternative.
When only part of a record is to have alternative formats, the
alternatives must be bracketed within the record format statement.
Example: record format RF3(integer TYPE, real RATIO, (byte integer
array A(1:20) c or string (10) S c or record (RF2) DATA), string(*)
name SN)
More than one set of alternatives can be given within a single record
format; in addition, they can be nested. Redundant brackets round
alternatives are allowed.
c) Records can contain records. The format of such a record must have
already been defined, or be explicit. [A record clearly cannot contain
a record with the same format as it itself has.]
Records can contain multi-dimensional arrays of fixed bounds, of any
type.
Records can contain record names. The format of such a record name can
be the same as that of the record containing it; thus
record format RF4(integer X, record (RF4) name NEXT)
is permitted.
15. external items
a) The IMP9 keyword extrinsic is replaced by external ... spec.
Example: extrinsic integer array A(1:500) in IMP9 becomes external
integer array spec A(1:500) in IMP80
External variables can be initialised, like own variables, in
declaration statements, but not in specification statements.
Example: external integer array A(1:500) = 25(10), 14(72), 16(22),
63(*)
b) External variables or procedures may be given an alias. The form
alias "..."
can follow the identifier name, in declaration statements or
specification statements.
Example: external real function spec SIN alias "MATH$DSIN"(real A)
The string constant specifies the string to be used for external
linkage (i.e. the external reference). From within the program the item
is referred to by its identifier, in the usual way.
16. Procedures as parameters
When a procedure has a procedure parameter the specification of the
latter is given in the parameter list, not in a subsequent spec
statement.
Example: routine X(integer Y, routine Z(real A), string (10) S)
John M. Murison