Blocks and Procedures

KEY

Block structure and storage

KEY IMP is a block-structured language. A block is a sequence of statements of which the first is %begin and the last is %end. The program itself is regarded as a block, and the first %begin encountered is interpreted as the start of the program. The statement %end %of %program, rather than %end, is used to indicate that the end of the program has been reached. Blocks may be nested to a depth determined by the particular implementation. Within each block, variables and constants to be used must be declared at the head of the block (and before any %on %event statement), unless they have already been declared at the head of an outer block. Labels and switch labels are always local to a block; thus it is impossible to jump from one block to another. Keywords which occur in pairs such as %cycle ... %repeat must have both elements within the same block.
Example: %begin %integer I, J %real %array A(1:10) : %real X, Y : : %begin %real Z, P I = 4 J = 10 : : %end : : %end %of %program
I and J have been declared at the head of the outermost block and may thus be referred to from any inner blocks of the program. If, however, a variable is declared which has the same identifier as a variable already declared in an outer block of the program, then use of that identifier will refer to the variable most recently declared. Example: %begin %integer I, J, K %real X, Y I = I+1 : : %begin %real I I = 4.106 :
: %begin X = I : : %end %end %end %of %program I is first declared as an integer type and will be allocated storage accordingly. The first use of I refers to this integer location. Within the next block, however, I is redeclared as a real variable. Now space is allocated for a real variable and within this block (and any deeper blocks of the program - unless I is again redeclared) use of I refers to the real location and the integer location of the outer block remains untouched.
When a variable is accessible it is said to be in scope. A variable is global to a block within the block in which it is declared, if it is accessible there. In the example above, X, Y, J and K are global to both inner blocks. The redeclaration of variables is permissible because of the way in which storage space is allocated to a program. Each program can be considered to have space allocated to it on what is called the stack. The stack is an area of store and the stack space given to each program has a prescribed layout, as shown in the following diagram.
stack pointer-----------\ | | _____________________________________________________________v________ | Program | Constants, |%own variables, | Cells in | Free \ | Code | %constant variables,|%own arrays | use | cells | | %constant arrays | | | ... |__________|______________________|________________|__________|________ \________________________________/ \___________________________________/ | | read only read and write The "read only" area contains the object code of the program as produced by the compiler, and also any of the constant variables declared by the program. This area cannot be altered during execution of the program. The "read and write" area has own variables stored first and thereafter space is allocated according to the requirements of the program. Each cell will be as big as is required by the entity stored in it: thus an integer variable occupies only a small cell, whilst a complex record variable may require a very large cell. The stack pointer holds the address of the next free location in store. Information stored on the stack is kept as compact as possible though with due regard for alignment considerations. This is of particular significance on paging machines, as it allows the program to run with a minimum number of page faults. The following example illustrates the stack mechanism. Example: %begin %real A,B,C %integer I,MAX %real %array X(1:3), Y(1:4)
As a result of the above declaration, the stack might look like this: ST1 ST2---\ | | v________________________________________________________________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 the stack pointer before the %begin, and ST2 is its position after the declarations. The shaded areas indicate portions of store which contain information essential to the program (such as array dimensions) but which cannot be accessed by the program. The stack pointer may be advanced by any further declarations or by activity initiated by the instructions of the program.
On entry to a new block or procedure, the stack pointer is advanced as necessary to cope with new declarations, etc. On exit from the block (or procedure) it returns to its last position prior to entry to that block (or procedure). Storage space for fixed variables such as %real or %integer types is determined at compile time, but arrays with dynamic bounds cannot be allocated space until the values of the bounds are determined at run time. Since the block structure of a program is so closely related to the allocation of store, skilful use of blocks can lead to economical use of store. Consider the following examples.
Example: %begin %integer N %cycle READ(N) %exit %if N=0 %begin %integer I %integer %array A(1:N) READ(A(I)) %for I=1,1,N : : %end %repeat %end %of %program
The required size of the array is read in the outer block and the array itself declared in the inner block. Thus the space used by any one set of data will be recovered when the inner block is left, so allowing one to repeat the process without incurring successively increasing demands for storage space. Example: %begin : : %begin %real %array XYZ(1:5000) : : %end :
: %begin %integer %array IJK(1:20, 1:250) : : %end : : %end 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 space. The above example illustrates the point. Procedures can be used in a similar way to economise on store.

Events

KEY During the execution of a program, events may occur which normally cause the program to terminate with an error message. However, there is a mechanism which allows events to be intercepted and used to control the subsequent execution of the program. This mechanism is activated by the use of the %on %event statement. The %on %event statement (which may occur only once in any block) is used to introduce a block of statements which is only executed if one of the specified events occurs. The form of the %on %event block is: %on %event <nlist> %start <executable instructions> %finish <nlist> is a list of integers in the range 1 to 14 inclusive, where each number refers to a specified class of error as follows:
1 Overflow 2 Excess resource 3 Data error 4 Invalid data 5 Invalid arguments 6 Out of range 7 Resolution failure 8 Undefined value 9 I/O error 10 Library procedure error (e.g. SQRT negative) 11-14 Available for user definition {EMAS IMP80: event 11 is used by the ERCC Graphics Package.} {IMP77: there are two extensions to the range of event numbers: Event 0 is defined - Termination Event 15 is available for user definition}
{IMP77: the form %on %event * %start is permitted. It is a shorthand way of specifying every event number; i.e. 0,1,...,14,15.} Up to 255 sub-events may be defined for each event, but these cannot be specifically intercepted and are necessarily implementation-dependent. For example, not all machines distinguish integer overflow from real overflow. Sub-events defined for some implementations are listed in Appendix B. The %on %event block must follow the declarations at the head of a block and may be regarded as the last declaration of the block. The code within the %start ... %finish is not executed by entry through the head of the block, but is jumped to on the occurrence, during the execution of the block, of an event referenced by the event list. Following such a jump, the flow of control is determined by the contents of the %on %event block; the program does not resume at the point of the failure. An event may be forced to occur by the instruction %signal %event <const>, <exprn> where <const> specifies the event required and <exprn> is an optional integer expression (evaluating to an integer within the range 0-255) which may be used to specify sub-event information. The use of the %signal %event statement is the only way of causing a user-defined event (i.e. one which is not pre-defined by the implementation) to occur, although it can also be used with the predefined events (1-10). If an event is forced by a %signal %event statement in an %on %event 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 an %on %event statement including the occurring event in its list is found, or the user environment is left. If a suitable %on %event statement is found, control is transferred to its %start ... %finish block. In parallel with these language statements, two standard integer functions are provided 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. %integer %function EVENT INF This function returns (event no<<8) ! sub-event no for the last event which has occurred. An error occurs at compile time if the function is called in a block with no %on %event statement, and an undefined value will result at run time if no event has in fact occurred when the function is called.
%integer %function EVENT LINE This function 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 undefined value will result. If an event is not intercepted 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 an outer 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.
Examples: %on %event 10 %start %if EVENT INF&255#8 %start %signal %event 10, EVENT INF&255 ! All subevents except 8 are passed to outer block %finish : : ! Code to deal with subevent 8 of event 10 : %finish
System defined events %integer SUBCLASS, EVENTNO %constant %string(21)%array MESSAGE(1:2) = %c "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)) %c %else PRINTSTRING("Invalid subclass") NEWLINE ->ERROR EXIT %finish : : ERROR EXIT: ....
User defined events %integer SUBEVENT %on %event 12 %start PRINTSTRING("Event 12 has been intercepted") NEWLINE ->EVENT 12 %finish : : SUBEVENT = 2 : : %signal %event 12, SUBEVENT : : EVENT 12: .....
{IMP77: a standard record map is provided to enable the programmer to determine further information when an event occurs. %record %format EVENT FM(%integer EVENT, SUB, EXTRA) %record(EVENT FM)%map EVENT EVENT returns a reference to a system-provided record which contains the parameters of the last event to have been signalled. If no event has been signalled all the fields of the record are set to zero. Consult Appendix B and documents relating to specific implementations of IMP77 for details of the information returned.} Note that the event mechanism is designed for intercepting the occasional event only - overheads are high if the %on %event statement is used frequently.

Procedures

KEY A procedure takes the form of a block in which the first %begin is replaced by the procedure heading. However, a procedure can only be entered by execution of a procedure call statement, whereas a block is entered when the %begin statement at the start of the block is executed. There are three forms of procedure - %routine, %function (or %fn) and %map. Example: %begin %integer %array A(1:40) : : %routine CLEARA %integer I A(I) = 0 %for I=1,1,40 %end {Of %routine CLEARA.} :
: CLEARA : : %end %of %program In this example, a procedure - routine CLEARA - is described and then used by means of the procedure call statement 'CLEARA'. CLEARA is effectively a named block: if the procedure heading were replaced by %begin and the procedure description moved down to take the place of the procedure call statement, the effect would be exactly the same. However, by making the block a routine - and thus giving it a name - it is possible to call it at different places in the program without repeating the description each time. In addition, procedures can have parameters, passed to them via a parameter list enclosed in brackets in the procedure call statement.
Example: %begin %integer F, T %string(31) %array A(0:99) %routine STRINGSORT(%string(*)%array %name X, %integer FROM, TO) %integer L, U %string(255) D : : %end {Of %routine STRINGSORT.} : : STRINGSORT(A, F, T) : : %end %of %program
In the above example, the procedure heading specifies the form of procedure (%routine) being described, gives the procedure the identifier STRINGSORT and describes the number, order and types of variables passed as parameters, using dummy names. The procedure is entered when the call statement STRINGSORT(A, F, T) is executed. The first line of a procedure has one of the following forms: %routine <name> (<parameter list>) <type> %function <name> (<parameter list>) <type> %map <name> (<parameter list>) where <type> is one of the arithmetic types, or %string(<n>) or %record(<format>), and (<parameter list>) is optional.
{EMAS IMP80: record functions and record maps are not available.} A procedure must be declared before it is called. If the procedure itself is placed at the head of a block (as above) no further declaration is needed. Otherwise a specification (%spec) statement must be placed amongst the other declarations at the head of a block, with the procedure included later at the same textual level. The %spec statement is exactly like the procedure heading with %spec inserted after the keyword %routine, %function or %map. Example: %routine %spec STRINGSORT(%string(*)%array %name X, %integer FROM, TO) It is most important to give the specification accurately: in particular, the number and types of the parameters must be correct. However, the names of the parameters in a specification statement are not significant.
Variables used in procedures may be declared locally (as is the case for L, U and D in the above example), but any information stored in them becomes inaccessible on exit from the routine. If the information calculated by the procedure is to be preserved for use on subsequent entries, it must be stored in global variables or %own variables declared locally. Global variables should be used with care in procedures. Note that such variables must be declared globally to the procedure itself: it is not sufficient that they be declared globally to the procedure call. Example: %begin %integer X, Y %routine CONVERT X = .... Y = .... %end
CONVERT : : %begin %integer X : : CONVERT : %end : : %end %of %program The routine CONVERT, which has no parameters, operates on variables X and Y. The first call of the routine uses X and Y as declared at the head of the program. The second call occurs from within an inner block in which X has been redefined. However, the procedure again uses the X declared at the head of the program, ignoring the redefined X of the inner block.
Information calculated by a procedure and stored in global variables is, of course, accessible on exit from the procedure. There are three categories of procedure which may be called by a program: 1) standard procedures, which are automatically available to all programs (see Section 7); for example, READ, INT PT; 2) procedures described within the program; 3) external procedures, which are compiled separately from the program (see Section 3.3). Procedures can be nested: that is, a procedure can be defined inside another procedure. The scope rules apply as before. Procedures can be used recursively: that is, a procedure can be called from within itself. The example in 3.2.1 of a sorting program demonstrated the recursive use of routine STRINGSORT. Obviously, some criterion within the body of the procedure must eventually prevent the procedure calling itself endlessly. In the example, the recursive calls of STRINGSORT are embedded in conditional instructions, thus providing the necessary opportunity to stop the recursion process.

Parameters

KEY When a procedure with parameters is described, the heading statement contains dummy names for the variables passed as parameters. These names are used in the description of the procedure and are referred to as "formal" names. When the procedure is executed, however, "actual" parameters take the place of the formal parameters, and are specified in the parameter list of the particular call. The parameters given in the procedure call must correspond in number, order and type with those specified by the procedure heading. Local storage is allocated within the procedure for each formal parameter. Parameters fall roughly into two categories - those passed "by value" and those passed "by name". When a procedure call is executed, parameters passed by value have their values assigned to the corresponding local variables. An arithmetic expression may thus be passed as a parameter: it will be evaluated before entry to the procedure and its value assigned to the appropriate formal parameter. On exit, it will become inaccessible and any information stored in it will be lost.
Example: %begin %real Z, Y %real %function AUX(%real X) : : %end : : Y = AUX(Z) : : Y = AUX(4.5*Z) : : %end %of %program
Function AUX has formal parameter X of type %real. Execution of the first call of the function will assign to X the value to be found in Z. On executing the second call, the expression 4.5*Z will be evaluated and the result assigned to formal parameter X. Parameters passed "by name", however, are treated differently. The local storage allocated for a parameter passed by name is a reference variable of the appropriate type. In this case, when a procedure call is executed, the effect is that the local variable is "pointed at" the actual parameter, which must therefore be the name of a variable, and not an expression. Thus, every reference in the procedure to the formal parameter is treated as if it were a reference to the actual parameter. Parameters passed by name can be used to preserve information calculated by the procedure, for use on exit.
Example: Given a procedure with heading %routine ALPHA(%integer BETA, %real %name GAMMA) the call ALPHA(J*K+4, R(M)) has the effect of causing the following assignments to be carried out on entry to the procedure: BETA = J*K + 4 GAMMA == R(M) (Note however that these two assignments as given may violate the normal rules for scope of names, because they use variables in scope at the point of the call to assign to variables local to the routine body.)
Example: %begin %constant %string (1) SNL = " " %string(31)%array NAMES(1:99) %routine %spec STRINGSORT(%string(*)%array %name X, %integer F, T) %integer I, N READ(N) %until 1 <= N <= 99; ! Reject if not in range. READSTRING(NAMES(I)) %for I=1,1,N STRINGSORT(NAMES,1,N) PRINTSTRING(NAMES(I).SNL) %for I=1,1,N %routine STRINGSORT(%string(*)%array %name X, %integer FROM, TO) %integer L, U %string(255) D %return %if FROM >= TO L = FROM; U = TO D = X(U) %cycle L = L+1 %while L < U %and X(L) <= D %exit %if L = U X(U) = X(L) U = U-1 %while U > L %and X(U) >= D %exit %if U = L X(L) = X(U) %repeat ! Now L = U. X(U) = D L = L-1; U = U+1 STRINGSORT(X,FROM,L) %if FROM < L STRINGSORT(X,U,TO) %if U < TO %end %end %of %program
This program sorts a set of strings held in array NAMES. Note the %routine %spec statement at the head of the block, with the routine description occurring later at the same textual level. There are three parameters passed to the %routine STRINGSORT; the two integers are passed by value, and the string array is passed by name. Arrays can only be passed by name, to prevent unnecessary allocation of storage space and time-consuming copying. When the routine is called the first time the parameters are treated as follows. The string array NAMES is passed by name and thus all references to the formal parameter X within the body of the routine become references to NAMES; the actual value 1 will be assigned to formal parameter F; and the value stored in N will be assigned to formal parameter T. On exit from the routine, NAMES will have its elements sorted, but the value of N will be unchanged.
Strings may be passed as parameters to procedures. Where a string name parameter is used, the length specified in the procedure heading can be replaced by * so that strings of any length (up to the allowed maximum) can be passed to that procedure. In this situation run-time overflow checking is applied to the actual string passed to the procedure. In IMP, parameters called by name are assigned at the time of call. Thus if a routine with parameter list (%realname X, %integername I, ...) were called with parameters (A(J), J, ...) where A is the name of a previously declared real array, then on execution of the procedure every reference to X will refer to the element of A determined by the value of J on entry, no matter how J varies during execution of the procedure. Procedures, too, may be passed as parameters:
Example: %begin %routine ONE(%routine PARAM(%integer X) ) : : %end %routine TWO(%integer P) : : %end %routine THREE(%real X) : : %end ONE(TWO) %end
Routine ONE has a single parameter, a routine with a single parameter of type %integer. Note that routine THREE cannot be passed as parameter to routine ONE because THREE has a parameter of type %real. That is, the parameter list of the actual procedure passed must correspond with the parameter list of the corresponding formal procedure parameter. To summarise: a formal parameter can be any of the following types: 1) any arithmetic type (e.g. %long %real, %short %integer) 2) %string(n) 3) %record(format) 4) any of the above followed by %array %name 5) any type of procedure (i.e %routine, %function of any type, %map of any type) Items (1) - (3) correspond to call by value; items (4) and (5) to call by name. The actual parameter in a call by value must be an expression of the appropriate type; in a call by name it must be a "reference" to an entity of the appropriate type.

Routines

KEY A routine call may be used exactly like an instruction. When the call is executed, control is transferred to the routine, which executes until either the %end statement is reached or a %return statement is encountered. Flow of control is resumed at the statement after the routine call. Example: : : %integer X,Y %routine CONVERT %if X < Y %start X = X+Y %finish %else %start X = X-Y %finish %end :
: CONVERT : : CONVERT %unless X = 0 : : Note that CONVERT uses global variables X and Y and that the result is stored in X on exit from the routine. Note also the use of CONVERT in a conditional statement.

Functions

KEY A function calculates a value of the specified type (integer, real, string or record), and may be used in an expression exactly like an operand of that type. The function terminates when an instruction of the form %result = <expression> is executed, and the value of the expression, which must be of the same type as that of the function, is returned to the statement making the call. {EMAS IMP80: record functions are not available.}
Example: %integer %function SUMSQ(%integer A, B) %result = A**2 + B**2 %end %integer X, Y, Z : : Z = SUMSQ(X,Y) - 3 : The use of global variables in functions may have unusual side effects. Such side effects can be difficult to detect and should be avoided.
Example: %begin %integer I, J, K %integer %function SIDE I = I+1 %result = J %end : K = I+SIDE : %end In the statement K = I+SIDE, there is no defined order of evaluation of operands in the expression on the right hand side of the assignment, but the value of I used in the expression depends upon the order of evaluation. Thus the value of the expression is indeterminate. The actual value computed depends on the implementation of IMP80 used.
Functions may be of %string type; in this case the maximum length of the string which may be returned by the function is included in the specification and heading of the function. Example: %string(20)%function FIELD(%integer I) Functions may be of %record type; in this case the format of the record returned must be included in the specification and heading of the function. Example: %record %format RFA(%integer ONE, TWO, THREE) %record (RFA) %function TRIPLES(%integer ITEM) : {EMAS IMP80: record functions are not available.}

Maps

KEY A map (or "mapping function") calculates a reference to a variable of the specified type (integer, real, string or record) and may be used exactly like a variable of that type. The map terminates when an instruction of the form %result == <ref to a variable of the same type as the map> is executed and the address of the given variable is returned to the calling instruction. The "reference to a variable" on the right hand side of the %result statement can be a normal variable, a reference variable or a mapping function call. {EMAS IMP80: programmer-written record maps are not available.} {EMAS IMP80: a %result statement in a map can be of the form %result = integer expression where the integer expression gives the address of some location. It usually includes a call of the function ADDR, described in Section 6.}
{IMP77: the keyword %map may be replaced by %name %function or %name %fn.} Example: %integer X, Y, K %integer %map MIN %if X < Y %then %result == X %else %result == Y %end MIN = 0 ! This statement is exactly equivalent to ! %if X < Y %then X = 0 %else Y = 0 : K = MIN : Note the use of a map on the left-hand side or right-hand side of an assignment statement.
Where a map is of %string type, the specification and heading must include a length - the precise maximum length of any string to which the map may refer. Example: %string(3)%map XA(%integer I) If a string map might refer to strings of varying length, then the procedure heading and declaration may have the symbol '*' in place of a specific length. The map may then reference strings of any length up to the allowed maximum. Example: %string(*)%map XA(%integer I) : Where a map is of %record type, the specification and heading must include a record format. The right hand side of a %result statement within a record map must refer to a record of the same type as the map, or to the standard record map RECORD (described in Section 6).
Example: %record %format RF(%integer X, %string(10) TITLE) %record (RF) %map RM(%integer I, J) %record (RF) %name CURRENT : CURRENT == ... : : %result == CURRENT %if ... : %end {Of %record %map RM %string(15) HEAD %integer P, Q : HEAD = RM(P,Q+1)_TITLE : RM(17,3)_X = 24.6 :
{EMAS IMP80: programmer-written record maps are not available. However, a standard record map RECORD is provided; it is described in Section 6.} {IMP77: the record format given in the specification or heading can be replaced by (*), meaning that the reference returned by the map may be to a record of any format; the actual record format used depends on the context. Example: %record(*)%map SURVEY(%integer I, %real X) The standard map RECORD (described in Section 6) is of this sort.} A number of standard maps are provided. These are described in Section 6.

External linkage

KEY A complete program may be divided into separately compiled modules which are linked before (or possibly while) the program is executed. This section describes the language facilities provided for setting up or accessing a separately compiled module. A procedure compiled separately from a program which uses it is called an external procedure. If a program uses an external procedure it must contain an external specification statement. This is of the same form as the %spec statement described in Section 3.2, but with the prefix %external. Example: %external %string(*) %function %spec I TO S(%integer A) An %external...%spec statement has the same effect as a normal %spec, except that there is no description of the procedure later in the program. %external ... %spec statements may be given wherever other %spec statements would be valid.
The keywords %system and %dynamic may be used in place of %external; refer to the relevant system documentation for details of the effects of these keywords. External variables are also available. If a program uses an external variable it must include an external specification. This is of the same form as the variable declaration statement but with the keywords %external and %spec added. Examples: %external %integer %spec WAIT, CHOICE %external %real %array %spec MEAN(-6:6)

External files

KEY A file of external procedures and variables may be compiled. Such a file differs from the structure of a program file (described in Section 1.2) in several respects: * There is no initial %begin. * %end %of %program is replaced by %end %of %file. * Variables declared outside any procedures must be %own, %constant or %external (described below). * The first statement of any procedure description can be preceded by the keyword %external; such a procedure can then be made accessible to other programs, as explained above. If a procedure in the file is not %external then it is accessible only within the file, in accordance with the normal scope rules.
* %begin/%end blocks are not allowed, except within procedures. {IMP77: a single %begin/%end block at the outer level is allowed, so long as it immediately precedes the %end %of %file statement. The block's %end statement and the %end %of %file statement can then be replaced by the single statement %end %of %program.} * Where an %external ... %spec statement in the file specifies an external procedure or variable described later in the same file, the keyword %external may be omitted. An %external variable has all the properties of an %own variable, but is declared with the keyword %own replaced by %external. Examples: %external %integer CHOICE = 6, WAIT = -5 %external %real %array MEAN(-6:6) = 2.7(5),0.3,1.5(*)
External variables can be declared in an external file or in a normal program file, wherever other declarations are valid. They are normally declared in the outer block of an external file. Note that external variables may be initialised, like %own variables, when they are declared, but not when they are specified in an %external ... %spec statement.

Example of an external file

KEY %external %integer IN=0, OUT=0 %routine GET(%integername SYM) READSYMBOL(SYM) IN = IN+1 %end %routine PUT(%integer SYM) PRINTSYMBOL(SYM) OUT = OUT+1 %end %external %routine PROCESS %integer CH : GET(CH) %until CH='*' : PUT(CH) : %end {Of PROCESS} %end %of %file
A program making use of the external file: %begin %external %routine %spec PROCESS %external %integer %spec IN, OUT %integer DATA, DMAX : %for DATA = 1,1,DMAX %cycle IN = 0; OUT = 0 PROCESS PRINTSTRING("Calculation no.") WRITE(IN,1) PRINTSTRING(" characters in;") WRITE(OUT,1) PRINTSTRING(" characters out.") NEWLINE %repeat : : %end %of %program

%alias

KEY Any identifier given in an %external declaration or specification may be followed by %alias string constant, where the string constant specifies the string to be used for external linkage. This has no effect on the use of the identifier within the program. Examples: %external %long %real %fn %spec EIGENVALUE %alias %c "D#REFEIGEN$" (%long %real %array %name MAT) %external %integer RESULT %alias "ICL9CERETURN" = 4