<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>&ge;</td><td rowspan="8">5</td><td>int</td><td>int</td><td>bool</td><td></td></tr><tr><td>&gt;=</td><td>real</td><td>real</td><td>bool</td><td></td></tr><tr><td rowspan="7">ge</td><td>real</td><td>int</td><td>bool</td><td></td></tr><tr><td>int</td><td>real</td><td>bool</td><td></td></tr><tr><td>bits</td><td>bits</td><td>bool</td><td></td></tr><tr><td>char</td><td>char</td><td>bool</td><td></td></tr><tr><td>string</td><td>string</td><td>bool</td><td></td></tr><tr><td>string</td><td>char</td><td>bool</td><td></td></tr><tr><td>char</td><td>string</td><td>bool</td><td></td></tr><tr><td>bytes</td><td>bytes</td><td>bool</td><td></td></tr><tr><td>=</td><td rowspan="15">4</td><td>bool</td><td>bool</td><td>bool</td><td></td></tr><tr><td rowspan="10">eq</td><td>int</td><td>int</td><td>bool</td><td></td></tr><tr><td>real</td><td>real</td><td>bool</td><td></td></tr><tr><td>compl</td><td>compl</td><td>bool</td><td></td></tr><tr><td>real</td><td>int</td><td>bool</td><td></td></tr><tr><td>int</td><td>real</td><td>bool</td><td></td></tr><tr><td>compl</td><td>int</td><td>bool</td><td></td></tr><tr><td>compl</td><td>real</td><td>bool</td><td></td></tr><tr><td>int</td><td>compl</td><td>bool</td><td></td></tr><tr><td>real</td><td>compl</td><td>bool</td><td></td></tr><tr><td>bits</td><td>bits</td><td>bool</td><td></td></tr><tr><td>char</td><td>char</td><td>bool</td><td></td></tr><tr><td>string</td><td>string</td><td>bool</td><td></td></tr><tr><td>string</td><td>char</td><td>bool</td><td></td></tr><tr><td>char</td><td>string</td><td>bool</td><td></td></tr><tr><td>bytes</td><td>bytes</td><td>bool</td><td></td></tr><tr><td>‡</td><td rowspan="10">4</td><td>bool</td><td>bool</td><td>bool</td><td></td></tr><tr><td rowspan="10">ne</td><td>int</td><td>int</td><td>bool</td><td></td></tr><tr><td>real</td><td>real</td><td>bool</td><td></td></tr><tr><td>compl</td><td>compl</td><td>bool</td><td></td></tr><tr><td>real</td><td>int</td><td>bool</td><td></td></tr><tr><td>int</td><td>real</td><td>bool</td><td></td></tr><tr><td>compl</td><td>int</td><td>bool</td><td></td></tr><tr><td>compl</td><td>real</td><td>bool</td><td></td></tr><tr><td>int</td><td>compl</td><td>bool</td><td></td></tr><tr><td>real</td><td>compl</td><td>bool</td><td></td></tr><tr><td>bits</td><td>bits</td><td>bool</td><td></td></tr><tr><td>char</td><td>char</td><td>bool</td><td></td></tr><tr><td>string</td><td>string</td><td>bool</td><td></td></tr><tr><td>string</td><td>char</td><td>bool</td><td></td></tr><tr><td>char</td><td>string</td><td>bool</td><td></td></tr><tr><td>bytes</td><td>bytes</td><td>bool</td><td></td></tr><tr><td>^</td><td rowspan="2">3</td><td>bool</td><td>bool</td><td>bool</td><td></td></tr><tr><td>&amp; and</td><td>bits</td><td>bits</td><td>bits</td><td></td></tr><tr><td>V</td><td rowspan="2">2</td><td>bool</td><td>bool</td><td>bool</td><td></td></tr><tr><td>or</td><td>bits</td><td>bits</td><td>bits</td><td></td></tr></tbody></table>

Vertical readers, please turn to 7.1.
## 6.2. Constants and procedures

### 6.2.1. Constants

With the exception of *pi*, the purpose of these constants is to give information about the implementation upon which the program is being run, and they are therefore called "environment enquiries". They are all declared in the standard-prelude [R 10.2.1], by means of identity-declarations, to be of some mode such as **int** or **real**. Hence they are not names, and hence they cannot be altered by the user.

Some further environment enquiries are given in 6.7.1 (in connection with long modes) and in 7.2.2 and 7.5.3 (in connection with transput).

<table><thead><tr><th>identifier<br>of constant</th><th>mode</th><th>value</th></tr></thead><tbody><tr><td>max int</td><td>int</td><td>the largest int value which can be represented</td></tr><tr><td>max real</td><td>real</td><td>the largest real value which can be represented</td></tr><tr><td>small real</td><td>real</td><td>the smallest real value which can be meaningfully added to or subtracted from 1</td></tr><tr><td>bits width</td><td>int</td><td>the number of bits in bits (see 2.7.1)</td></tr><tr><td>bytes width</td><td>int</td><td>the number of chars in bytes (see 2.7.1)</td></tr><tr><td>max abs char</td><td>int</td><td>the largest value which abs of a char can yield</td></tr><tr><td>null character</td><td>char</td><td>some character (see bytespack in 6.2.2)</td></tr><tr><td>blank</td><td>char</td><td>"_" (the space character)</td></tr><tr><td>pi</td><td>real</td><td>π</td></tr></tbody></table>

### 6.2.2. Procedures

The following procedures are all declared within the standard-prelude [R 10.2.3.12, 10.5.1] to be of some mode **proc amode**, rather than **ref proc amode**. Hence they cannot be altered by the user. Their meanings are those generally accepted, or as specified by the last column of the following table.

Further procedures from the standard-prelude are to be found in 6.7.2, 7.1.1, 7.1.2, 7.2.3, 7.2.4, 7.2.5, 7.4.2, 7.4.3, 7.5.1, 7.6.3 and 7.7.1.
<table><thead><tr><th>identifier of proc</th><th>mode</th></tr></thead><tbody><tr><td><code>sqrt</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>exp</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>ln</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>cos</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>arccos</code></td><td><code>proc/real/real</code><br><code>0 &le; arccos(x) &le; &pi;</code></td></tr><tr><td><code>sin</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>arcsin</code></td><td><code>proc/real/real</code><br><code>-&pi;/2 &le; arcsin(x) &le; &pi;/2</code></td></tr><tr><td><code>tan</code></td><td><code>proc/real/real</code></td></tr><tr><td><code>arctan</code></td><td><code>proc/real/real</code><br><code>-&pi;/2 &le; arctan(x) &le; &pi;/2</code></td></tr><tr><td><code>next random</code></td><td><code>proc(ref int a)/real</code><br><code>The next int value after a from a pseudo-random sequence uniformly distributed in the range 0 &le; a &le; max int is assigned to a. The yield is a real value x (0 &le; x &lt; 1) obtained by means of some uniform mapping from a (such that x is also pseudo-random and uniformly distributed)</code></td></tr><tr><td><code>last random</code></td><td><code>ref int</code><br><code>an int variable, initialised to <code>round(max int/2)</code>, which is used by <code>random</code> (below)</code></td></tr><tr><td><code>random</code></td><td><code>proc real</code><br><code>a call of <code>next random</code>, using <code>last random</code> as parameter</code></td></tr><tr><td><code>bitspack</code></td><td><code>proc/[] bool a/bits</code><br><code>the multiple a, made up with <code>fales</code> at the left, is turned into bits</code></td></tr><tr><td><code>bytespack</code></td><td><code>proc(string a)/bytes</code><br><code>the string a, made up with <code>null characters</code> (6.2.1) on the right, is turned into bytes</code></td></tr></tbody></table>

See 6.7.2 for long(s) versions of these.

Vertical readers, please turn to 7.2.
## 6.3. Assigning operators

The operators in the following table all have the property that the result of the operation is automatically assigned to the name of the left hand operand, and this name is yielded as the value of the formula. Thus:

(E1) $a$ plusab $b$ or $a + := b$ $c$ means the same as $a := a+b c$

(E2) $x := a$ plusab $b$ $c$ means the same as $x := a := a+b c$

(E3) $a$ minusab $b$ plusab $c$

E3 has implied bracketing:

(E4) $(a$ minusab $b)$ plusab $c$ $c$ and therefore means $a := a-b$; $a := a+c c$

(E5) $a$ plusab $b := x$

E5 is legitimate example of a formula on the LHS of an assignation, but it is not very sensible since $b$ does not enter into the result.

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>timesab<br/>x:=<br/>*:=</td><td>1</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl<br/>ref string</td><td>int<br/>real<br/>compl<br/>int<br/>int<br/>real<br/>int</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl<br/>ref string</td><td>a := axb<br/>a := axb (x implying replication)</td></tr><tr><td>overab<br/>÷:=<br/>%:=</td><td>1</td><td>ref int</td><td>int</td><td>ref int</td><td>a := a÷b</td></tr><tr><td>divab<br/>/:=</td><td>1</td><td>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl</td><td>real<br/>compl<br/>int<br/>int<br/>real</td><td>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl</td><td>a := a/b</td></tr><tr><td>modab<br/>÷x:=<br/>÷*:=<br/>%x:=<br/>%*:=</td><td>1</td><td>ref int</td><td>int</td><td>ref int</td><td>a := a mod b</td></tr></tbody></table>
<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>plusab<br/>+:=</td><td>1</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl<br/>ref string<br/>ref string</td><td>int<br/>real<br/>compl<br/>int<br/>int<br/>real<br/>string<br/>char</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl<br/>ref string<br/>ref string</td><td>a := a+b<br/>} a := a+b (+ implying concatenation)</td></tr><tr><td>plusto<br/>+:=</td><td>1</td><td>string<br/>char</td><td>ref string<br/>ref string</td><td>ref string<br/>ref string</td><td>b := a+b</td></tr><tr><td>minusab<br/>-:=</td><td>1</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl</td><td>int<br/>real<br/>compl<br/>int<br/>int<br/>real</td><td>ref int<br/>ref real<br/>ref compl<br/>ref real<br/>ref compl<br/>ref compl</td><td>a := a-b</td></tr></tbody></table>

Vertical readers, please turn to 8.3.
## 6.5. Interrogations

The following table specifies the operators introduced informally in 5.5.3. Note that `amode` stands for any mode and `“,s”` stands for any number of commas (including none).

### 6.5.1. Dyadic operators

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>lwb</td><td>8</td><td>int</td><td>[,s] amode</td><td>int</td><td>the lower bound of the a<sup>th</sup> subscript of b</td></tr><tr><td>upb</td><td>8</td><td>int</td><td>[,s] amode</td><td>int</td><td>the upper bound of the a<sup>th</sup> subscript of b</td></tr></tbody></table>

### 6.5.2. Monadic operators

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>lwb</td><td>10</td><td>[,s] amode</td><td>int</td><td>lwb<sub>a</sub></td></tr><tr><td>upb</td><td>10</td><td>[,s] amode</td><td>int</td><td>lupb<sub>a</sub></td></tr></tbody></table>

Vertical readers, please turn to 7.5.
## 6.7. Long operators

### 6.7.1. Environment enquiries

The numbers of different lengths and shorths of **ints**, **reals**, etc. that are provided may vary between different implementations. Environment enquiries (6.2.1) are therefore provided to indicate these numbers [R 10.2.1]. Additionally, the environment enquiries introduced in 6.2.1 (*max int*, etc.) and in 7.5.3 (*int width*, etc.) have long versions of themselves. Note that the number of different “lengths” or “shorths” of each mode includes none at all, so that if the implementation distinguishes just **short int**, **int** and **long int**, then both **int lengths** and **int shorths** will have the value 2.

<table><thead><tr><th>identifier<br>of constant</th><th>mode</th><th>value</th></tr></thead><tbody><tr><td>int lengths</td><td>int</td><td>the number of different lengths of ints</td></tr><tr><td>int shorths</td><td>int</td><td>the number of different shorths of ints</td></tr><tr><td>real lengths</td><td>int</td><td>the number of different lengths of reals<br>(and of compIs)</td></tr><tr><td>real shorths</td><td>int</td><td>the number of different shorths of reals<br>(and of compIs)</td></tr><tr><td>bits lengths</td><td>int</td><td>the number of different widths of bits</td></tr><tr><td>bits shorths</td><td>int</td><td>the number of different shorths of bits</td></tr><tr><td>bytes lengths</td><td>int</td><td>the number of different widths of bytes</td></tr><tr><td>bytes shorths</td><td>int</td><td>the number of different shorths of bytes</td></tr><tr><td>long max int</td><td>long int</td><td>the largest long int value which can be<br>represented</td></tr><tr><td>long long max int<br>long long long<br>max int</td><td>long long int</td><td></td></tr><tr><td>long(s) max real</td><td>long(s) real</td><td>the largest long(s) real value which can be<br>represented</td></tr><tr><td>long(s) small real</td><td>long(s) real</td><td>the smallest long(s) real value which can be<br>meaningfully added to or subtracted from 1.</td></tr><tr><td>long(s) bits width</td><td>int</td><td>the number of bits in long(s) bits</td></tr><tr><td>long(s) bytes<br>width</td><td>int</td><td>the number of chars in long(s) bytes</td></tr><tr><td>long(s) int width</td><td>int</td><td>the number of decimal digits required to re-<br>present long(s) max int - not including sign</td></tr><tr><td>long(s) real width</td><td>int</td><td>the number of decimal digits required to re-<br>present a mantissa, such that long(s) small real<br>is not neglected in comparison with 1 - not<br>including sign</td></tr><tr><td>long(s) exp width</td><td>int</td><td>the number of decimal digits required to re-<br>present a decimal exponent, such that long(s)<br>max real can be correctly represented - not<br>including sign</td></tr><tr><td>long(s) pi</td><td>long(s) real</td><td>π</td></tr></tbody></table>
## 6.7.2. Procedures

The procedures introduced in 6.2.2 [R 10.2.3.12, 10.5.1] also have their long and short versions. Note that a procedure with, for example, a long long real formal-parameter yields a value whose mode has exactly the same number of longs in it.

<table><thead><tr><th>identifier<br>of proc</th><th>mode</th></tr></thead><tbody><tr><td>long sqrt</td><td>proc/long real/long real</td></tr><tr><td>long long sqrt</td><td>proc/long long real/long long real</td></tr><tr><td colspan="2">and so on. We shall adopt the same abbreviation as before.</td></tr><tr><td>long(s) exp</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) ln</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) cos</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) arccos</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) sin</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) arcsin</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) tan</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) arctan</td><td>proc/long(s) real/long(s) real</td></tr><tr><td>long(s) next random</td><td>proc/ref long(s) int/long(s) real</td></tr><tr><td>long(s) last random</td><td>ref long(s) int ... initialized to round(long(s) max int/2)</td></tr><tr><td>long(s) random</td><td>proc long(s) real ... which uses long(s) last random: see 6.2.2</td></tr><tr><td>long(s) bitspack</td><td>proc/[ ]bool/long(s) bits</td></tr><tr><td>long(s) bytespack</td><td>proc/string/long(s) bytes</td></tr></tbody></table>

## 6.7.3. Operators

Most of the operators introduced in 6.1.1, 6.1.2 and 6.3 have their long(s) and short(s) counterparts [R 10.2.3]. We shall not list them all here; instead we shall give you a rule for working them out yourself.

Each operator has one or two parameters and a result, each being of some mode. If one or more of these modes is:

int, real, compl bits or bytes

then new version of that operator can be obtained by inserting long(s) or short(s) in front of each of those modes. However, the modes bool, char and string, wherever they occur, must be left strictly alone.

For example, one of the versions of the operator "+" can be used to add a real to an int yielding a real (6.1.2). There therefore exists another version which adds a long long real to a long long int yielding a long long real (but not to add a long long real to a long int yielding a real — the number of longs
added must be the same throughout). Likewise, a short real can be added to a short int yielding a short real.

However, there are certain exceptions to this general rule, all of which are concerned with not allowing long(s) ints in places where they would clearly be ridiculous. Thus:

* The abs of a char yields a (single) int

* The repr of a (single) int yields a char

* long(s) ints, reals and compls can be raised to a (single)

* int power, yielding correspondingly long(s) ints etc.

* strings and chars can be replicated a (single) int number of times

* using x, * or timesab

* The (single) int th element of a long(s) bits or bytes

* yields a bool or a char

* The level of a (single) int yields a sema and vice versa (3.7.2)

In all of these, the phrase "(single) int" implies int where long(s) int or short(s) int might otherwise have been expected.

### 6.7.4. leng and shorten

There are no coercions provided in the language for converting, for example, ints into long ints or vice versa. Instead, you are provided with the monadic-operators `leng` and `shorten` (see 8.4.2 for a meaningful example of their use):

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>leng</td><td>10</td><td>long(s) int<br>long(s) real<br>long(s) compl<br>long(s) bits<br>long(s) bytes</td><td>long long(s) int<br>long long(s) real<br>long long(s) compl<br>long long(s) bits<br>long long(s) bytes</td><td>the longer value<br>equivalent to a<br>making up with<br>falses at the left<br>making up with null<br>characters (6.2.1) on<br>the right</td></tr><tr><td>shorten</td><td>10</td><td>long long(s) int<br>long long(s) real<br>long long(s) compl<br>long long(s) bits<br>long long(s) bytes</td><td>long(s) int<br>long(s) real<br>long(s) compl<br>long(s) bits<br>long(s) bytes</td><td>the shorter value<br>equivalent to a,<br>if it exists<br>truncating on the<br>left<br>truncating on the<br>right</td></tr></tbody></table>
In this table, as usual, "long(s)" means **long** or **short** repeated zero or more times (but the same number of times in each column). Also, of course, **leng** of a **short short int** yields a **short int**, **leng** of a **short int** yields an **int**, and so on. Note that if you try to **shorten**, for example, a **long int** which is greater than *max int* (6.2.1), then the result is undefined.

### 6.7.5. up and down

The operators **up**, **down** and **level**, as applied to **semas**, were defined in 3.7.2.

**Vertical readers**, please turn to 7.7.
# 7. TRANSPUT

## 7.1. Formatless transput

"Transput" is the name given to all those operations which communicate with the environment. These include input, output and transfers to backing media such as magnetic tape and discs.

There is a large variety of transput facilities provided to suit the user's taste, ranging from the simplest formatless transput described in this section, through the facilities for accessing various types of device (7.2) and for dealing with exceptional situations (7.4.4) up to the formatted transput described in 7.6 and the binary transput in 7.7.

### 7.1.1. Formatless output

Formatless output is achieved by means of the procedure *print*, e.g.:

(E1) `print(x); print(i+3); print(p & i<j); print("A");`
`print("ABC"); print(x iy); print.bin 5; print(r)`

The modes of the actual-parameters in these examples are, respectively, **real**, **int**, **bool**, **char**, **string**, **compl**, **bits** and **bytes** (for a description of the mode **string** see 2.5.3 and 5.5.1.1, for **compl** see 2.4.4 and 5.4.3 and for **bits** and **bytes** see 2.7.1 and 5.7.1.1). In addition, multiple values (1.5.1, 2.5) and structures (1.4.1, 2.4) made up of any of these modes can be used. The actual-parameter of this procedure is a firm unit (the firmness arises from the particular way in which it is defined in the standard-prelude), which means that widening is not allowed, but dereferencing is. Note that it is not possible to output names (i.e. modes beginning with **ref**), or **formats** (7.6.2) or routines.

It is possible to output more than one item with one call on *print*:

(E2) `print((x, i+3, p & i<j, "A", "ABC", x iy, bin 5, r))`

which is equivalent to the series of separate *prints* in E1 above. Note the additional parentheses (these are required because the "data list" of items is really a row-display (see 3.5.1)).

The following layout procedures [R 10.3.1.6] may be called upon in between calls of *print*:
<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>newpage</td><td>proc(ref file)/void</td><td>continue printing at the beginning of the next page</td></tr><tr><td>newline</td><td>proc(ref file)/void</td><td>continue printing at the beginning of the next line</td></tr><tr><td>space</td><td>proc(ref file)/void</td><td>skip one character (which results in a space character unless cunning use has been made of backspace)</td></tr><tr><td>backspace</td><td>proc(ref file)/void</td><td>move back one character (but not beyond the start of the current line). A subsequent call on print will overwrite whatever character was previously there (but a call on space will not).</td></tr></tbody></table>

These layout procedures (and other `proc(ref file)/voids` (see 7.2.5) written by the user) may also be called upon within a `print` call. Thus:

(E3) `print((newpage, "HEADING", newline, "X = ", x))`

means the same as:

(E4)
* `newpage(stand out);`
* `print("HEADING");`
* `newline(stand out);`
* `print(("X = ", x))`

The `stand out` parameter specifies the `file` (see 7.2.1) to be affected. The `file stand out` is automatically implied by `print`, and is therefore supplied as the parameter of these routines when they are called from within it.

When `print` is called, the mode of each item to be printed is identified, and appropriate action taken as follows:

**ints, reals, compls:**

If there is not room for the item on the current line (page), then `newline` (`newpage`) is called. Then the item is printed, preceded by a space (if not at the beginning of a line), allowing sufficient positions to cope with the largest permissible value of that mode.

Examples are:
```
+123456
+456
-1
+0
+1.2345610+11
-6.5432110-2
+1.2345610+11 ⊥-6.5432110-2
```

chars, bools:

newline or newpage is called if necessary as above, and then the item is output with no preceding space. The (single) characters to be printed for true and false are to be decided by the implementer (see 7.5.3). In this book we use T and F.

strings, bytes, bits:

These are treated as sequences of chars or bools as appropriate, newline and newpage are called wherever required (and thus a string may get split over a line - but see 7.4.4 for how to control this).

If an item is a multiple (structure), then its component elements (fields) are output in turn according to the above rules. This is discussed more fully in 7.5.1 (7.4.1) under the heading of "straightening".

For those who prefer it, the procedure write may be used instead of print.

### 7.1.2. Formatless input

This is achieved by means of the procedure read, e.g.:

(E5) `read (x); read (i); read (p); read (c); read (s); read (z); read (t); read (r)`

The modes of the actual-parameters in these examples are, respectively:

ref real, ref int, ref bool, ref char, ref string, ref compl, ref bits, ref bytes

In addition, references to multiples and references to structures made up of any of the modes referred to can be used. The actual-parameter is in fact a firm unit, which means that.

(E6) `read (xx)`

is allowed, where `xx` is of mode `ref real` and must be dereferenced once.
The quantity actually input, of course, is of mode real, int, etc. The actual-parameter yields the name of the place where it is to be put. Note that it is not possible to input names, or formats, or routines or unions (1.6, 2.6).

It is possible to input more than one item with one call on *read*:

(E7) `read((x, i, p, c, s, z, t, r))`

which is entirely equivalent to the series of separate *reads* given above. Note the additional parentheses (these are required because the "data list" of items is really a row-display (see 3.5.1)).

The following layout procedures [R 10.3.1.6] may be called upon in between calls of *read*:

<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>newpage</td><td>proc(ref file)/void</td><td>ignore the rest of the current page and start reading the next</td></tr><tr><td>newline</td><td>proc(ref file)/void</td><td>ignore the rest of the current line, and start reading the next</td></tr><tr><td>space</td><td>proc(ref file)/void</td><td>ignore the next character</td></tr><tr><td>backspace</td><td>proc(ref file)/void</td><td>move back one character (but not beyond the start of the current line). A subsequent call on <i>read</i> will yield the last character again</td></tr></tbody></table>

These layout procedures (and other `proc(ref file)/voids` (see 7.2.5) written by the user) may also be called upon within a call of *read*. Thus:

(E8) `read((newpage, s, newline, x))`

means the same as:

(E9) `newpage(stand in);`
`read(s);`
`newline(stand in);`
`read(x)`

The `stand in` parameter specifies the *file* (see 7.2.1) to be affected. The *file* `stand in` is automatically implied by *read*, and is therefore supplied as the parameter of these routines when they are called from within it.

When *read* is called, the mode of each item required is identified, and appropriate action taken as follows:

*ints*, *reals*, *compls*, *bools*:

The input stream is searched for the first character that is not space (`newline`
and *newpage* being called as necessary). When it is found, the required item is read in (note that when **real** is called for, an **int** will suffice). If no recognisable item is found, then the result is undefined (unless the user has called the **on char error** procedure (see 7.4.4.7)). The following examples are acceptable:

```
+123456
+  456
+456
-1
123456
12.3456
.3456
-  12.34
1.2345610+11
1.23456e-2
121012
12.3411.234561012
T (for true)
F (for false)
```

“i” may be accepted in place of “|”, and “e” or “\” in place of “10”.

**chars:**

The next-character (possibly space) is read from the input stream, *newline* or *newpage* being first called if necessary.

**strings** (i.e. *flex* [ ] *chars*):

Characters are read from the current position until either the end of the current line is reached, or (if the user has called *make term* (see 7.4.2)) one of the terminating characters is found (this character is not yielded as part of the **string**, but will be read by the next *read*). If you do not want to have the **string** stopped by the end of the line (but only by the *term*), you may call the **on line end** procedure (7.4.4.4) so as to call *newline* automatically. If the current position is already at the end of the line (or if the line is empty), *newline* is not called – you just get an empty **string**. On the other hand, *newpage* will be called if you are off the end of the page.

**[m : n] chars** (i.e. a multiple with fixed bounds), **bytes** and **bits**:

The exact number of **chars** needed (i.e. *n*-*m*+1 or *bytes width* or *bits width*)
is read, newline and newpage being called as needed. In the case of bits, spaces are skipped (as with bools).

If an item refers to a multiple value (structure), then its component elements (fields) are sought in turn according to the above rules. This is discussed more fully in 7.5.1 (7.4.1) under the heading of "straightening". The number of elements expected in a multiple value (other than a string) is the number contained in the existing multiple referred to by the item.

Vertical readers, please turn to 8.1.

## 7.2. Files

### 7.2.1. Channels, books and files

Your particular-program communicates with its environment via facilities termed "channels" [R 10.3.1.2]. A channel may be anything from a keyboard to a wind tunnel, with all the usual peripherals (tape, cards, magnetic tape, discs) coming in between. In a large operating system, it will most likely turn out to be a file in its filestore. We distinguish between "character transput" (in which the external representation of the data is potentially readable) and "binary transput" (in which it is not, and which we shall not consider until 7.7).

Confining ourselves, then, to character transput (although some channels may be able to accommodate both varieties), it is convenient to imagine that at the other end of the channel is a "book" (or maybe several books). Some channels permit the program to read the book, and some to write in it. Some very accommodating ones will permit both, and may even allow you to browse through the pages in any order. A program connected to several paper tape readers would be reading several such books through one channel (a channel is thus a type of device, rather than an individual piece of hardware). This channel would presumably permit reading (*get possible*), forbid writing (*put possible*), would insist that the book be read in strict sequence (*reset possible* and *set possible*) but might conceivably agree to provide data in binary (*bin possible*).

A book has pages, lines and characters, the maximum number of each of which may be limited by the channel, although the actual book may be smaller. If a line is able to accommodate *n* characters, then positions within the line are specified by one of *n+1* character numbers (the extra one
corresponding to an overflow position at the end). If the line is empty (i.e. it contains zero characters), then its character number is always *1* and it is always in the overflowed state. Similarly, if a page (a book) is able to accomodate *m* lines (*m* pages), then positions within the page (the book) are specified by one of *m+1* line numbers (page numbers). If the page (the book) is empty, then its line number (its page number) is always *1*. The "current position" is a triple (*page number*, *line number*, *char number*) specifying the position of the character to be read or written to next (normally the position just after the character read or written last). New readers are advised to start at (*1*, *1*, *1*). If, by some mischance, you find your current position to be at the overflow position of a line, or of a page, or of the book, then you have overflowed the "physical" book. If the book has been written, but not right up the its end, then the "logical end of file" is the position (page, line and character number) just after the last character written. New writers are recommended to start on an empty book with its logical end of file at (*1*, *1*, *1*). If by some further mischance you contrive to get your current position beyond your logical end of file, then you have overflowed the "logical" book.

A book has a title, its "identification", which you may use to ensure that you get the right one. Sometimes, you may be allowed to change the identification of the book (*reidf possible*). For your convenience when referring to the book from within your program, we provide an identifier for it, and with this we associate a record containing useful information (as detailed in 7.4.2). This record is of a special mode called **file** (in actual fact a **file** is a particular form of structure (1.4), and there is no reason why several **files** should not refer to one book, nor why one **file** should not be assigned to another). **files** may be declared thus:

(E1) **file** *my input, my output*;

The process of causing a **file** to refer to a book (via some specified **channel**) is known as "opening" the **file** (see 7.2.3 below). Initially, every particular program is provided with one book to be read, one to be written, and one to browse in. These are already opened in the standard-prelude [R 10.5.1.c] (and are closed in the standard-postlude), and are referred to by **file** variables called:

*stand in*
*stand out*
*stand back*

the books being linked

**via channels** called

*stand in channel*
*stand out channel*
*stand back channel*

The properties of all books linked via these standard channels are given by
<table><thead><tr><th></th><th>stand in channel</th><th>stand out channel</th><th>stand back channel</th></tr></thead><tbody><tr><td>set possible</td><td></td><td></td><td>true</td></tr><tr><td>reset possible</td><td></td><td></td><td>true</td></tr><tr><td>get possible</td><td>true</td><td></td><td>true</td></tr><tr><td>put possible</td><td></td><td>true</td><td>true</td></tr><tr><td>bin possible</td><td></td><td></td><td>true</td></tr><tr><td>reidf possible</td><td></td><td></td><td>true</td></tr><tr><td>estab possible</td><td></td><td></td><td></td></tr><tr><td>compressible</td><td></td><td></td><td></td></tr></tbody></table>

You may open further files on these and other channels:

(E2) open (my input, "BOOK_1", stand in channel);
create (my output, special printer channel)

The results of the first of these can be represented thus:

<figure><img src="image_82.png" /></figure>

The procedures *print* and *read* introduced in 7.1. automatically use the books referred to by *stand out* and *stand in*. Two further procedures *put* and *get* perform identical functions for other *files*. These must specify some *file*, and are such that:
`print (XXXXX)` is equivalent to `put (stand out, XXXXX)`

`read (XXXXX)` is equivalent to `get (stand in, XXXXX)`

### 7.2.2. Environment enquiries

You will see, therefore, that **channels** and books have lots of useful properties. What we need are some more environment enquiries (see 6.2.1) to guide us [R 10.3.1.3]. Since some of these properties may be a function of the **channel** and some of the book and some (at the whim of the operating system) of both, or neither, these environment enquiries mostly take the form of procedures with **ref file** parameters. They are therefore only meaningful when a book has been opened on the file.

<table><thead><tr><th>identifier<br>of proc or constant</th><th>mode</th><th>value</th></tr></thead><tbody><tr><td>set possible</td><td>proc/ref file/bool</td><td>true if random access is permitted</td></tr><tr><td>reset possible</td><td>proc/ref file/bool</td><td>true if the current position can be reset to (1,1,1) (e.g. rewind on magnetic tape)</td></tr><tr><td>get possible</td><td>proc/ref file/bool</td><td>true if input is possible</td></tr><tr><td>put possible</td><td>proc/ref file/bool</td><td>true if output is possible</td></tr><tr><td>bin possible</td><td>proc/ref file/bool</td><td>true if binary transput is possible</td></tr><tr><td>reidf possible</td><td>proc/ref file/bool</td><td>true if the string which identifies the book can be changed by reidf (7.2.3)</td></tr><tr><td>compressible</td><td>proc/ref file/bool</td><td>true if the line length can be varied on output</td></tr><tr><td>chan</td><td>proc/ref file/channel</td><td>the channel on which the file has been opened</td></tr><tr><td>estab possible</td><td>proc/channel/bool</td><td>true if new books may be established (7.2.3) on the channel</td></tr><tr><td>stand in channel</td><td>channel</td><td>the channel on which the file stand in is opened</td></tr><tr><td>stand out channel</td><td>channel</td><td>the channel on which the file stand out is opened</td></tr><tr><td>stand back<br>channel</td><td>channel</td><td>the channel on which the file stand back is opened</td></tr></tbody></table>

Some further environment enquiries will be given in 7.5.3.

Observe that **channel** is actually a new mode. Implementations will doubtless ascribe to suitable identifiers in their library-preludes (1.1) extra channels on the lines of *stand in channel* etc. (but you cannot create new channel values for yourself).
### 7.2.3. Procedures for opening and closing

[R 10.3.1.4]

<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>open</td><td>proc(ref file file,<br>string idf,<br>channel ch)/int</td><td>Attach file to an existing book with identification idf through channel ch. The book will already contain writing up to some logical end of file, and it will have some number of pages, lines and characters consistent with the maxima for ch.</td></tr><tr><td>establish</td><td>proc(ref file file,<br>string idf,<br>channel ch,<br>int mp, ml,<br>mc) int</td><td>Create a new, empty book with identification idf and with mp pages each of ml lines of mc characters. Attach file to this book through channel ch (with which mp, ml and mc must be consistent).</td></tr><tr><td>create</td><td>proc(ref file file,<br>channel ch)/int</td><td>Create a new, empty book with undefined identification, and with the maximum number of pages, lines and characters permitted by the channel ch. Attach file to this book through ch.</td></tr><tr><td>associate</td><td>proc(ref file file,<br>ref [ ] [ ] [ ]<br>char sss/void</td><td>The existing multiple value (of mode [ ] [ ] [ ] char), referred to by sss is attached to file in lieu of a book. By virtue of the rowing coercion (5.5.0 and 5.5.1.3), the actual-parameter supplied for sss may be of mode ref [ ] [ ] char (giving a "book" of only 1 page) or of mode ref [ ] char (giving a "book" of only 1 line).</td></tr></tbody></table>

Note that the `int` returned by `open`, `establish` and `create` is normally zero, but if the opening is not successful for some reason (e.g. the required book does not exist, or the operating system is unable to provide the required facility) some other integer may be returned, depending upon the implementation.

<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>scratch</td><td>proc(ref file file)/void</td><td>detach the book (if any) attached to file and burn it</td></tr><tr><td>close</td><td>proc(ref file file)/void</td><td>detach the book from file (but it may subsequently be opened again)</td></tr><tr><td>lock</td><td>proc(ref file file)/void</td><td>detach the book from file. It may not be re-opened until it has been unlocked again by some action of the operating system</td></tr><tr><td>reidf</td><td>proc(ref file file,<br>string idf)/void</td><td>change the identification of the book to idf (reidf must be possible)</td></tr></tbody></table>

Note that, if two files are declared, and one is assigned to the other, then they are both attached to the same book. For the application of such assignations, see 7.4.2.
### 7.2.4. Position enquiries

[R 10.3.1.5]

<table><thead><tr><th>identifier<br>of proc</th><th>mode</th></tr></thead><tbody><tr><td>page number</td><td>proc/ref file file/int</td></tr><tr><td>line number</td><td>proc/ref file file/int</td></tr><tr><td>char number</td><td>proc/ref file file/int</td></tr></tbody></table><p>the current page number of the book</p><p>the current line number of the book</p><p>the current character number of the book.</p><p>N.B. the page, line and character number between them define the character position about to be read from or written to.</p>

### 7.2.5. Layout routines

[R 10.3.1.6]

<table><thead><tr><th>identifier<br>of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>set</td><td>proc/ref file file,<br>int p, l, c) void</td><td>Set the current position of the book referred to to (p, l, c). Only meaningful if <i>set possible</i>. See 7.7.1 for applications.</td></tr><tr><td>set char number</td><td>proc/ref file file,<br>int c) void</td><td>Set the current position to character c within the current line.</td></tr><tr><td>reset</td><td>proc/ref file file) void</td><td>Reset the current position to (1, 1, 1). Only meaningful if <i>reset possible</i>. See 7.7.2 for further effects.</td></tr><tr><td>newpage</td><td>proc/ref file file) void</td><td>see 7.1.1 and 7.1.2</td></tr><tr><td>newline</td><td>proc/ref file file) void</td><td>see 7.1.1 and 7.1.2</td></tr><tr><td>space</td><td>proc/ref file file) void</td><td>see 7.1.1 and 7.1.2</td></tr><tr><td>backspace</td><td>proc/ref file file) void</td><td>see 7.1.1 and 7.1.2</td></tr></tbody></table>

Note that if the book is *compressible* (7.2.2), the effect of newline (newpage) during output is to terminate the current line (page) immediately, the length of the line (page) being determined by the number of characters (lines) already written. If the book is not *compressible*, the line (page) is filled out with spaces to the size specified when the book was *established* (7.2.3) (the sizes specified in *establish* are simply the maxima allowed in the *compressible* case).

It will be recalled that procedures of mode `proc/ref file/void` (or firmly coercible thereto) may appear as actual-parameters in calls of `get`, `read` (7.1.2), `put` and `print` (7.1.1). Of course, any procedure of this mode written by the user is acceptable in such positions. Of the procedures defined in the
standard-prelude, the following are the relevant ones:

backspace, space, newline, newpage, reset, scratch, close, lock.

Note that where such procedures are called from inside *read*, etc. they need no actual-parameter. In other places, the *file* must be specified.

**Vertical readers**, please turn to 8.2.

## 7.4. Structures and events

### 7.4.1. Straightening of structures

Given:

(E1) `struct /int a, real b, compl c, char d, ......) s;`

then *print(s)* (or *put*, *get*, *read*, etc) is equivalent to

(E2) `print((a of s, b of s, c of s, d of s, ......))`

In other words, the fields of *s*, taken in order in which they were declared, are *printed* (or *put*, or *got*, or *read*) in accordance with whatever rules are applicable to their modes. This is known as "straightening" [R 10.3.2.3]. If one of the fields is a further structure or a multiple value, then that field itself is also straightened, and so on. Note, however, that although the mode *compl* is a *struct*, it is specifically forbidden from being straightened into two *reals*.

Clearly, since the transput of names and routines and *formats* and the input of *unions* is forbidden (at least so far as the transput routines declared within the standard-prelude are concerned), it follows that these things cannot appear in *structs* that are to be transput.

For straightening of multiple values, see 7.5.1.

### 7.4.2. Files

A *file* is, in reality, a *struct* being declared in the standard-prelude [R 10.3.1.3.a] somewhat like this:
(E3)
mode file = struct(ref book ?book?,
                 secret ?conv?, ?term?,
                 proc(ref file)/bool
                 ?logical file end?,
                 ?physical file end?,
                 ?page end?,
                 ?line end?,
                 ?format end?,
                 ?value error?,
                 proc(ref file, ref char/bool
                 ?char error?)

The queries around the field-selectors are intended to convey to you that these are not the true selectors of those fields. The true ones are secret, and so you have no way of making use of them. You can only alter them via procedures provided for the purpose or by assigning a complete new file, and it is therefore up to the implementor whether his struct is actually made up of the fields suggested in E3*.

Now, if you declare two files, open a book on one, and then assign it to the other:

(E4)
file first, second;
open (first, "bookname", channel);
second := first;

you arrive at the situation shown on the next page.

Both files must inevitably refer to the same book, and there is no way in which you can change this. However, if you contrive to make one of the fields different in the two versions, then you may get different results when

* Pedantically speaking, this is not quite true. Your compiler ought not to complain upon seeing:

file f := (skip, skip, stand in channel, f, i, p, p, p, p, p,
          skip, "", skip, (ref file f) bool: false,
          (ref file f) bool: false, (ref file f) bool: false,
          (ref file f) bool: false, (ref file f) bool: false,
          (ref file f) bool: false, (ref file f, ref char a) bool: false)

but we would not like to take any bets on it.
<figure><img src="image_83.png" /></figure>
you use them:

(E5)
* make term (first, "A");
* make term (second, "BC");
* string s;
* get (first, s);
* comment will read in a string of characters from the current position up to the end of the current line, or up to an "A" (whichever occurs first) (see 7.1.1) comment
* get (second, s);
* comment will read in a string from the same book as before, starting from where the previous get left off (presumably starting with an "A" in this case) and reading up to the end of the line, or until either a "B" or a "C" is encountered comment

make term is the first of the procedures referred to above. Its use should be apparent from the above example. A complete list of these procedures is now given, and their use will be explained in the sections which follow

[R 10.3.1.3]

<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>make term</td><td>proc/ref file f,<br>string t/void</td><td>assigns t to the ?term? field of f</td></tr><tr><td>make conv</td><td>proc/ref file f,<br>secret c/void</td><td>assigns c to the ?conv? field of f</td></tr><tr><td>on logical file<br>end</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?logical file end? field of f</td></tr><tr><td>on physical file<br>end</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?physical file end? field of f</td></tr><tr><td>on page end</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?page end? field of f</td></tr><tr><td>on line end</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?line end? field of f</td></tr><tr><td>on format end</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?format end? field of f</td></tr><tr><td>on value error</td><td>proc/ref file f,<br>proc/ref file/bool p/void</td><td>assigns p to the ?value error? field of f</td></tr><tr><td>on char error</td><td>proc/ref file f,<br>proc/ref file,<br>ref char/bool p/void</td><td>assigns p to the ?char error? field of f</td></tr></tbody></table>

Procedures which alter the ?book? field of a file are open, close, establish, associate, etc. (7.2.3). Note that associate causes the file to refer to a [] [] [] char instead of to a book.
### 7.4.3. Code conversion

All transput is really a matter of sending **chars** to or from a book. The function of the various transput procedures (*put*, *get*, etc.) is basically to convert the value on hand to or from **strings** of **chars**, and to transput the latter. You will doubtless have observed that internally we have been talking of "chars" — that is the internal objects of mode **char** which can be handled by an ALGOL 68 program. The things which we write in the book (i.e. the external representations) we have been talking of as "characters".

The relationship between these is determined by a conversion rule, and the conversion rule is kept in one of the secret fields of the **file**. A standard conversion rule is provided for each **channel**, and the intention is that the library-prelude of your implementation will provide additional ones to suit any special codes with which your installation may have to deal.

An environment enquiry [R 10.3.1.2.d] provides the standard rules, and the procedure *make conv* attaches them to the **file**.

<table><thead><tr><td>identifier</td><td>mode</td><td>value</td></tr></thead><tbody><tr><td>stand conv</td><td>proc(channel chan)<br>secret</td><td>gives the standard conversion for chan</td></tr></tbody></table>

The mode **secret** is not really called **secret**, so you cannot do anything with it, except use it in *make conv*. When a **file** is *opened* (or *established* or *created*) on a **channel**, it is set up with the appropriate *stand conv*. When a **file** is assigned, its *?conv?* goes with it.

(E6)
*file first, second;*
*open (first, "bookname", stand in channel);*
*second := first;*
*make conv (second, special conv);*
*  & supposing that *special conv* is available in the
  particular library-prelude &*
*get (first, s); & reads a *string* according to the standard &*
*get (second, s); & reads the next *string* from the same
  book, according to *special conv* &*
*make conv (second, stand conv (stand in channel));*
*  & restores the original rule &*
*get (second, s) & now does the same as get (first, s)
  would have done &*

Each conversion rule specifies the transformation of each single **char** into a
single external character and vice versa (the mapping rule is not necessarily one to one in either direction).

### 7.4.4. Event routines

The remaining fields in **file** are event routines [R 10.3.1.3.cc]. They are provided to enable some user-defined action to take place when, for example, the end of a page is reached, without the user having to insert a test for this at the end of every transput call.

They all yield some **bool** value, and their default state, as left by *open*, *create*, *establish* or *associate*, is to yield the value **false**. If you write some routine of your own, and associate it with your **file** by means of one of the *on* procedures given above (7.4.2), then you may do what you like inside it, but there are three ways in which you may finish it:

1) **yield false.** In this case you are asking the transput routine which called you in to continue by taking its default action (which in some cases is left undefined by the Report, but which should then be some sensible system action).

2) **yield true.** In this case the calling routine will presume that you have corrected the situation to your satisfaction, and it will continue with next business.

3) jump right out of (i.e. terminate) your routine. In this case, the calling routine is terminated also. However, you must be sure that the label to which you jump is in the same reach as that in which your routine was declared, or in a surrounding range (*else* you will be in identification trouble (see 3.2.3)).

In cases 1) and 2), you may alter any of the values associated with the book (e.g. the current position - by *newline*, *reset*, etc. - or the *format*, or the contents) or with the **file** (e.g. by *close*ing and re-*opening* it with a different book, or by providing a different terminating *string*, conversion rule or event routines).

Beware of associating an event routine with a **file** if its scope (4.2.3) is newer than that of the **file**. If necessary, you must declare a copy of the **file** with the scope of the proposed routine, so that the original **file** can continue to use its original routine outside this scope. A good example of this technique can be found in the Report at 10.3.1.3.cc.

We shall now consider the various routines and their uses. They all cause an event routine to be associated with the appropriate secret field of the **file**. The first four of them are concerned with exceeding the logical or physical limits of the book (7.2.1). To do this is in itself no crime. You are quite
entitled to have overflowed these limits by one character, one line or one page as the case may be. It is only when you are in such an overflowed position and you try to make matters worse by attempting transput (*put*, *get*, etc.) or layout (*space*, *newline*, etc.) that an event routine will be called [R 10.3.1.6.dd].

### 7.4.4.1. On logical file end

The associated event routine can be called by the input routines (*get*, *getf*, *get bin*, etc.) and by the layout routines *space*, *set char number*, *newline* and *newpage* when called in conjunction with input operations. It can also be called by *set*. Input or layout continues right up to and including the last character present in the book before the logical end of the file. If a further character is now demanded (or one of the layout routines is called), then the event is called. If this returns *false* (or if no such routine is provided) then the further elaboration is undefined (presumably the implementation halts the program with suitable diagnostics). If it returns *true*, then a further attempt is made to input the character or perform the layout.

The most likely action of the user's routine here is to recognise that his input data is ended, and to take steps to commence the next phase of his program.

### 7.4.4.2. On physical file end

The associated event routine can be called by the output routines (*put*, *putf*, *put bin*, etc.) and by the layout routines *space*, *set char number*, *newline* and *newpage* when called in conjunction with output operations. Output or layout continues until the book has overflowed (i.e. until the current position has gone beyond the last page that is physically available). If further output is now attempted (or one of those layout routines is called), then the event is called. The action taken is similar to the previous case – if *false* is returned the further elaboration is undefined, if *true* the output or layout is attempted again.

This event might be called, for example, if you had filled up a reel of magnetic tape, in which case it would be appropriate for your routine to *close* it and *open* another one.

### 7.4.4.3. On page end

The associated event routine can be called by all the transput routines (i.e. by both *put* and *get*, etc.) and by the layout routines *space*, *set char number*
and *newline*. Transput or layout continues until the current page has over-
flowed (i.e. until the current position has gone beyond the last line physically
available in the page). If further transput is now attempted (or one of those
layout routines is called), then the event is called. If this returns *false* (or if no
such routine is provided), then the default action is to call *newpage* (which
should remedy the situation). If it returns *true*, then the transput or layout is
attempted again.

The user may of course call *newpage* himself and return *true*, but he then
also has the opportunity, for example, of outputting some heading and page
number on the new page.

7.4.4.4. On line end

This is exactly like on page end, except that the event happens when the
current line has overflowed and the default action (except in formatted
transput and when getting strings) is to call newline (which should remedy the
situation).

The user may, again, call *newline* himself and return *true*, perhaps first
outputting some line number.

It is to be noted that the default actions or user routines invoked by the
above events may provoke other events. For example, the default call of
*newpage* in *on page end* will normally remedy the situation but, in the
exceptional case that this is the last page in the book, or before the logical
end, the *physical* (or *logical*) *file end* event will then be invoked. In the
extreme case in which the user when invited to mend the situation fails to do
so, but erroneously claims (by returning *true*) that all is now well, the same
event will be invoked again, and so on indefinitely.

7.4.4.5. On format end

The associated event routine is called by the formatted transput routines
(*putf*, *getf*, etc.) when the *format* is exhausted. It may yield *false* whereupon
the previous *format* associated with the book is repeated, otherwise it must
provide a fresh *format* and yield *true*.

7.4.4.6. On value error

The associated event routine is called by the formatted transput routines
(7.6.3) when the (internal) value on hand is incompatible with the current
picture [R 10.3.4.1.1.hh, ii]. For example, on output the picture may
provide too few digits, on input the value yielded may be too large to store
(e.g. > max int) or the expected literal in a choice may not be found, and in either case the mode of the picture may be wrong. If true is yielded, the offending value and picture are skipped; otherwise the result is undefined, except that with putf the value is first output with put.

This event is also invoked during formatless input (get) when the value yielded is too large to store.

### 7.4.4.7. On char error

The associated event routine is called by the input routines (get and getf) when the converted char read from the book does not agree with the sort of value expected (e.g. a letter is found when a number has been called for) or when the character in the book cannot be converted to any char (e.g. a parity error). With the call is provided the name of a char which it is proposed to substitute for the offender in order that input may continue. If false is yielded, then the implementation will take its own action (e.g. diagnostic message) after which the substitution may duly be made (although the user's routine may nevertheless have taken some note of the error). Alternatively, the user's routine may yield true, after possibly having assigned some alternative char to be used in place of the suggested one.

The suggestions that will be made in various circumstances are as follows:

<table><thead><tr><th>Expected</th><th>suggestion</th></tr></thead><tbody><tr><td>a number (unformatted)</td><td>0</td></tr><tr><td>a digit or supressed zero<br>(formatted)</td><td>0</td></tr><tr><td>a sign (formatted)</td><td>+</td></tr><tr><td>a decimal point (formatted)</td><td>.</td></tr><tr><td>10 (formatted)</td><td>10</td></tr><tr><td>⊥ (for compl) (formatted<br>or unformatted)</td><td>⊥</td></tr><tr><td>a bool value (formatted<br>or unformatted<br>an expected char of an insertion<br>(formatted)</td><td>F (but see 7.5.3)<br>that char</td></tr></tbody></table>

If the user, in this routine, wants to examine the offending character, he has only to backspace the file and use get. If he decides the offending character should be a candidate for the next input operation, he has only to leave the file backspaced.
In the case of an unconvertible character, the suggestion will be "_" (i.e. a space).

**Vertical readers**, please turn to 8.4.

## 7.5. Rows and strings

### 7.5.1. Straightening of multiple values

Given:

(E1) $[1:n, 1:4] \text{ int } j2;$

then `print(j2)` (or `put`, `get`, `read`, etc.) is equivalent to:

(E2) `print((j2[1,1], j2[1,2], j2[1,3], j2[1,4], j2[2,1], j2[2,2], j2[2,3], j2[2,4], j2[3,1], j2[3,2], j2[3,3], j2[3,4], ......))`

In other words, the rows of `j2`, and within them the elements of each row, are *printed* (or *put*, or *got*, or *read*) in accordance with whatever rules are applicable to their mode. This is known as "straightening" [R 10.3.2.3]. If one of the elements is a structure, then it itself is straightened in accordance with 7.4.1 and if it is itself a multiple, then it is straightened as above, and so on. Note, however, that a *string* or `[] char` is never straightened into its constituent *chars*.

### 7.5.2. Conversion procedures

Basically, non-binary transput consists of considering values of various modes and converting these values to or from *strings*. It is the *strings* which are transput across the *channel* to or from the book.

`print` and `put` provide certain fixed rules for converting *ints*, *reals*, *compls*, *bools*, etc. (7.1.1 and 7.1.2). These are quick and easy to use, but they may not always provide the layout you want, in which case you must do-it-yourself (or you might consider formatted transput (7.6)). You can always output a *string*, and so you use one of the following do-it-yourself procedures [R 10.3.2.1] to make your own *string*. In the following table, *number* stands for *real* or *int* or any *long* or *short* version thereof.
<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>whole</td><td>proc(number v, int w)/string</td><td>Converts v into a string of abs w chars. Leading zeroes are replaced by spaces. If w is positive, a "+" or "-" is always included in the string. If w is negative, the string is unsigned for positive v. If w is zero, the shortest possible string into which v can be converted is provided (including a "-" if v is negative, but never a "+"). If v cannot be converted within abs w chars, a string of w asterisks is returned (but see 7.5.3).</td></tr><tr><td>fixed</td><td>proc(number v, int w, a)/string</td><td>Converts v into a string of abs w chars, including sign, if any, and decimal point and with a digits after the decimal point. The cases when w is negative or zero are treated as in whole. If v cannot be converted within abs w chars (even after reducing a so as to provide more positions before the decimal point), then w asterisks are returned.</td></tr><tr><td>float</td><td>proc(number v, int w, a, e)/string</td><td>Converts v into a string of abs w chars, including sign, decimal point and "10", and with a digits after the decimal point and abs e digits (including any sign) of exponent. If w is negative, a leading "+" is replaced by "-" and, if e is negative, positive exponents are not signed.</td></tr><tr><td>char in string</td><td>proc(char c, ref int i, string a)/bool</td><td>Returns true if c is contained in s, in which case the index of its first occurrence in s is assigned to i.</td></tr></tbody></table>

Examples. Given:

<table><tr><td>(E3)</td><td>i := 1023; x := 999.888;</td><td></td><td></td></tr><tr><td></td><td>print(whole(i, 7));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(whole(i, -7));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(whole(i, 0));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(whole(i, 3));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(fixed(-x, 8, 3));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(fixed(-x, -8, 2));</td><td>¢</td><td>¢</td></tr><tr><td></td><td>print(float(x, -12, 5, 3));</td><td>¢</td><td>¢</td></tr><tr><td></td><td></td><td>¢</td><td>¢</td></tr><tr><td></td><td></td><td>¢</td><td>¢</td></tr></table>
### 7.5.3. Conversion environment enquiries

*print* and *put* always output the exact number of digits necessary to represent the largest possible magnitude of the value being output. The user might wish to know what this number of digits is, either when planning the layout of his page, or when using formatted transput (7.6). Appropriate environment enquiries are therefore provided [R 10.3.2.1.m, n, o, 10.2.1.r, s, t].

<table><thead><tr><th>identifier of constant</th><th>mode</th><th>value</th></tr></thead><tbody><tr><td><code>int width</code></td><td><code>int</code></td><td>the number of decimal digits required to represent <code>max int</code> (6.2.1) – not including sign</td></tr><tr><td><code>real width</code></td><td><code>int</code></td><td>the number of decimal digits required to represent a mantissa, such that <code>small real</code> (6.2.1) is not neglected in comparison with <code>1</code> – not including sign</td></tr><tr><td><code>exp width</code></td><td><code>int</code></td><td>the number of decimal digits required to represent a decimal exponent, such that <code>max real</code> (6.2.1) can be correctly represented – not including sign</td></tr><tr><td><code>error character</code></td><td><code>char</code></td><td>the <code>char</code> used to represent unconvertible values in <em>whole</em>, etc. (7.5.2) – in this book we use "*"</td></tr><tr><td><code>flip</code></td><td><code>char</code></td><td>the <code>char</code> used to represent <code>true</code> during transput – in this book we use "T"</td></tr><tr><td><code>flop</code></td><td><code>char</code></td><td>the <code>char</code> used to represent <code>false</code> during transput – in this book we use "F"</td></tr></tbody></table>

See 6.7.1. for long(s) versions of these.

Note that the *chars* used for *error character*, *flip* and *flop* are to be chosen by the implementer – the choice of "*", "T" and "F" is merely the convention adopted for this book.

**Vertical readers**, please turn to 8.5.
## 7.6. Formatted transput

In formatted transput, the information about the values to be transput is presented separately from the information about how they are to be laid out. For example, given, in the book to be read, characters to yield the string:

"+123_456_789/A47/999.888*6"

we could read in the ints 123456789 and 47 and the real 999888000 by writing:

$$ (E1) \quad \texttt{read f( ( $ + 3d x 3d x 3d "/", x 2d "/", 3d. 3d se "*" d $, i, j, x ) )} $$

Here, i, j, x is a data list of the names to which the values input are to be assigned. In this case they are two ref ints and a ref real, but they could have been of any of the modes acceptable to read (7.1.2) including references to multiples and structures which would require straightening (7.4.1 and 7.5.1). The only things not permitted here are proc/ref file/voids such as newline, space, etc. because these are concerned with the layout rather than the values.

The layout is controlled by the piece between the two "$"s, which is known as a 'format-text'. This is made up of various items known as 'frames', 'alignments' and 'literals', and the meaning of each item in this example is as follows:

<table><thead><tr><th>item</th><th>name</th><th>effect</th></tr></thead><tbody><tr><td>$</td><td></td><td>to introduce the format-text</td></tr><tr><td>+</td><td>sign frame</td><td>expect a "+" or a "-"</td></tr><tr><td>3d</td><td>digit frame</td><td>read 3 digits</td></tr><tr><td>x</td><td>alignment</td><td>skip one character</td></tr><tr><td>3d</td><td>digit frame</td><td>read 3 digits</td></tr><tr><td>x</td><td>alignment</td><td>skip one character</td></tr><tr><td>3d</td><td>digit frame</td><td>read 3 digits</td></tr><tr><td>"/"</td><td>literal</td><td>the next character must be a "/"<br>This is the end of the 1st "picture". The sign and the 9<br>digits that have been read are to be converted and<br>assigned to the 1st value, which is i.</td></tr><tr><td>x</td><td>alignment</td><td>skip one character</td></tr><tr><td>2d</td><td>digit frame</td><td>read 2 digits</td></tr><tr><td>"/"</td><td>literal</td><td>the next character must be a "/"<br>This is the end of the 2nd picture. The 2 digits that have<br>been read since the last picture are to be converted and<br>assigned to the second value, which is j.</td></tr><tr><td>3d</td><td>digit frame</td><td>read 3 digits</td></tr><tr><td>.</td><td>point frame</td><td>expect a "."</td></tr><tr><td>3d</td><td>digit frame</td><td>read 3 digits</td></tr></tbody></table>
<table><tr><td>se</td><td>exponent frame</td><td>because of the s (for suppressed), no character is read for this frame, but the next digit frame will be interpreted as the start of a decimal exponent</td></tr><tr><td>"*"</td><td>literal</td><td>the next character must be an *</td></tr><tr><td>d</td><td>digit frame</td><td>read 1 digit</td></tr><tr><td>$</td><td></td><td>End of the format-text and of the 3rd picture.<br/>The characters read (or implied) by its various frames are to be converted to real and assigned to the 3rd value, which is x.</td></tr></table>

Thus every character position of the input line is accounted for, and each must contain exactly what the format-text says it should. Formatted input is therefore very suitable for punched card input, where fixed layouts are customary, but less so for paper tape where the free layouts accepted by the unformatted procedures will often be more appropriate.

For output, however, the formatted procedures will always give more control over what is printed, chiefly by their ability to include fixed information (i.e. literals) anywhere amongst the values that are being printed. For example, to print the same line that we read in in E1, we could write:

(E2) `printf( ( $ + 3d x 3d x 3d "/", "A" 2d "/", 3d . 3d se "*" d $, 123456789, 47, 999888000) )`

You will see that the format-text here is almost exactly the same as before, the only difference being that here we specify the "A" that is to be printed, whereas on input we were prepared to pass over any character that might have been present. On the other hand, the alignment `x` is quite sufficient to ensure that a space will be output, unless some other piece of transput has tried to put some other character there. In this respect, the `x` behaves just like a call on *space* (7.1.1).

### 7.6.1. Format texts

A format-text consists of a list of 'pictures' separated by commas, the whole being enclosed between "$"s [R 10.3.4.1.1]. Each picture is obeyed in turn, and if it contains any frames it is matched up against the next value that is to be transput (otherwise its insertions are performed and the next picture is taken).

Within each picture there may be found 'insertions' (which can be further subdivided into 'literals' and 'alignments'), and 'frames'. Insertions, or sequences of insertions, may be put at the beginning or end of the picture, or in between any two frames.
### 7.6.1.1. Literals

A literal [R 10.3.4.1.1.i] consists simply of a *string* denotation (5.5.1.1). On output, when this point in the format-text is reached, the *string* denotation is printed. On input, it is "expected" [R 10.3.4.1.1.1] ; i.e. the characters read from the book at this point must match the literal – if they do not, then the *char error* event is invoked (7.4.4.7).

The *string* denotation of a literal is actually preceded by a 'replicator'. These will be described more fully in 7.6.1.4. It will suffice for the moment that a replicator can consist of either "empty" or of an *int* denotation (5.1.1.1), and that we shall indicate the possible presence of one in what follows by an "R".

(E3) `printf( ($"START" 7"_." 3d $, i))`

There are two literals in the one and only picture in the format-text in this example. The first has an empty replicator, implying that the string "START" is to be printed only once. The replicator in the second shows that "_" is to be printed 7 times, so that the characters written to the book should look like this:

START ......987

Note that if two literals occur in succession, then the second one must have a non-empty replicator, for otherwise:

(E4) `"SMITH""JONES"`

would be ambiguous. In fact, E4 is a single literal which would be printed out (see 5.5.1.1) as:

SMITH"JONES

### 7.6.1.2. Alignments

Alignments [R 10.3.4.1.1.e] do not write any characters to the book. Their purpose is to move the current position (7.2.1) to some different page, line or char number, in a similar manner to the procedures *newpage*, *newline*, *space* and *backspace* (7.1.1 and 7.1.2) used in formatless transput. The following are the alignments permitted [R 10.3.4.1.1 ff]:
<table><thead><tr><th>alignment</th><th>effect</th></tr></thead><tbody><tr><td>Rx</td><td>call space the number of times specified by the replicator R. I.e. skip over R characters.</td></tr><tr><td>Rq</td><td>write (or expect) R space characters</td></tr><tr><td>Ry</td><td>call backspace R times</td></tr><tr><td>Rl</td><td>call newline R times</td></tr><tr><td>Rp</td><td>call newpage R times</td></tr><tr><td>Rk</td><td>call set char number (7.2.5) with R as its second parameter</td></tr></tbody></table>

(E5) printf(( $1"ABCD" 4x 4a, 5k 4a $, "IJKL", "EFGH" ) )

(in which 4a is a character frame) will therefore cause to be written, on a new line in the book:

A B C D E F G H I J K L

### 7.6.1.3. Frames

<table><thead><tr><th>frame type</th><th>syntax</th><th>effect on input</th><th>effect on output</th></tr></thead><tbody><tr><td>digit frame</td><td>Rd<br>Rsd</td><td>expect R digits</td><td>print R digits</td></tr><tr><td>sign frame</td><td>+</td><td>expect "+" or "-"</td><td>print "+" or "-"</td></tr><tr><td></td><td>-</td><td>expect "-" or "-"</td><td>print "-" or "-"</td></tr><tr><td></td><td>Rz+</td><td>pass over up to R spaces (say n), and</td><td>replace up to R leading zeroes (say n) by</td></tr><tr><td></td><td>Rz-</td><td>then expect "+", or "-" or "-" as above, followed by R-n digits</td><td>spaces, and then print "+", "-" or "-" as above, followed by R-n digits</td></tr><tr><td>zero frame</td><td>Rz<br>Rsz</td><td>expect R digits with leading zeroes replaced by spaces</td><td>print R digits with leading zeroes replaced by spaces</td></tr><tr><td>point frame</td><td>s.</td><td>expect a decimal point</td><td>print a decimal point</td></tr><tr><td>exponent frame</td><td>e<br>se</td><td>expect "10" or "" or "e"</td><td>print "10"</td></tr><tr><td>complex frame</td><td>i<br>si</td><td>expect "1" or "i"</td><td>print "i"</td></tr></tbody></table>
<table><thead><tr><th>frame type</th><th>syntax</th><th>effect on input</th><th>effect on output</th></tr></thead><tbody><tr><td>radix frame</td><td>2r<br>4r<br>8r<br>16r</td><td>convert the digits read, using the specified radix, into a <b>bits</b> value</td><td>convert the <b>bits</b> being output using the specified radix, and print in accordance with the rest of the frames</td></tr><tr><td>character frame</td><td>Ra<br>Rsa</td><td>expect R characters</td><td>print R characters</td></tr><tr><td>boolean frame</td><td>b</td><td>expect "T" or "F" (but see 7.5.3)</td><td>print "T" or "F"</td></tr><tr><td>general frame</td><td>g<br>g(w)<br>g(w, a)<br>g(w, a, e)<br>here, w, a and e stand for units yielding <b>int</b></td><td>accept characters as unformatted input (read or get)<br>print as in unformatted output (print or <b>put</b>)<br>print(whole(v, w))<br>print(fixed(v, w, a))<br>print(float(v, w, a, e))<br>where v is the value to be output</td><td></td></tr><tr><td>format frame</td><td>f(format)<br>here (format) stands for any ENCLOSED-clause (3.2.4) yielding a <b>format</b></td><td>transput proceeds using the <b>format</b> yielded by <b>format</b>. Upon exhaustion of this, the transput reverts to the next item of the original <b>format</b></td><td></td></tr></tbody></table>

In all the frames listed above, if an `s` is present, then on input the expected characters are not read from the book, but input proceeds as though they had been (and in the case where digits were expected, zeroes are yielded). On output, the characters concerned are not written to the book, but are simply "thrown away".

Note that sign, point, exponent and complex frames serve a dual purpose. They indicate that a certain character is to be expected or printed (unless suppressed), and they also indicate to the conversion routines the significance of the adjacent digit frames. Here are some examples:
<table><tr><td>(E6)</td><td>x := 999888000;</td><td></td><td></td></tr><tr><td></td><td>printf(( $ +d.5de2d $, x));</td><td>¢</td><td>+9.99888<sub>10</sub>08</td><td>¢</td></tr><tr><td></td><td>printf(( $ -5zde-zd $, x));</td><td>¢</td><td>999888<sub>10</sub> 3</td><td>¢</td></tr><tr><td></td><td>printf(( $ .6de+2d $, x));</td><td>¢</td><td>.999888<sub>10</sub>+09</td><td>¢</td></tr><tr><td></td><td>printf(( $ .5de+2d $, x));</td><td>¢</td><td>.99989<sub>10</sub>+09</td><td>¢</td></tr><tr><td></td><td>printf(( $ +11zd. $, x));</td><td>¢</td><td>+ 999888000.</td><td>¢</td></tr><tr><td></td><td>printf(( $ 11z+ds. $, x));</td><td>¢</td><td>+999888000</td><td>¢</td></tr><tr><td></td><td>printf(( $ 9d.3d $, x));</td><td>¢</td><td>999888000.000</td><td>¢</td></tr><tr><td></td><td>printf(( $ 6d3z. $, x));</td><td>¢</td><td>999888</td><td>¢</td></tr><tr><td></td><td>printf(( $ 6d3sds. $, x));</td><td>¢</td><td>999888</td><td>¢</td></tr></table>

As you will see, any reasonable combination of frames is permissible. Rather than try to list all the permitted cases, we shall instead point out certain compatibility restrictions [R 10.3.4.2 – 10.3.4.7] which arise with certain modes of the value being transput. Failure to observe them will result in invocation of the *value error* event (7.4.4.6).

1) A radix frame (r) may only be useful if the value is *int*.

2) Either a point frame (.) or an exponent frame (e) must be present if the value is *real*.

3) A complex frame (i) must be present if the value is *compl*, with either a point frame (.) or an exponent frame (e) somewhere on each side of it.

4) On output, there is no objection to having point, exponent and complex frames present when the value is *int*, nor to having a complex frame when the value is *real*, since the *int* or *real* can be widened. These cases are not acceptable on input, however.

5) Character frames (a) may only be used if the value is *char* or *string*.

6) A boolean frame (b) may only be used if the value is *bool*.

7) The order in which the various frames, if present, must appear in *int*, *real* or *compl* pictures is as follows:
* sign frame (+, -, z+, z-)
* zero frames (z) and digit frames (d)
* point frame (.)
* zero frames (z) and digit frames (d)
* exponent frame (e)
* sign frame (+, -, z+, z-)
* zero frames (z) and digit frames (d)
* complex frame (i), in which case all the preceding frames may occur again.

8) Character frames (a) must not be mixed with other types within one picture, but there may be several of them.

9) A boolean frame (b), a general frame (g) or a format frame (f) must be the one and only frame of its picture.
Here are some more examples, illustrating `compl`s, `bool`s and `string`s (single `char`s are treated exactly like `string`):

(E7)
```c
printf(( $ 2z-d.2d i-d.2de-d $, 37.2 i-43.4 ) );
```
& 37.201-4.34101 &
printf(( $ b,b,b $, true, false, true ) );
& TFT &
printf(( $ 4a x 4a $, "ABCDEF GH" ) );
& ABCD EFGH &
make term (stand in, "F");
readf(( $ g $, s ) ) & reads "ABCDE" from a book containing
& ABCDEFGH &
```

In addition to the various frames introduced above, there are two further types, known as “choices” [R 10.3.4.8], which can be used when the value to be transput is `int` or `bool`:

(E8)
```c
i := 4; j := 5;
printf((
    $ c("SUN", "MON", "TUES", "WEDNES", "THUS", "FRI",
        "SATUR") "DAY" $,
    i ) );
```
& prints WEDNESDAY &
printf((
    $ b("LESS THAN", "GREATER") $,
    i<j) )
& prints LESS THAN &
```

On output, one of these literals is selected from the list according to the value of the `int` or the `bool`. (Note that a sequence of literals, complete with replicators (7.6.1.1), could be used in place of each of the single literals shown in the examples.) On input, one of the literals listed is expected, and a value is assigned to the `int` or `bool` accordingly. If two or more of the literals match, the earliest one in the list is taken. The search is never carried beyond the end of the current line. If no literal matches, the *value error* event is invoked (7.4.4.6).

### 7.6.1.4. Replicators and collections

Two types of replicator have been introduced already (7.6.1.1). These consist of “empty” and of an `int` denotation. There exists a third type, known as a “dynamic” replicator [R 10.3.4.1.1.dd], which consists of an `n`
followed by an ENCLOSED int clause (3.2.4):

(E9)
proc digits in = ( int i) int: entier(ln(i)/ln(10)+1);
j := 0;
for i to 4
  do
    j timesab 10 plusab i;
    printf( ( $ 1 n(digits in (j))d $, j ) )
od
¢ prints: 1
        12
        123
        1234 ¢

If the expression of a dynamic replicator yields a negative value, then zero is assumed.

Replicators may also be used to cause a 'collection' of pictures within a format to be repeated. This is particularly useful when a multiple value of flexible size is to be transput:

(E10)
flex [1:0] struct / (int i, char a) ic1 := ((1,"A"), (2,"B"), (3,"C"), (4,"D"));
file f := stand out; ¢ f has the same scope as ic1 ¢
pu tf (f, ($ p n(upb ic1) (4z+d, 2x a 1), "TOTAL=" 3z+d $,
ic1, (int i := 0; for j to upb ic1
do i += i of ic1 [j] od; i)) )

¢ which will print out, on a new page:

+1 A
+2 B
+3 C
+4 D
TOTAL= +10 ¢

Such replicated collections can, of course, be nested to any depth. Moreover the grouping of the pictures so defined need not correspond to any natural grouping in the values being transput:

(E11)
[1:4] int j1 := (999,999,999,999), k1 := (888,888,888,888);
printf( ( $ 3d, 3(3"A" 2(3d x) 3x), 3d $.
j1, k1) )
¢ which would print:

999AAA999 999 AAA999 888 AAA888 888 888 ¢

In this example, *j1* and *k1* are first straightened (7.5.1). The changeover from the values arising from *j1* to those arising from *k1* actually takes place half way through the second repetition of the outermost collection — this is slightly odd, but perfectly permissible.

### 7.6.2. formats

We shall now introduce a new mode, known as **format**. As with other modes, you may declare **formats**, assign them, refer to them, construct multiples and structures and **unions** out of them, invent **procs** that deliver them, and have operators operating upon them. About the only thing you cannot do with a **format** is to transput it.

The value of a **format** is the internal object yielded by some format-text (7.6.1). Moreover, the value of any **format** at any stage in the elaboration of a program, unless it is undefined, must be traceable back to a format-text somewhere in that program.

(E12) **format f;** and **f is therefore of mode ref format** ¢

$f := \$ + n(\text{int width})\$;$

`printf ((f, 999))`

¢ which will print something like:

`+ 00000999 ¢`

Because a format-text can contain expressions which in turn may contain identifiers of limited reach, it should be pointed out that the scope of a format-text is determined by exactly the same rule as is applied to routines (see 4.2.3), so that the result of the elaboration of the following is not defined:

format f;
begin
  int i := 4;
  f := \$ n(i)\$ \$
end
printf ((f, j))

### 7.6.3. The formatted transput procedures

Associated with each **file** is a **format** value and a **format** pointer (which
keeps track of which picture is to be used next). As with *print* and *read*
(7.1.1, 7.1.2), the parameter supplied to *printf* or *readf* is a data list. each
element of which yields either a **format** value, or a value to be transput (but
not a **proc/ref file/void** this time). Usually, the first element provides a **format**
(it is then associated with the **file** *stand in* or *stand out* as the case may be)
whose sequence of pictures (as expanded by performing the replication of
any collections) is then matched against the sequence of values obtained by
straightening the remaining elements. This was done in all the examples
shown so far, but it need not necessarily be the case. Example E2 can thus be
rewritten as

$$
\begin{array}{l}
(E13) \quad printf( \$ + 3d \times 3d \times 3d \text{"/" } \$, 123456789, \\
\quad \$ \text{"A" } 2d \text{"/" } \$, 47, \\
\quad \$ 3d. \ 3d \ se \text{"*" } \$ \$, 999888000) \)
\end{array}
$$

If a new **format** is provided before the old one has been exhausted, the old
one is lost (note, however, that if the new **format** is provided to a copy of a
**file** obtained by assignation, the original **file** still retains the old **format**, as
should be clear from the diagram in 7.4.2). If part of a **format** still remains
unused when the end of the data list is reached, it remains associated with the
**file** and will be used for the next data list to be transput via that **file**.

(E14) `printf($p 6(8(6(+d.6de+d 2x) 1) 2l) $);`
    `‡ a data list of one element which actually performs no`
    `transput at all ‡`
    `proc real compute = c;`
    `to some large number`
    `do printf(compute) od`

This will print the results of the computation, 6 numbers to a line. 48 lines to
the page, with 2 extra blank lines inserted after every 8 lines. After printing
the results of 288 computations the format will be exhausted. Then the
format end event will be invoked (7.4.4.5). In this case the user has provided
no event routine and so the default action is taken, viz the same format is
started again (and printing is continued on a fresh page).

The procedures `printf` and `readf` use the books and **formats** referred to by
*stand out* and *stand in* (there is also a procedure `writef` which is identical to
`printf`). Two further procedures `putf` and `getf` perform identical functions for
other **files**, and are such that:

`printf(XXXXX)` is equivalent to `putf(stand out, XXXXX)`
`readf(XXXXX)` is equivalent to `getf(stand in, XXXXX)`
### 7.6.4. Events

The various procedures which you can associate with each *file* in order to trap various events during transput were described in 7.4.4. We shall now summarise the situations in which each of them can be called during formatted transput.

During both input and output:

1) The various frames, alignments and literals encountered in the *format* may cause the current position to overflow the physical book (7.2.1). If a character is read from or written to the book in this situation, the *line end*, *page end* or *physical file end* event is called as appropriate.

2) If the end of the *format* associated with the book is reached before the straightened data list of values being transput has been exhausted, then the *format end* event is called.

3) If the mode of the value being transput is incompatible with the sequence of frames which occurs in the current picture (the possible causes of this were listed in 7.6.1.3), then the *value error* event is called.

During input:

4) If an attempt is made to read beyond the (logical) end of the book (7.2.1), then the *logical file end* event is called.

5) If the value yielded by conversion of various digits etc, in accordance with the picture, is too great for values of that mode (e.g. an *int* greater than *max int* (6.2.1)), then the *value error* event is called.

6) If the character read from the book in accordance with one of the frames *d*, *z*, +, -, ., *e*, *i* or *b* is not expected, then the *char error* event is called.

7) If a character that has been expected by a literal is not found, then the *char error* event is called.

8) If none of the literals of a choice is found, then the *value error* event is called.

During output:

9) If a value to be output cannot be converted into the number of digits specified in the picture, then the *value error* event is called.

10) If a negative value is to be output, and the picture does not contain a sign frame, then the *value error* event is called.

11) If the *int* to be output by a choice is zero or negative or greater than the number of literals in the list, then the *value error* event is called.

**Vertical readers, please turn to 8.6.**
## 7.7. Binary transput

Binary output may be used where the sole purpose of the material produced is that it should subsequently be read (during the same or some other program) by binary input. Normally, the medium used will be magnetic tape, disc or drum, but paper tape or cards can be used if your implementation permits.

During binary transput, the medium is still divided into pages, lines and chars, but it is not defined how many chars are occupied by each object that is transput, and your implementation may provide some strange shape for the physical book (e.g. a magnetic drum might be regarded as a continuum of chars, all on the one and only line of the one and only page: on magnetic tape, a line might correspond to some block length, and on a disc a page might demarcate a region which could be accessed without head movement). Nevertheless, it will always be true that the current position will be defined by the triple (*page number*, *line number*, *char number*), and that it can always be inspected and manipulated by means of the facilities provided (7.2.4 and 7.2.5). In particular, the procedure *reset* can be used (7.2.5) if *reset* is *possible* (7.2.2) (as on tapes, discs and drums) and *set* can be used if *set* is *possible* (as on discs and drums). All the binary transput routines which are about to be described start from the current position. As line and page boundaries are passed, *line end* and *page end* events are called, but the default action is to call *newline* or *newpage*, so that the routines proceed automatically to cover as many chars, lines and pages as the values being transput may demand.

### 7.7.1. Binary transput procedures

In all of these procedures, the values are first straightened (7.4.1 and 7.5.1), and the straightened values are transput [R 10.3.6]. Thus all information as to how the original values were divided into structures and rows of multiple values is lost, as are the values of any bounds. Nevertheless, if the values output in this way are subsequently read back into a set of structures and multiples identical to that from which they originally came, then the new set will be an exact copy of the old.
(E1)
struct/int a, b)s1, s2, [1:4] int i1, i2;
s1 := (1,2); i1 := (3,4,5,6);
reset(stand back);
put bin(stand back, (s1, i1));
reset(stand back);
get bin(stand back, (s2, i2));
comment we might just as well have said

s2 := s1; i2 := i1

However, if we want to mix things up: comment
reset(stand back);
get bin(stand back, (i2, s2))
¢ whereupon i2 has the value (1,2,3,4) and s2
has the value (5,6) ¢

<table><thead><tr><th>identifier of proc</th><th>mode</th><th></th></tr></thead><tbody><tr><td>put bin</td><td>proc(ref file f, [ ] outtype x)</td><td>x is straightened and the resultant values are output to the book referred to by f, starting at the current position (which is suitably advanced)</td></tr><tr><td>write bin</td><td>proc([ ] outtype x)</td><td>equivalent to put bin(stand back, x)</td></tr><tr><td>get bin</td><td>proc(ref file f, [ ] inttype x)</td><td>x is straightened to yield the names to which the values in the book referred to by f, starting at the current position (which is suitably advanced), are read</td></tr><tr><td>read bin</td><td>proc([ ] inttype x)</td><td>equivalent to get bin(stand back, x)</td></tr></tbody></table>

In this table, the modes outtype and inttype (these are not their real names) indicate the modes acceptable to *print* (7.1.1) and *read* (7.1.2), with the exception of *proc/ref file/void*.

### 7.7.2. Some restrictions

The environment enquiries listed in 7.2.2 show what can and cannot be done with the various **channels** provided in an implementation. You can only do binary transput if *bin possible*. However, this is not to say that non-binary (i.e. character) transput is forbidden thereby. You are perfectly entitled to *put* and *get* to and from your disc, provided only that you are prepared to tolerate any strange page and line sizes that it may have.

There is an important distinction between **channels** with *set possible* (i.e. drums and discs) and the rest [R 10.3.1.4.j–m]. With *set possible*, you can
roam around your book writing characters here, reading them back there, and
doing binary transput in between. It is your entire responsibility to keep
track of the (*page number*, *line number*, *char number*) where everything has
been put, and of course if you try to read back as characters that which has
been written in binary, or vice versa, then the result will be quite undefined.

If, on the other hand, *set* is not *possible*, then things are different. When-
ever you start off at (1,1,1) (after a *reset*, for example, assuming *reset
possible*), you have the choice of reading or writing in characters or binary
(assuming a suitable combination of *put*, *get* and *bin possible* on the channel).
Thus you have 4 possibilities:

*   read binary — you must carry on reading in binary.

*   write binary — you must carry on writing in binary.

*   read characters — you may continue reading characters up to some
point, and then change to writing characters. But you must
not read beyond the logical end of the file (7.2.1).

*   write characters — each time you write, the logical end of the file is set
  to the new current position, which effectively prevents
  you from doing anything other than to write characters
  again.

Thus, with *put*, *get* and *reset possible*, but not *set possible*, the normal
behaviour expected with magnetic tape is obtained. If you disobey any of
these rules, then the result is undefined. Note that, when *set* is *possible*, it is
still impossible to *set* beyond the logical end. Any attempt to do so will
merely set the current position to the logical end exactly, and then call the
*logical file end* event.

The possible properties of the three standard channels were given in 7.2.1.
Note that only the minimum requirements are given there, and individual
implementations might, for example, allow *bin possible* on *stand in channel*.

Vertical readers, please turn to 8.7.
# 8. EXAMPLES

## 8.1. Simple examples

In this chapter, which forms the tail of the columns in our orthogonal plan, we shall show you, column by column, what you can do with the facilities described so far.

However, the language available to us at the end of this first column is rather sparse. We have shown you only the crudest form of conditional-statement. *strings* have only been hinted at. You cannot declare *procs*, nor *refs*, nor even constants. Any substantial and worthwhile example within these limitations could never do justice to the expressive power of ALGOL 68, and we must therefore invite you to read further before encountering a real example in 8.2.

If shorter examples of these simple facilities are what you would like to see, then we must refer you back to the early parts of Chapter 0 (the Very Informal Introduction) where you will find many such.

Vertical readers, please turn to 1.2.

## 8.2. Procedure examples

### 8.2.1. Easter

The Gregorian Calendar, insofar as it determines upon which day each year shall start, is universally accepted throughout the world. It also fixes the date of Easter as being the next Sunday after the Paschall Full Moon, which is intended to be the first full moon occurring on or after the Vernal Equinox (March 21st). The rules given for computing this are not so widely accepted. For example, the Jewish Passover and the Orthodox Easter are determined from different (and probably more accurate) calendars.

The defining document for these rules was written by one Clavius under a commission from Pope Gregory XIII [1]. Absolute accuracy was not a prime consideration. The Full Moon is considered to occur on the fourteenth day of the lunar month (which commences with the new moon). The rule was carefully devised so that the date predicted for its new moon always fell on, or one or two days after, the true mean new moon of the astronomers – but never before it. This was to ensure that never, under any circumstances, would the Christian Easter fall on the same day as the Jewish Passover.
(notwithstanding which, this terrible circumstance does occasionally arise, as in 1903).

The following is a complete program for calculating the date of Easter according to the Gregorian rule. For further explanations, see [3] and [4].

begin

int year, date, moon, paschal, easter;

comment We shall reckon dates by the number of days since the start of the year.

Thus: comment

int march21st = 31 + 28 + 21;

comment The Gregorian calendar was introduced into various parts of the world at different dates. In Great Britain, the year was: comment

int gregory start = 1752 ¢ or whatever date you prefer ¢;
read ( year );

if year < gregory start

then print ( "The Gregorian calendar was not introduced until",
            gregory start, newline )

else int century = year ÷ 100,

leap = abs ( year mod 4 = 0 ^ year mod 100 ÷ 0 v
            year mod 400 = 0 );

comment leap = 1 for a leap year, and 0 otherwise. comment

print ( (newpage,
            year,
            if leap = 1 then " (Leap year)" else "" fi,
            newline) );

comment To calculate the day of the week corresponding to any date, we
associate with each year a Dominical Letter, whose position in the alphabet
gives the date of the first Sunday in January. comment

int dominic = 7 - (year + year ÷ 4 - century + century ÷ 4
                      - 1 - leap) mod 7;

print ( ("The Dominical Letter is ",
          case dominic in "A", "B", "C", "D", "E", "F", "G" esac,
          if leap = 1
          then case (dominic - 2) mod 7 + 1
                      in "/A", "/B", "/C", "/D", "/E", "/F", "/G"
                      esac
          else ""
          fi,
          newline) );
proc weekday = (int date) string:

case (date - dominic) mod 7 + 1

in "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"

esac;

proc month = (ref int date) string.

comment This proc has a ref int parameter which it will alter to become the date within the month. comment

<table><tr><td>if date &le; 31</td><td>then "January"</td></tr><tr><td>elif (date := date-31) &le; 28 + leap</td><td>then "February"</td></tr><tr><td>elif (date := date-28-leap) &le; 31</td><td>then "March"</td></tr><tr><td>elif (date := date-31) &le; 30</td><td>then "April"</td></tr><tr><td>elif (date := date-30) &le; 31</td><td>then "May"</td></tr><tr><td>elif (date := date-31) &le; 30</td><td>then "June"</td></tr><tr><td>elif (date := date-30) &le; 31</td><td>then "July"</td></tr><tr><td>elif (date := date-31) &le; 31</td><td>then "August"</td></tr><tr><td>elif (date := date-31) &le; 30</td><td>then "September"</td></tr><tr><td>elif (date := date-30) &le; 31</td><td>then "October"</td></tr><tr><td>elif (date := date-31) &le; 30</td><td>then "November"</td></tr><tr><td>else date := date-30; "December"</td><td></td></tr><tr><td>fi;</td><td></td></tr></table>

comment The moon revolves around the earth once every 29.530588 days. 235 such lunations last just 1½ hours less than 19 Julian years. The calendar is therefore based on a "Metonic" cycle of 19 years, each year in a cycle being allotted a "Golden Number" in the range 1 to 19: comment

int golden = year mod 19 + 1;

print ("The Golden Number is", golden, newline);

comment However, following this cycle indefinitely would introduce an error of approximately 0.43 days per century. There is therefore a correction which, for convenience, is only allowed to change at the end of a century:

comment

int lilius ¤ who is a not inherently meaningful identifier ¤

$$ 
\begin{align*}
&= (\text{century} - \text{century} \div 4) \quad \begin{array}{@{}l@{}} \mathfrak{t} \text{ for the leap years omitted} \\ \text{at the start of some cen-} \\ \text{turies } \mathfrak{t} \end{array} \\
&\quad - (\text{century} - (\text{century} - 17)) \div 25) \div 3 \\
&\quad \mathfrak{t} \text{ the } 1\frac{1}{2} \text{ hours error } \mathfrak{t} \\
&\quad -8) \mod 30;
\end{align*}
$$

comment On the 1st of January of any year, the number of days since the last new moon is given by the "Epact": comment
int epact = (11 × (golden−1)−lilius) mod 30;

print (("The Epact is", epact, newline));

**comment** If successive new moons were to occur every 30 days, then we should be able to associate with each date a unique epact, one less for each day modulo 30 (then that date would be a new moon in years with that epact). In fact, six times in the year (and once extra at the end of 19 years) we must have a lunation of only 29 days, whereupon the sequence of epacts slips back a day and some date will have two epacts listed against it. These dates have been carefully chosen (it is alleged) so as to minimise the deviation from the true moon. One of them occurs in February and so happenings in March occur exactly 59 days after those in January (or 60 in a leap year, since the intercalary day, if any, in February is automatically added to the lunation in which it occurs). Therefore, there is a new moon on: **comment**

moon := 31−epact + 59 + leap;

if (paschal := moon + 13) <march21st + leap

then

**comment** the fourteenth day of this moon falls before the Vernal Equinox and we want the next one. The next date with two epacts against it occurs in April, the critical epact being given by: **comment**

int clavius = if golden > 11 then 26 else 25 fi;

moon := moon + (epact ≥ clavius | 30 | 29);

paschal := moon + 13

fi;

print ( ("The Paschal Full Moon falls upon ",
    weekday ( paschal ), space,
    month ( date := paschal ), space) );

**comment** Note how we have to break off the *print* here and start another one, so that we can use the value of *date*, as calculated therein, in the next *print*. If it had all been done in one *print*, then we might have been using *date* and assigning to it at the same time (i.e. collaterally), and anything might have happened. **comment**

print ((date, newline));

print ( ("Easter day, being the next Sunday after the ",
    "Paschal Full Moon, therefore falls upon ",
    month ( date := easter := paschal + 7−(paschal − dominic)
                      mod 7) ) );
print ((date, newline))

fi

end
The following are the references quoted in this section:

[1] Christophorus Clavius. Kalendarium Gregorianum Perpetuum. Cum Privilegio Summi Pontificis Et Aliorum Principum. Rome, Ex Officina Dominicae Basae. MDLXXXII. Cum Licentia Superiorum.

A companion volume was also prepared, and published in 1603:

[2] Christophorus Clavius. Romani Calendarii a Gregorio XIII. Pontifice Maximo restituti Explicatio.

[3] A. de Morgan. A Budget of Paradoxes. Longmans, Green & Co, 1872.

[4] Sir Harris Nicolas. The Chronology of History, containing Tables, Calculations & Statements, indispensable for ascertaining the dates of Historical Events, and of Public and Private Documents from the earliest periods to the present time. Longman, Brown, Green and Longman's, 1838.

Vertical readers, please turn to 1.3.

## 8.3. Examples of operators

### 8.3.1. Parallel plus

This example is intended to show how defining your own operators can lead to a considerable simplification of a program, at the same time making it more easy to follow.

It is well known that if two resistors A and B are placed in parallel, their combined resistance is given by:

$$ \frac{1}{A} = \frac{1}{B} $$

We can now define the operator "parallel plus" (we shall represent it by pap) to perform this operation. pap is a well behaved operator, being both commutative and associative. For the sake of completeness we shall also define "parallel minus" (pam) and assigning versions (6.3) paplusab and paminusab.

Consider the following network:

<figure><img src="image_84.png" /></figure>
It is required to find the value of x such that the resistance of the whole network shall be rt. Here is a program to do it:

```
begin
    prio pap = 7, pam = 7, paplusab = 1, paminusab = 1;
    op pap = (real a, b) real: a × b / (a + b);
    op pam = (real a, b) real: a × b / (b-a);
    op paplusab = (ref real a, real b) ref real: a := a × b / (a + b);
    op paminusab = (ref real a, real b) ref real: a := a × b / (b-a);
    real rt, r1, r2, r3, r4, r5, r6;
    read ((rt, r1, r2, r3, r4, r5, r6));
    print ((rt-(r1 + r2 pap r3 pap (r4+r5))) pam r6);
end
```

Electrical engineers will realise that all these operators ought also to be defined for **compl** operands (2.4.4) and for mixed **real** and **compl**.

**Vertical readers**, please turn to 1.4.

## 8.4. Two examples of library preludes

A library-prelude (see 1.1) is an expansion of the standard-prelude. It may contain further identity-, mode-, priority- and operation-declarations for use in particular applications. A library-prelude must be throughout consistent with the standard-prelude (i.e. indicators declared in it may not conflict with those declared in the standard-prelude).

In 8.4.1 we give a library-prelude for the basic operations on vectors in a Euclidean space $E_3$, the vectors being declared as

```
mode vec = struct (real xcoord, ycoord, zcoord);
```

In Section 8.5 we give a library-prelude for the basic operations on vectors in $E_n$ (n arbitrary) which is more general, but also less simple than this one.

In 8.4.2 we give a library-prelude for the basic operations on rational numbers, declared as

```
mode rat = struct (int numerator, denominator);
```

The declarations in 8.4.1 and 8.4.2 (and also those in 8.5) are fully consistent with each other and may, therefore, be joined into one library-prelude without any precaution. They may be regarded as one of many possible expansions of the language. Their intention is to demonstrate the expressive power and efficient elegance of the language, and to suggest how
to do away in practice with dialects and specific languages for use in
particular problems.

8.4.1. Operations on vectors in E₃

$$ \text{mode vec} = \text{struct} (\text{real xcoord}, \text{ycoord}, \text{zcoord}) ; $$

(1) prio parl = 5, perp = 5, proj = 6, $⊥x = 7$;

(2) op x = (vec u) real: xcoord of u;

(3) op y = (vec u) real: ycoord of u;

(4) op z = (vec u) real: zcoord of u;

(5) op + = (vec u) vec: u;

(6) op - = (vec u) vec: (-xu, -yu, -zu);

(7) op + = (vec u, v) vec: (xu + xv, yu + yv, zu + zv);

(8) op - = (vec u, v) vec: (xu - xv, yu - yv, zu - zv);

(9) op x = (real r, vec u) & the product of a scalar and a vector & vec: (r x xu, r x yu, r x zu);

(10) op x = (vec u, real r) & the product of a vector and a scalar & vec: r x u;

(11) op / = (vec u, real r) & the quotient of a vector and a scalar & vec: (xu / r, yu / r, zu / r);

(12) op x = (vec u, v) & the innerproduct & real: xu x xv + yu x yv + zu x zv;

(13) op $⊥x$ = (vec u, v) & the vectorproduct & vec: (yu x zv - zu x yv, zu x xv - xu x zv, xu x yv - yu x xv);

(14) op norm = (vec u) real: sqrt (u x u);

(15) op e = (vec u) & the unit vector in the direction of u & vec: (eps u | skip | (1/norm u) x u);

(16) real eps = c some small enough real number c;

(17) op eps = (real r) bool: abs r < eps;

(18) op eps = (vec u) bool: eps norm u;

(19) op parl = (vec u, v) & parallel? & bool: eps (eu $⊥x$ ev);

(20) op perp = (vec u, v) & perpendicular? & bool: eps (eu x ev);

(21) op proj = (vec u, v) & the protection of u on a plane perpendicular to v & vec: (vec ew = e ((v $⊥x$ u) $⊥x$ v); (u x ew) x ew);

(22) proc angle = (vec u, v) & the angle between u and v & real: arccos (eu x ev);
$$ (23) \quad \begin{array}{l} \texttt{proc plane} = (\texttt{vec } u, \nu, w) \notin \textit{in one plane} ? \notin \textit{bool}: \\ \phantom{(23) \quad \texttt{proc plane} = (} \texttt{eps} / (\textit{eu} \times (\textit{ev} \perp \textit{x} \textit{ew})); \end{array} $$

### 8.4.1.1. Comments on the library-prelude 8.4.1

The given set of operations is confined to $E_3$-vectors over the field of real values; it is obvious that they can as easily be defined over the field of complex values and also over more particular fields (see, for example, the rationals as defined in 8.4.2). It is also obvious in what way more specific operations can be subjoined to those given in 8.4.1; the declarations (21), (22) and (23) are already of a somewhat specific nature.

The given set may be of use in a variety of applications in mathematics, physics, chemistry and astronomy, enabling the programmer to write transparent and straightforward algorithmic prose in his own professional jargon.

Further modes may be derived from the given `vec`, for instance:

`mode event = struct ( real time , vec position );`

`mode tens = struct ( vec xlevel , ylevel , zlevel );`

The kinds of operators to be then declared for `event` and `tens` values, of course, depend entirely upon the specific applications. For an example of the use of the `mode event`, see 8.4.1.2.

The declarations (1) – (12) may speak for themselves.

In (13) we adopted for vector multiplication (sometimes termed the “outer product”) the operator $\perp$. The formula $u \perp x \nu$ yields a `vec` perpendicular to both $u$ and $\nu$ and of length $|u||\nu| \sin(u, \nu)$.

The `norm` defined in (14) is the usual Euclidean norm. If the underlying field is that of the rational values (8.4.2) we may define:

`op norm = ( vec u ) rat: max ( abs xu , abs yu , abs zu );`

The environment enquiry `eps` in (16) serves as a criterion for “zeroness” and is used in (20), (21) and (23) to define parallelism, perpendicularity and “planeness”. The value of `eps` may depend heavily upon the given input- and the required output-precision. If, for instance, `real eps = 0.01`, then two vectors will be considered as “perpendicular” to each other as soon as their inner product is $<0.01$ (see also the example in 8.4.1.2).

In (21) the `vec ew` (which is local to the routine) is a unit vector perpendicular to $\nu$ in the plane of $\nu$ and $u$ (we applied the vector product $\perp$ twice); hence, $(u \times ew) \notin \text{a real} \notin \times ew$ yields a `vec` in the plane perpendicular to $\nu$ and in the plane of $\nu$ and $u$.
proc new = ¢ yields the coordinates of an event relative to the initial time and the new axes newx-newy-newz ¢

(event e) event:

( time of e - init , (pos of e x newx, pos of e x newy, pos of e x newz) );

proc pr = ¢ prints characteristic data of an event, preceded by a string and a newline ¢ ( string s , event e ) void:

( event newe = new(e);

print (( newline , s , e pos of newe , norm pos of newe , time of newe ))

);

for i from 3 to n-2

do event veli = vel [i] , orbi = orb [i] ,

acci ¢ acceleration ¢ = deriv ( vel , i );

vec v = pos of veli , a = pos of acci ;

¢ if certain situations occur, messages and data will be printed: ¢

if v perp newx then pr ( "orbit in YZ", orbi );
      pr ( "velocity =", veli );

elif v perp newy then pr ( "orbit in ZX", orbi );
      pr ( "velocity =", veli );

elif v perp newz then pr ( "orbit in XY", orbi );
      pr ( "velocity =", veli );

else skip fi;

if eps v then pr ( "standstill", orbi );
      pr ( "accelerat.=", acci ) fi;

if eps a then pr ( "zero force", orbi );
      pr ( "velocity =", veli ) fi;

if a parl v then pr ( "force//orbit", orbi );
      pr ( "velocity =", veli );
      pr ( "accelerat.=", acci );

elif a perp v then pr ( "force⊥orbit", orbi );
      pr ( "velocity =", veli );
      pr ( "accelerat.=", acci );

else skip fi;

¢ if an appropriate device is available, one might conceive here
the call of a procedure plotting the curve ¢

od
end
### 8.4.2. Operations on rational operands

mode rat = struct ( int numerator, denominator );

(1) prio nn = 7, nd = 7, dd = 7;

(2) op n = ( rat r ) int: numerator of r ;

(3) op d = ( rat r ) int: denominator of r ;

(4) rat o = ( 0 , 1 );

(5) rat l = ( 1 , 1 );

(6) proc errat = void: c some action interrupting or halting the elaboration of the program signalizing that a result, required to be rational, cannot be expressed as a value of the mode rat c ;

(7) proc gcd = ( int n, d ) int: if d = 0 then abs n else gcd ( d, n mod d ) fi;

(8) proc long gcd = ( long int n, d ) long int: if d = long 0 then abs n else long gcd ( d, n mod d ) fi;

(9) op ↓ = ( int n, d ) rat: if d = 0 then errat ; skip else int k = gcd ( n, d ); ( if sign n = sign d then abs n ÷ k else - abs n ÷ k fi, abs d ÷ k ) fi;

(10) op ↓ = ( long int n, d ) rat: if d = long 0 then errat ; skip else long int k = long gcd ( n, d ); long int nk = n ÷ k, dk = d ÷ k; if abs nk ≤ leng maxint ∧ abs dk ≤ leng maxint then shorten nk ↓ shorten dk else errat ; skip fi;

(11) op sign = ( rat r ) int: sign n r ;

(12) op whole = ( rat r ) bool: d r = 1 ;

(13) op entier = ( rat r ) int: if n r ≥ 0 then n r ÷ d r else n r ÷ d r − 1 fi;

(14) op frac = ( rat r ) rat: r − entier r ;
(15) op round = ( rat r ) int: if frac r < 1 ↓ 2 then entier r else entier r + 1 fi;

(16) op re = ( rat r ) real: n r / d r ;

(17) op nn = ( rat p , q ) long int: leng n p × leng n q ;

(18) op nd = ( rat p , q ) long int: leng n p × leng d q ;

(19) op dd = ( rat p , q ) long int: leng d p × leng d q ;

(20) op < = ( rat p , q ) bool: p nd q < q nd p ;

(21) op = = ( rat p , q ) bool: p nd q = q nd p ;

(22) op > = ( rat p , q ) bool: p nd q > q nd p ;

(23) op ≤ = ( rat p , q ) bool: ¬ ( p > q ) ;

(24) op ‡ = ( rat p , q ) bool: ¬ ( p = q ) ;

(25) op ≥ = ( rat p , q ) bool: ¬ ( p < q ) ;

(26) op + = ( rat r ) rat: r ;

(27) op − = ( rat r ) rat: − n r ↓ d r ;

(28) op + = ( rat p , q ) rat: ( p nd q + q nd p ) ↓ ( p dd q ) ;

(29) op + = ( int n , rat r ) rat: / leng n × leng d r + leng n r ) ↓
          leng d r ;

(30) op + = ( rat r , int n ) rat: n + r ;

(31) op − = ( rat p , q ) rat: p + − q ;

(32) op − = ( int n , rat r ) rat: n + − r ;

(33) op − = ( rat r , int n ) rat: r + − n ;

(34) op x = ( rat p , q ) rat: ( p nn q ) ↓ ( p dd q ) ;

(35) op x = ( int n , rat r ) rat: ( leng n × leng n r ) ↓ leng d r ;

(36) op x = ( rat r , int n ) rat: n × r ;

(37) op / = ( rat p , q ) rat: p × ( d q ↓ n q ) ;

(38) op / = ( int n , rat r ) rat: n × ( d r ↓ n r ) ;

(39) op / = ( rat r , int n ) rat: r × ( 1 ↓ n ) ;

(40) op ↑ = ( rat r , int n ) rat: ( n r ↑ n ) ↓ ( d r ↑ n ) ;

8.4.2.1. Comments on the library-prelude 8.4.2

Possibly more than may be necessary for `vecs`, the operations on `rats`
should be "hand-coded" to take advantage of specific machine-features in
double-precision integral arithmetic.

(1) The down-symbol ↓ is used to obtain a rat from two ints or from two long ints. It already has a priority of 8 (see 6.1.2).

(4-5) The rationals zero and one are ascribed to the identifiers *o* and *l*.

(7-8) The recursive declarations of `gcd` and of `long gcd` is not only the most natural algorithm, but most likely (in a good implementation) also the most efficient one.
(9-10) 777↓ 1813 yields ( 3,7)
-777↓ 1813 yields (-3,7)
777↓ -1813 yields (-3,7)
-777↓ -1813 yields ( 3,7)
correspondingly for **long int** operands.

(8) and (10) All intermediate computations on the numerator and denominator will be performed in double-precision. If (being a vertical reader) you are not familiar with the mode **long int**, the denotation **long 0** and the operators **leng** and **shorten**, please be assured that such double-precision is indeed achieved (or read 5.7.1.2 and 6.7). In (10), the fraction is then reduced (if possible) to the mode **rat**.

Notice that $\frac{1813}{777}$ yields the real 2.3333333
$\frac{1813}{777}$ yields the int 2
but $\frac{1813}{777}$ yields the rat (7,3)

(11) $\text{sign}(777 \downarrow 1813) = 1$ , $\text{sign}(-777 \downarrow 1813) = -1$, $\text{sign} o = 0$

(12) whole (777↓1813) = false , whole (37↓1) = true

(13) entier (1813↓777) = 2 , entier (-1813↓777) = -3

(14) frac (1813 ↓ 777) = (1,3)

(15) round (1813↓777) = 2 , round (2321↓777) = 3

(16) re (1813 ↓ 777) = 2.3333333

(17-19) The operators **nn**, **nd**, **dd** are declared mainly to facilitate the notation of the remaining routines.

(20-40) These declarations may speak for themselves.

8.4.2.2. Some remarks on the use of rationals

The given set of operations on rational numbers may be of some
importance in problems in which the (rational) coefficients of power series
should be determined exactly. Such problems may arise when operations like
addition, subtraction, multiplication, division and substitution of power series
are relevant. A (truncated) power series (i.e. a polynomial) may, for instance
be declared as a:

mode powser = flex [1:0] rat;

The power series for the exponential function then occurs as:

powser exp = ( 1, 1, (1,2), (1,6), (1,24), (1,120), (1,720), (1,5040), (1,40320), (1,362880), c etc c;
and the Bernoulli numbers (the Bernoulli polynomial) as:

$$ \text{powser bern} = (1, (-1,2), (1,6), 0, (-1,30), 0, (1,42), 0, (-1,30), 0, (5,66), 0, (-691,2730), 0, (7,6), 0, (-3167,510), 0, c \text{ etc } c); $$

For such **powsers** one may then define operators:

op + = (powser p, q) powser: c routine for addition c;

op - = (powser p, q) powser: c routine for subtraction c;

op x = (powser p, q) powser: c routine for multiplication c;

op / = (powser p, q) powser: c routine for division c;

(see also 8.5)

op ↓ = (powser p, q) powser: c routine for the substitution of
p in q c;

The complex function defined by such **powsers** may be declared as:

proc fun = ( powser p , compl z ) compl:

( int m = lwb p, n = upb p ; compl value := re p [n] ;
for i from n-1 by -1 to m
  do value := value x z + re p [i] od ;
value);

Vertical readers, please turn to 1.5.

## 8.5. A library prelude for vector and matrix operations in E<sub>n</sub>

For many applications in a variety of scientific disciplines you may want
to write in your particular-program mode- and identity-declarations such as:

mode vector = [1:n] real,

matrix = [1:n,1:n] real ;

real p, q, r;

vector u, v, w;

matrix a, b, c;

and to apply operators yielding the sum, the difference, the (inner)product,
the norm, etc. of such vectors and matrices, in order to be able to write
straightforward expressions close to the well established mathematical
notation, such as:
$$u := r \times v;$$

$$u := v + w;$$

$$r := v \times w;$$

$$p := \operatorname{norm} u;$$

$$a := r \times b;$$

$$c := a + b;$$

$$c := a \times b;$$

$$u := a \times v;$$

$$u := v \times a;$$

$$p := \det a;$$

$$v := \operatorname{inv} a \times u$$

Then you may, of course, also want to write composite formulae such as:

$$u := a \times (v / \operatorname{norm} v);$$

$$u := \operatorname{inv}(a \times (b-c)) \times (w-v)$$

You may even want to use vectors of unequal length and non-square matrices:

$$[1:n] \text{ real } x, y; \quad [1:m] \text{ real } z;$$

$$[1:m, 1:k] \text{ real } m; \quad [1:k, 1:n] \text{ real } n;$$

and formulae such as:

$$z := m \times n \times (x + y)$$

The library-declarations listed in 8.5.1, 8.5.2 and 8.5.3 supply a basic and general set of such linear operations in $E_n$. The whole set is fully compatible with the library-declarations 8.4.1 and 8.4.2 and presupposes even the priority-declarations 8.4.1 (1) and the declarations for *eps* and *eps* in 8.4.1 (15) and (16). As was the case in the library-prelude for *vecs* (8.4.1) we confine ourselves to $E_n$-vectors and matrices over the field of real values; it may again be obvious that and how the whole set can be expanded over the field of complex values and even over more particular fields such as the rational values (8.4.2).

All our operation-declarations have formal-parameters of mode `[] real` or `[] real`, even though this may lead to great inefficiency in some implementations due to the copying of multiple values when these operators are used in formulas (see 4.5). We make no apology for this. The operators reflect the user's requirement much more naturally in the form here given, and their yields (which are again multiple values) are in a form immediately suitable for use as operands in further formulas. As for the so-called inefficiency, this is simply a problem of implementation. Methods exist which avoid the copying entirely, except in those peculiar and rare cases where it is really needed.
(However, should you be faced with an old-fashioned inefficient implementation, then you will need to declare all these formal-parameters as `ref [] reals` or `ref [,] reals`. Moreover, the values returned will also have to be of these modes. Next you will have to worry about the scope (3.2.2) of these returned names, and you will then find that the variable-declarations which create them will have to have `heap` where we have written `loc` (2.7.3). Alternatively, shoot your implementor.)

In calculating the innerproduct of two vectors (line (10) of 8.5.1), we make use of double-precision arithmetic. If (being a vertical reader) you are not yet familiar with the long modes, please see the remarks about them in 8.4.2.1.

The intention of these declarations is (rather than to make a definite proposal for a particular library-prelude) to show how in a quite natural, even dogmatic, manner one can define a set of powerful operators which are, in their application, very close to the generally accepted conventions of mathematical notation.

A priori information about the multiples to which the operators are to be applied and considerations of required precision may influence the ultimate form of the routines ascribed to these operators. In particular the algorithms in 8.5.3 may, from several technical points of view, depend heavily upon a priori information about the condition of the matrices there we are faced with problems of numerical analysis rather than of programming.

In 8.5.1 we declare the operations on vectors, adopting a notation which is as close as possible to the notation of 8.4.1. In fact, if you redeclare in your particular-program:

`mode vec = [1:3] real;`

then the result yielded by the operators `+`, `-`, `x`, `norm`, `e`, `eps`, `parl` and `perp` will be the same by 8.5.1 as it otherwise would have been by 8.4.1.

In 8.5.2 we declare the operations on vectors and matrices, applying where possible the operators declared in 8.5.1. Consider, for example, in 8.5.2 (10) the statement:

`for k from p2 to q2 do ab [, k] := a x b [, k] od`

the occurrence of `x` identifies the operator declared in 8.5.2 (8) where in its turn the occurrence of `x` in the statement:

`for i from m1 to n1 do au[i] := a[i, ] x u od`

identifies the operator declared in 8.5.1 (10) where in its turn the occurrence of `x` in the statement:
for *i* from *m* to *n* do *inpr* +:= *leng u[i]* × *leng v[i]* od

finally identifies the operator declared in the standard-prelude [R 10.2.3.4.1].

Observe that the operators `+:=`, `-:=`, `x:=` and `/:=` in 8.5.1 and 8.5.2 may be considerably more efficient than `+`, `-`, `x` and `/`, because no intermediate results have to be stored anywhere; for which reason they are anyhow less space-consuming!

The library-declarations in 8.5.3 may be considered as examples of the use of the operators declared in 8.5.1 and 8.5.2. The procedure *crout* is essentially the procedure *det* from R 11.7 in an adopted notation with a minor improvement. The operator **invert** yields a routine which is the ALGOL 68 version of a procedure by T.J. Dekker [*].

It may be very instructive to study carefully the use of the slicing feature in the routines 8.5.3 (6) and (8).

### 8.5.1. Operations on vectors in $E_n$

(1) op +
= ( [ ] real u, v ) [ ] real:
  ♯ the sum of two vectors ♯
  if   int m = lwb u, n = upb u;
       m = lwb v & n = upb v
  then loc [m:n] real s;
        for i from m to n do s[i] := u[i] + v[i] od;
       s
  else error ; skip
fi;

(2) op -
= ( [ ] real u, v ) [ ] real:
  ♯ the difference of two vectors ♯
  if   int m = lwb u, n = upb u;
       m = lwb v & n = upb v
  then loc [m:n] real s;
        for i from m to n do s[i] := u[i] + v[i] od;
       s
  else error ; skip
fi;

<footnote>[*] T.J. Dekker: ALGOL 68 procedures in numerical algebra, Part I
(Mathematical Centre Tracts 22,
Mathematisch Centrum, Boerhaavestraat 49, Amsterdam).</footnote>
(3) op x = ( real r, [] real u ) [] real:
    the product of a scalar and a vector
( int m = lwb u, n = upb u ;
  loc [m:n] real ru ;
  for i from m to n do ru[i] := r × u[i] od ;
  ru ) ;

(4) op x = ( [] real u, real r ) [] real:
    the product of a vector and a scalar
    r × u;

(5) op / = ( [] real u, real r ) [] real:
    the quotient of a vector and a scalar
    u × (1/r);

(6) op += = ( ref [] real u, [] real v ) ref [] real:
    if int m = lwb u, n = upb u ;
    m = lwb v ∧ n = upb v
    then for i from m to n do u[i] += v[i] od ;
    u
    else error ; skip
    fi;

(7) op -= = ( ref [] real u, [] real v ) ref [] real:
    if int m = lwb u, n = upb u ;
    m = lwb v ∧ n = upb v
    then for i from m to n do u[i] -= v[i] od ;
    u
    else error ; skip
    fi;

(8) op x := = ( ref [] real u, real r ) ref [] real:
    ( for i from lwb u to upb u do u[i] x := r od ; u ) ;

(9) op / := = ( ref [] real u, real r ) ref [] real:
    ( for i from lwb u to upb u do u[i] / := r od ; u ) ;
(10) op x
= ( [] real u, v ) real:
¢ the innerproduct of two vectors ¢
if int m = lwb u, n = upb u ;
m = lwb v ∧ n = upb v
then long real inpr := long 0 ;
for i from m to n
do inpr +:= leng u[i] × leng v[i] od ;
shorten inpr
else error ; skip
fi ;

(11) op norm
= ( [] real u ) real:
¢ the euclidean norm of a vector ¢
sqrt ( u x u ) ;

(12) op e
= ( [] real u ) [] real:
¢ a unit-vector in the direction of the given vector ¢
u / norm u ;

(13) proc norm = ( ref [] real u ) ref [] real:
¢ a reference to a vector divided by its norm
i.e., u := u / norm u ¢
( real normu = norm u ;
for i from lwb u to upb u do u[i] /:= normu od ; u ) ;

(14) op =
= ( [] real u, v ) bool:
eps norm ( u - v ) ;
¢ for eps applied to a real,
see 8.4.1 (17) ¢

(15) op ≠
= ( [] real u, v ) bool:
¬ ( u = v ) ;

(16) op parl
= ( [] real u, v ) bool:
e u = e v ;
¢ for the priority of parl,
see 8.4.1 (1) ¢

(17) op perp
= ( [] real u, v ) bool:
eps ( u x v ) ;
(18) proc error = void: c some action interrupting or halting the elaboration of the program signalizing that two vectors or matrices are of incompatible size c;

### 8.5.2. Operations on matrices and vectors

(1) op +
= ( [ , ] real a, b ) [ , ] real:
¢ the sum of two matrices ¢
  if
    int m1 = 1 lwb a, m2 = 2 lwb a,
    n1 = 1 upb a, n2 = 2 upb a;
    m2 = 2 lwb b ∧ n2 = 2 upb b
  then loc [m1:n1, m2:n2] real s;
    for j from m2 to n2
    do s[ , j ] := a[ , j ] + b[ , j ] od ; s
else error ; skip
fi;

(2) op -
= ( [ , ] real a, b ) [ , ] real:
¢ the difference of two matrices ¢
  if
    int m1 = 1 lwb a, m2 = 2 lwb a,
    n1 = 1 upb a, n2 = 2 upb a;
    m2 = 2 lwb b ∧ n2 = 2 upb b
  then loc [m1:n1, m2:n2] real d;
    for j from m2 to n2
    do d[ , j ] := a[ , j ] - b[ , j ] od ; d
else error ; skip
fi;

(3) op x
= ( real r, [ , ] real a ) [ , ] real:
¢ the product of a scalar and a matrix ¢
( int m1 = 1 lwb a, m2 = 2 lwb a, n1 = 1 upb a, n2 = 2 upb a;
  loc [m1:n1, m2:n2] real ra;
  for j from m2 to n2 do ra[ , j ] := r x a[ , j ] od ; ra );

(4) op x
= ( [ , ] real a, real r ) [ , ] real:
¢ the product of a matrix and a scalar ¢
r x a;
(5) op +:= = ( ref [, ] real a, [, ] real b ) ref [, ] real:
    if   int m1 = 1 lwb a, m2 = 2 lwb a,
        n1 = 1 upb a, n2 = 2 upb a;
        m2 = 2 lwb b ∧ n2 = 2 upb b
    then for j from m2 to n2 do a[ , j ] +:= b[ , j ] od ; a
else error ; skip
fi;

(6) op -:= = ( ref [, ] real a, [, ] real b ) ref [, ] real:
    if   int m1 = 1 lwb a, m2 = 2 lwb a,
        n1 = 1 upb a, n2 = 2 upb a;
        m2 = 2 lwb b ∧ n2 = 2 upb b
    then for j from m2 to n2 do a[ , j ] -:= b[ , j ] od ; a
else error ; skip
fi;

(7) op x:= = ( ref [, ] real a, real r ) ref [, ] real:
( for j from 2 lwb a to 2 upb a do a[ , j ] x:= r od ; a );

(8) op x = ( [, ] real a, [ ] real u ) [ ] real:
    ¢ the product of a matrix and a column-vector ¢
    if   int m1 = 1 lwb a, m2 = 2 lwb a,
        n1 = 1 upb a, n2 = 2 upb a;
        m2 = lwb u ∧ n2 = upb u
    then loc [m1:n1] real au ;
        for i from m1 to n1 do au[i] := a[i, ] × u od ; au
else error ; skip
fi;

(9) op x = ( [ ] real v, [, ] real a ) [ ] real:
    ¢ the product of a row-vector and a matrix ¢
    if   int m1 = 1 lwb a, m2 = 2 lwb a,
        n1 = 1 upb a, n2 = 2 upb a;
        lwb v = m1 ∧ upb v = n1
    then loc [m2:n2] real va ;
        for j from m2 to n2 do va[ j ] := v × a[ , j ] od ; va
else error ; skip
fi;
(10) op x
= ( [ , ] real a, b ) [ , ] real:
$\Phi$ the product of two matrices $\Phi$
( int m1 = 1 lwb a, n1 = 1 upb a, p2 = 2 lwb b, q2 = 2 upb b;
loc [m1:n1, p2:q2] real ab;
for k from p2 to q2 do ab [ , k ] := a x b [ , k ] od ; ab );

(11) proc icol
= ( ref [ , ] real a, int j1, j2 ) ref [ , ] real:
$\Phi$ interchanges a [ , j1 ] and a [ , j2 ] $\Phi$
( [ 1 lwb a:1 upb a ] real u := a [ , j1 ] ;
a [ , j1 ] := a [ , j2 ] ; a [ , j2 ] := u ; a ) ;

(12) proc irow
= ( ref [ , ] real a, int i1, i2 ) ref [ , ] real:
$\Phi$ interchanges a[i1, ] and a[i2, ] $\Phi$
( [ 2 lwb a:2 upb a ] real v := a[i1, ] ;
a[i1, ] := a[i2, ] ; a[i2, ] := v ; a );

### 8.5.3. Operations on square matrices

(1) op zero
= ( ref [ ] real u ) ref [ ] real:
( for i from lwb u to upb u do u[i] := 0 od ; u );

(2) op zero
= ( ref [ , ] real a ) ref [ , ] real:
( for i from 1 lwb a to 1 upb a do zero a[i, ] od ; a );

(3) op unit
= ( ref [ , ] real a ) ref [ , ] real:
if
  int m1 = 1 lwb a, n1 = 1 upb a;
  m1 = 2 lwb a & n1 = 2 upb a
then
  zero a ; for k from m1 to n1 do a[k, k] := 1 od ;
  a
else
  error ; skip
fi;

(4) proc iroco
= ( ref [ , ] real a, int i, j ) ref [ , ] real:
$\Phi$ interchanges a[i, ] and a[ , j ] $\Phi$
if
  int m1 = 1 lwb a, n1 = 1 upb a;
  m1 = 2 lwb a & n1 = 2 upb a
then
  loc [l:n] real u := a[i, ] ;
  a[i, ] := a[ , j ] ; a[ , j ] := u ;
  a
else
  error ; skip
fi;
(5) op trnsp = ( ref [, ] real a ) ref [, ] real :

¢ transposes the matrix a ¢

if int m1 = 1 lwb a, n1 = 1 upb a ;

m1 = 2 lwb a ^ n1 = 2 upb a

then for k from m1 to n1 - 1

do iroco ( a[k:n1, k:n1] , k, k ) od ;

a

else error ; skip

fi ;

(6) proc crout = ( ref [, ] real a, ref [ ] int p ) real :

¢ By the method of Crout with row interchanges the
square matrix a is replaced by its triangular decompo-
sition a := l x u with all u[k,k] = 1. The vector p
gives as output the pivotal row indices; the k-th pivot
is chosen in the k-th column of l such that
abs l[i,k] / row norm is maximal. The procedure
crout yields the value of the determinant of a ¢

if int m1 = 1 lwb a, n1 = 1 upb a ;

m1 = 2 lwb a ^ n1 = 2 upb a

^ m1 = lwb p ^ n1 = upb p

then [m1:n1] real norma;

for i from m1 to n1 do norma [i] := norm a[i, ] od ;

real determinant := 1, r, pivot ;

for k from m1 to n1

do int k1 = k - 1 ; ref int pk = p[k] ; real max := -1 ;

ref [, ] real l= a[ , m1:k1], u = a[m1:k1, ] ;

ref [ ] real ak = a[k, ] , ka = a[ , k]

lk = l[k, ] , ku =u[ , k] ;

for i from k to n1

do if ( r := abs ( ka [ i ] := l[i, ] × ku ) / norma[i] ) > max

then max := r; pk := i

fi

od ;

if pk ≠ k

then norma[pk] := norma[k] ;

irow ( a, pk, k ) ;

determinant := - determinant

fi ;
pivot := ka[k];

for j from k + 1 to n1

do ak[j] := (lk x u[, j]) /:= pivot od;

determinant x:= pivot

od;

determinant

else

0

fi;

(7) op det = ( [ , ] real a ) real:

¢ the determinant of a square matrix ¢

( int m1 = 1 lwb a, n1 = 1 upb a;

[m1:n1, m1:n1] real lu := a;

crout ( lu, loc[m1:n1] int );

(8) op invert = ( ref [ , ] real a ) ref [ , ] real:

¢ a reference to the inverted matrix a whose triangularly
decomposed form l x u and pivotal indices

[m1:n1] int p are obtained by a call of the procedure

crout (6); the inverse matrix supersedes the given

matrix a ¢

if int m1 = 1 lwb a, n1 = 1 upb a; [m1:n1] int p;

crout ( a, p ) ¯ 0

then [m1:n1] real rr, cc;

for k from n1 by -1 to m1

do int k1 = k + 1;

ref [ , ] real as := a[k1 : n1, k1 : n1];

ref [] real ar = a[k, k1 : n1], ac = a[k1 : n1, k];

ref real akk = a[k, k];

int m = n1 - k;

for i from m1 to m

do rr[i] := -(ar x as[, i]) ;

cc[i] := -(as[i, ] x ac) / akk

od;

ar := rr[ : m];

akk := (1 - ar x ac) / akk;

ac := cc[ : m]
```
od ;
for k from n1 by -1 to m1
  do int pk = p[k] ;
    if pk ≠ k then icol (a, k, pk) fi
  od ;
a
else error ; skip
fi ;
```

(9) op inv = ( [, ] real a ) [ , ] real:
    ⌜ an inverted copy of the given matrix a, which itself
    remains unchanged ⌜
    ( int m1 = 1 lwb a, n1 = 1 upb a,
     m2 = 2 lwb a, n2 = 2 upb a ;
     loc [m1:n1, m2:n2] real copya := a ;
     invert copya ) ;

Vertical readers, please turn to 1.6.

## 8.6. Examples of transput

### 8.6.1. The happy family

This example is intended to show some of the things that can be done with formatted transput. The techniques shown are not necessarily the best ways of producing the particular outputs of this program, but they exemplify methods which may well be valid in more realistic situations.

The example concerns the history of the Fitzwilliam family, and the relationships between its members (or at least those relationships which they were disposed to publicise). We have eschewed the use of generators (in case, being a vertical reader, you have not yet come upon 5.7.2), but we did find it necessary to use identity-relations (5.7.4), and these are explained to you at their first occurrence.

```
begin
```

```
comment This example concerns people: comment
```

```
mode person = struct ( string surname, given ¢ name ¢,
                       ref person father, mother, wife ¢ or husband ¢,
                       flex [1:0] ref person children,
                       bool dead, male ) ;
```

```
bool male = true, female = false, alive = false, dead = true;
```

```
ref person nobody = nil;
```
**comment** Sometimes it will be convenient to have a person's given name and surname together: comment

```
proc names = (ref person pers) struct (string given, surname):
    (given of pers, surname of pers);
```

**comment** All our formal-parameters will be of mode ref person rather than person, to save making unnecessary copies of persons (which are rather large) at run time. comment

**comment** Here is a procedure that will be used to add a little random spice to the messages that we shall produce. It yields a random integer in the range specified by its parameter. comment

```
proc randint = (int range) int:
    1 + entier (random x range);
read(last random); ¢ to start it off ¢
```

**comment** This program is going to print texts of variable length. We therefore have to take a newline whenever a line is full (after 80 characters, say), but before doing this we must go back to the last space and transfer the whole of the word which was about to be split onto the next line. Therefore, we shall output into a [] char instead of directly to the book. comment

```
file file; [1:80] char buffer;
for i to upb buffer do buffer [i] := "." od;
associate(file, buffer);
```

**comment** Whenever the buffer becomes full, its contents (except for the split word) must be printed in the real book. comment

```
proc empty buffer = (ref file f) bool:
    ( int j := upb buffer;
      if char number (f) > j
      then while buffer [j] ≠ "." do j := j + 1 od
      fi;
      print ((buffer [j:j], newline));
      reset (f);
      put (f, buffer [j + 1:]);
      for i from upb buffer - j + 1 to upb buffer
        do buffer [i] := "." od;
      true);
    on line end (file, empty buffer);
```

**comment** The [] char associated with file is like a book containing one page containing one line. As soon as we call newline(file), therefore, we shall find
that the page has overflowed (the current position will actually be at (1,2,1)). **comment**

on page end(file, empty buffer);

struct/int day, [1:3] char month, int year) date;
comment We shall frequently have occasion to print dates. Here is a
format to do it. **comment**

format datef = $ g(0)x, 3ax, 2d $;

proc generate = ( ref person infant, father, mother,
                 string given name, bool male) void:

if male of father ∧ ¬male of mother ∧ ¬dead of mother

then op plusab = ( ref flex [ ] ref person names, ref person pers ) void:
               names ::=

( int upb = upb names;
[1:upb + 1] ref person new names;
new names [1:upb] := names;
new names [upb + 1] := pers; new names);

infant := ( surname of mother,
            given name,
            father,
            mother,
            nil,
            ( ), ¢ not yet ! ¢
            alive,
            male);

children of father plusab infant;

children of mother plusab infant;

if wife of father :=: mother

**comment** That was an identity-relation. If you have not yet read 5.7.4, please accept our assurance that " :=: " is a sort of operator which yields **true** if the two names which are its operands in fact are the same name. In this case, the operands were of mode **ref person**, and **if** the **persons** **refed** to turn out to be the same **person** comment

then putf(file,
           ($ 2l "Birth."  
             l 4x g $,                 surname of infant,  
             $ ". On " f(datef) $,      date,  
             $ " to " g $,              given of mother,  
             $ ", wife of " g $,        given of father,
$", a" c( "darling",
"bouncing",
"beautiful",
"tiny")$, randint(4),
$xb("son", "daughter")
"-"$, male,
$g"."$, given name)

comment

else

no comment comment

fi

comment The above call of *putf* is intended to produce messages such as:
Birth.

Fitzwilliam. On 3 MAR 28 to Eleanor, wife of Ebenezer, a beautiful son - Japhet comment

else stop & the birth was quite impossible &

fi; & end of generate &

comment The following procedure is intended to print the name of some person, together with details of his parents. However, if there is some doubt about the marital state of the parents, then we shall draw a discreet veil over the matter by using a different format. comment

proc details = ( ref person pers ) void:

if mother of pers := ref person(wife of father of pers)

then bool sex = male of pers;

putf(file,

($g", "$,
given of pers,

$c("only", "youngest", "younger",
"eldest", "elder", "" ) x $,

( int j := 0, k;

ref flex [] ref person children =
children of father of pers;

int upb = upb children;

for i to upb & each brother/sister of pers &

do ref person child = children [i];

(male of child = sex | j += 1);

(given of child = given of pers | k := j)

od;

( j = 1 | 1 & only &

|: k = j | 2 + abs (j = 2) & youngest or younger &

|: k = 1 | 4 + abs (j = 2) & eldest or elder &

| 6) ),
```c
$ b("son", "daughter")
" of " $, sex,
$ g" and ", g x, g $, given of father of pers,
                       names(mother of pers))
else putf(file, ($ g x, g $, names(pers)))
fi;      ¢ end of details ¢
```

proc marry = (ref person bride, groom) void:

if male of groom ∧ ¬dead of groom
           ∧ ¬male of bride ∧ ¬dead of bride
           ∧ (wife of groom :=: nobody | true
                   | dead of wife of groom)
           ∧ (wife of bride ¢ sic ¢ :=: nobody | true
                   | dead of wife of bride)
then wife of groom := bride;
wife of bride := groom;

comment We are now going to produce a message such as:

Marriage.

Fitzwilliam/Jones. On 1 APR 24, Eleanor, only daughter of Emrys and Myfanwy Jones to Ebenezer, elder son of Aloysius and Anastasia Fitzwilliam.

comment

```c
putf(file,
     ($ 2l "Marriage."
       l 4x g "/", g "." On " $, surname of groom, surname of bride,
       $ f(datef) ", " $, date) );
details(bride);
put(file, " to ");
details(groom);
put(file, ".");
surname of bride := surname of groom
```

else stop ¢ the marriage is impossible, or illegal, or both ¢
fi;      ¢ end of marry ¢

proc kill = (ref person bloke) void:

if dead of bloke
then dead of bloke := true;
bool sex = male of bloke;

bool wa ¢ wife alive ¢ =
(wife of bloke :=: nobody | false
| dead of wife of bloke);
```c
string & name of & wife = (wa | given of wife of bloke | "");
```

**comment** The following call of *putf* is intended to produce messages such as:

Death.

On 21 DEC 68, Ebenezer, elder son of Aloysius and Anastasia Fitzwilliam, mourned by his devoted wife Eleanor

```c
putf(file,
($ 2l "Death."
1 4x " On " f(datef) ", " $, date));
details(bloke);
if wa
then putf(file,
($, mourned by "
b("his", "her") x,
c("everloving", "devoted",
"thankful") x,
b("wife", "husband"),
x g $,
sex, randint(3), sex, wife))
fi;
```

**comment** If *bloke* has surviving descendants, the dirge continues in the following vein:

and his children Shem, Ham and Japhet and his grandchildren Ananias, Azarias and Misael and his great-grandchild Tom.

```c
bool mp & mourners printed & := wa;
```

**comment** The following *proc* calls itself recursively for each generation.

comment

```c
proc print children of = ( [] ref person parents,
                          int generation) void:
```

```c
begin int i := 0, j := 0;
  [1:/ int i := 0;
    for j to upb parents
      do i += upb children of parents [j] od;
    i ]] ref person children, living children;
    for k to upb parents
```
do for *l* to upb *children* of *parents* [*k*]

do ref person child =

(children of parents [*k*] [*l*];

*children* [*i* +:= *l*] :=

(`not` dead of child

| living children [*j* +:= *l*] := child

| child )

od

od;

if *j* ≠ *o*

then `&` there are living children to be printed `&`
`putf(file,`

($f mp | $ " and" $ |: wa | $ "," $

| $ " mourned by" $),

x b("his", "her") x,

n(generation-1) "great-"

f(generation ≠ 0 | $ "grand" $ | $ $),

"child" f(*j* ≠ 1 | $ "ren" $ | $ $) x,

n(*j*) (*g*, f( (*j* -:= *l*) + 1

| $ $, $ " and" $

| $ "," $) $),

sex,

( [*l*:*j*] string names;

for *i* to *j* do names [*i*] :=

given of living children [*i*] od;

names) );

mp := true

fi;

if upb *children* ≠ *o*

then `print children of (children, generation + 1)`

fi

end `&` of print children of `&`;

`print children of (bloke, 0);`

`put(file, ".")`

else `stop &` the bloke was dead already `&`

fi; `&` end of kill `&`

comment Now we are ready to start our tale. Since we do not wish to go right
back to Adam, we shall start by declaring the story so far: comment

person *aloysius* :=

("Fitzwilliam", "Aloysius", skip, skip, skip, ( ), dead, male);
person *anastasia* :=

("Fitzwilliam", "Anastasia", skip, skip, aloysius, ( ), dead, female);

person *ebenezer* :=

("Fitzwilliam", "Ebenezer", aloysius, *anastasia*, *nil*, ( ), alive, male);

person *alaric* :=

("Fitzwilliam", "Alaric", aloysius, *anastasia*, *nil*, ( ), alive, male);

comment We were unable to include *anastasia* as *aloysius'* wife when initializing him, because her declaration had not been elaborated at that time (cf. 3.2.E7).

We can rectify this, and the similar case of their children, now comment

wife of *aloysius* := *anastasia*;

children of *aloysius* := children of *anastasia* := (*ebenezer*, *alaric*);

comment We shall declare the next family differently, so avoiding this problem: comment

person *emrys*, *myfanwy*, *frederick*, *eleanor*;

*emrys* := ("Jones", "Emrys", skip, skip, *myfanwy*, (*frederick*, *eleanor*), dead, male);

*myfanwy* := ("Jones", "Myfanwy", skip, skip, *emrys*, *children of emrys*, alive, female);

*frederick* := ("Jones", "Frederick", *emrys*, *myfanwy*, *nil*, ( ), alive, male);

*eleanor* := ("Jones", "Eleanor", *emrys*, *myfanwy*, *nil*, ( ), alive, female);

person *shem*, *ham*, *japhet*, *anarias*, *azarias*, *misael*, *tom*;

comment These are the unborn generations, and are therefore undefined.

comment

date := (1, "APR", 24); *marry*(*eleanor*, *ebenezer*);

date := (1, "JAN", 25); *generate*(*shem*, *ebenezer*, *eleanor*, "Shem", male);

comment We don't waste much time in this program. comment

date := (31, "MAR", 26); *generate*(*ham*, *ebenezer*, *eleanor*, "Ham", male);

date := (3, "MAR", 28); *generate*(*japhet*, *ebenezer*, *eleanor*, "Japhet", male);

comment This will produce the example given in the proc *generate*. comment

date := (14, "JUL", 48);

comment Now we need to declare some eligible young ladies. comment

person *a*, *b*, *josie*, *rosie*;

*josie* := ("Smith", "Josephine", *a*, *b*, *nil*, ( ), alive, female);

*rosie* := ("Smith", "Rose", *a*, *b*, *nil*, ( ), alive, female);

*marry*(*josie*, *shem*);
date := (23, "JAN", 49); generate(ananias, shem, josie,
"Ananias", male);

comment Well, perhaps it was premature. comment

date := (14, "DEC", 50); generate(azarias, shem, josie,
"Azarias", male);

date := (29, "FEB", 52); kill(josie);

comment Alas ! But . . . comment

date := (28, "DEC", 52); marry(rosie, shem);

comment There are some interesting ecclesiastical problems in that one.

comment

date := (14, "JAN", 54); generate(misael, shem, rosie,
"Misael", male);

comment Here is a not-so-eligible young lady: comment

person x := (skip, skip, skip, skip, nil, skip, alive, female);

date := (20, "DEC", 68); generate(tom, azarias, x, "Tom", male);

comment And so the permissive society has arrived. Nothing will be printed.

comment

date := (21, "DEC", 68); kill(ebenezer);

comment Poor chap! This will produce the example given in the proc kill.

comment

newline(file); newline(file) & to ensure that the final contents of buffer get
printed &

end

Vertical readers, please turn to 1.7.

8.7. Examples of everything

8.7.1. Analytic differentiation

This example is intended to illustrate how generators can be used to
achieve more efficiently results which would formerly have necessitated the
use of some list-processing language.

The following program will accept a series of expressions punched in a
convenient notation, differentiate each one, and print the result in the same
notation.

begin

mode formula = struct/operand left, int operator, operand right);

int plus = 1, minus = 2, times = 3, over = 4, to = 5;

mode operand = union/ref formula, var, const);

mode var = ref struct/string s, var next);
**comment** We propose to ensure below that all **var** values refer to structures containing distinct **strings**. Hence equality of two such **strings** implies identity of their **vars**. **comment**

`mode const = struct(real r);`

**comment** The mode **const** is different from the mode **real** in order that the operator + to be declared between **operands** should not be confused with the already existing operator + between **reals**. I.e. **const**, declared thus, is not firmly related to **operand** (4.3.3), and neither is **var**. **comment**

`op con = (real a)const: (const b; r of b := a; b);`

`op = = (const a, b)bool: (r of a = r of b);`

`const zero = con 0.0, one = con 1.0;`

`op += (operand a, b)operand:`

`begin`

`case a in`

(const c):

`case b in`

(const d): con (r of c + r of d)

¢ This is the one case where we can use the
standard version of + (between two reals)

to do some real arithmetic. ¢

`out (c = zero | b | goto formula) ¢ 0 + b = b ¢`

`esac`

`out case b in`

(const d): (d = zero | a | goto formula) ¢ a + 0 = a ¢

`out goto formula`

`esac`

`esac`

`exit`

**formula:** ¢ No simplification was possible. We now have no alternative
but to generate a new piece of tree on the heap ¢

**heap formula** := `(a, plus, b)`

`end ¢ of + ¢;`

`op - = (operand a, b)operand:`

`begin`

`case b in`

(const d):

`case a in`

(const c):

(real x := r of c - r of d;

(x > 0 | con x | goto formula) )
out (d = zero | a | goto formula) ¢ a - 0 = a ¢

esac,

(var t):

case a in

(var s): (s :=: t | zero | goto formula) ¢ a - a = 0 ¢

out goto formula

esac

out goto formula

¢ We do not attempt to produce the value -b here when a is zero,
because our system has no provision for a monadic minus. ¢

esac

exit

formula: heap formula := (a, minus, b)

end ¢ of - ¢;

op x = (operand a, b)operand:

begin

case a in

(const c):

case b in

(const d): con (r of c x r of d)

out (c = zero | zero ¢ 0 x b = 0 ¢
|: c = one | b ¢ 1 x b = b ¢
| goto formula)

esac

out case b in

(const d):

(d = zero | zero ¢ a x 0 = 0 ¢
|: d = one | a ¢ a x 1 = a ¢
| goto formula)

out goto formula

esac

esac

exit

formula: heap formula := (a, times, b)

end ¢ of x ¢;

op / = (operand a, b)operand:

begin

case a in

(const c):

case b in
(const d): con (r of c / r of d)

out (c = zero | zero | goto formula) ¢ 0 / b = 0 ¢

esac

out case b in

(const d):

(d = zero | goto help ¢ a/0 is undefined ¢

: d = one | a ¢ a/1 = a ¢

| goto formula)

out goto formula

esac

esac

exit

formula: heap formula := (a, over, b)

end ¢ of / ¢;

op ↑ = (operand a, b)operand:

begin

case b in

(const d):

case a in

(const c): con exp(ln(r of c) × r of d)

out (d = zero | one ¢ a ↑ 0 = 1 ¢

: d = one | a ¢ a ↑ 1 = a ¢

| goto formula)

esac

out goto formula

esac

exit

formula: heap formula := (a, to, b)

end ¢ of ↑ ¢;

comment We shall now arrange to read in expressions consisting of strings
(for variables), constants, the operators +, -, ×, /, and ↑, and pairs of
parentheses, each expression being terminated by a semicolon. Spaces and
newlines will be ignored in plausible places. Each expression read in is to
be stored, on the heap, as an operand. comment

make term (stand in, "+−x/↑( )⊥;";

comment These will be regarded as terminating a variable. comment

on logical file end (stand in, (ref file f)bool: goto stop);

comment When we have read all the expressions, we shall have finished the
program. comment
var *string list* := nil;

comment We shall use this to record all the variables met so far. Initially, it points to an empty chain. comment

proc get var or const = union/var, const, void):

begin string s, real x, file fool := stand in,

var *pointer* := *string list*;

on char error(fool,

(ref file f, ref char c)/void:

(backspace(f); goto notreal);

comment We had to invent *fool*, for local use, to avoid scope troubles.

We are now going to try to read a real. If the next thing on the input stream (ignoring any spaces and newlines) is not a constant, in some readable format (see 7.1.2), the *char error* event will be called, and we shall presume it was a variable. comment

get (fool, x);

con x exit ¢ con x is now united to union(var, const, void) ¢

notreal: read(s); ¢ up to one of the term chars, or end of line. ¢

if s = "" then empty

comment We met a term *char* straight away. comment

elif while (var/pointer) :‡: nil

| s of *pointer* ‡ s | false)

do *pointer* := .next of *pointer* od;

comment We see if we have had this string before. comment

var/pointer) :‡: nil then *pointer*

comment We have, so we yield the old var containing it. comment

else string list := heap struct(string s, var next)

:= (s, string list)

comment It is a newcomer. We have made a copy of it on the heap and inserted it at the start of the chain. comment

fi

comment The value of this conditional-clause is either a *var* or is *empty*.

It is now united to union (var, const, void) comment

end ¢ of get var or const ¢;

comment The next procedure is going to read an operand. It reads the first variable or constant itself, with the following operator, and then calls itself recursively to deal with the rest. Its int formal-parameter is used to convey the priority of the operator currently being processed.

comment
proc *read operand* = (*int priority*)*operand*:

begin operand operand, char c, int operator;

case get var or const in

(const x): operand := x,

(var s): operand := s,

(void):

if read(c); c ≠ "(" then goto help

else operand := read operand(1)

fi

comment If we meet an opening parenthesis, we are to start again at
priority one. comment

esac;

loop: while read(c);

comment get the operator after the first operand. comment

if ¬char in string (c, operator, "_,")+-x/↑")

then goto help

fi;

operator = 1

do skip od ¢ ignore spaces ¢;

operator -:= 2;

¢ ; = 0

) = 1

+ = 2

- = 3

x = 4

/ = 5

↑ = 6 ¢

if operator ≤ priority

then (operator > 1 ∨ operator < priority | backspace(stand in));

operand

comment If the next operator is of lower or equal priority to the one
currently on hand, we ignore it for the time being, and yield what we
have got so far. This is in fact the only exit from this procedure. Note
that ; and ) are bound to take this path. comment

else operand := case operator - 1 in

operand + read operand(2),

operand - read operand(3),

operand × read operand(4),

operand / read operand(5),
operand ↑ read operand(6) esac;
goto loop

fi

end & of read operand ¢;

comment Suppose we were now to write:

var x := (read operand(0) | (var s): s | help));

operand f = read operand(0)

and suppose that the book being read contained, at its current position:

ex;
ex↑2 x(ex-2)↑ (fred-bill);

then, after elaboration of these phrases, we should have the following
situation:

<figure><img src="image_85.png" /></figure>

Note that everything inside the dotted line is on the heap.
Now we shall write our procedure to differentiate an operand with respect to a variable. **comment**

proc `diff` = (operand `d`, `¢` `wrt` `¢` var `x`) operand:

case `d` in

(const): zero,

(var `s`): (`s` := `x` | one | zero),

**comment** The use of an identity-relation is quick and safe here because we ensured, during *get var or const*, that if `s` and `x` refer to structures containing identical *strings*, then they do in fact refer to the same structure **comment**

(ref formula *form*):

begin ref operand `left` = `left` of *form*,

`right` = `right` of *form*;

case operator of *form* in

`¢` + `¢` `diff`(left, `x`) + `diff`(right, `x`),

`¢` - `¢` `diff`(left, `x`) - `diff`(right, `x`),

`¢` x `¢` `diff`(left, `x`) x `right` + `diff`(right, `x`) x `left`,

`¢` / `¢` (`diff`(left, `x`) - `diff`(right, `x`) x `d`) / `right`,

`¢` ↑ `¢` begin

proc `checkforx` = (operand `f`, var `x`) bool:

`(f |`

(ref formula *form*):

`checkforx`(left of *form*, `x`) ∨

`checkforx`(right of *form*, `x`),

(var `s`): `s` := `x`

| `false`;

**comment** That was a conformity-clause, in case you didn't notice.

This proc yields **true** if `f` is a function of `x`. **comment**

if `checkforx`(right, `x`) then goto *help*

**comment** The present program does not purport to cope with this case.

**comment**

else `right` x `left` ↑ (`right` - `one`) x `diff`(left, `x`)

fi

end

esac

end

esac;

**comment** Now we ought to have a procedure to print our results **comment**

proc `print operand` = (operand operand, int `priority`) void:

case operand in
(const x): printf($2zd.3d$, r of x)),

(var s): print(s of s),

(ref formula f):

if int i; (i := entier((operator of f + 1) / 2)) < priority

then print("(");
          print operand(f, 0);
          print(")")

else print operand(left of f, i);
                  print("+--x/↑"[operator of f]);
                  print operand(right of f, i)

fi

esac;

comment Now we come to the rest of the body of our program (you will have noticed that it actually started when we called *make term* a little way back). comment

do ¢ ad nauseam, or at least until the logical file end event happens ¢
    newline(stand out);

case read operand(0) in

(var x): print operand(diff(read operand(0), x), 0)

out goto help

esac

od;

help: print("This is not a legitimate case for this program")

comment In the best circles, the program should here print out some more informative diagnostic message, but to include such in our present example would be tedious rather than instructive. comment

end

Suppose, now, that this program were to be offered as input the piece of text we discussed earlier. Then, during the elaboration of the *print operand*, its formal-parameter *operand* would be as in the scheme on the next page.

The bottom part of the picture is, of course, that which you saw in the
previous diagram.

Note that all the items shown here are on the heap, and that at this instant there is only one of them that is pointed to, and which is therefore available for garbage collection. As soon as *print operand* has been elaborated, they will all become garbage.

If you follow through the operation of the program on this example, you
will see that the number of items generated would have been much greater
had it not been for the facilities for dealing with singular cases (*1 x x, a + 0*,
<figure><img src="image_86.png" /></figure>

operand

operand

ref formula

formula

nil

ex

fred

bill
etc.) in the operation-declarations. When the elaboration of *print operand* is over, it will have printed the following:

$$2.000 \times \text{ex} \times (\text{ex} - 2.000) \uparrow (\text{fred-bill}) + (\text{fred-bill}) \times (\text{ex} - 2.000) \uparrow (\text{fred-bill} - 1.000) \times \text{ex} \uparrow 2$$

For a slightly different treatment of problems of this nature, you might now like to study example R 11.10 in the Report.
# APPENDICES

## APPENDIX 1. Alternative Representations

As explained in 0.2 and 1.3.3, the Report provides representations for all the symbols needed to construct an ALGOL 68 program, and in this Introduction we have adhered to these (as indeed will most implementations). In many cases, however, the Report provides two or more representations for the one symbol. Usually, one is a bold word (1.3.2) and the other a distinct graphic mark. These bold words are described as "reserved", which means that you are forbidden to redeclare them as mode-indications or operators of your own (imagine the ambiguities that would arise if you could declare begin to be an operator). Here then is a list of all the reserved bold words, together with their graphic alternatives, if any.

<table><tr><td>begin end</td><td>( )</td><td>3.2.4.1</td></tr><tr><td>if then elif else fi</td><td>(||:|)</td><td>3.2.4.2</td></tr><tr><td>case in ouse out esac</td><td>(||:|)</td><td>3.2.4.3, 3.6</td></tr><tr><td>for from by to while do od</td><td></td><td>3.5.2</td></tr><tr><td>par</td><td></td><td>3.7.2</td></tr><tr><td>exit</td><td></td><td>3.1.4</td></tr><tr><td>at</td><td>@</td><td>5.5.1.3</td></tr><tr><td>is</td><td>:=:</td><td>5.7.4</td></tr><tr><td>isnt</td><td>:=: :/=:</td><td>5.7.4</td></tr><tr><td>of</td><td></td><td>5.4.2</td></tr><tr><td>goto go to</td><td></td><td>4.7.1</td></tr><tr><td>skip</td><td>~</td><td>5.1.4.2</td></tr><tr><td>comment co</td><td>¢ #</td><td>1.3.2</td></tr><tr><td>pragmat pr</td><td></td><td>1.3.2</td></tr><tr><td>true false empty</td><td></td><td>5.1.1.1, 5.6.1</td></tr><tr><td>nil</td><td>o</td><td>5.2.3</td></tr><tr><td>long short ref loc heap struct flex proc union</td><td></td><td>2</td></tr><tr><td>mode prio op</td><td></td><td>2.3, 4.3.1, 4.3.2</td></tr><tr><td>int real bool char compl bits bytes string</td><td></td><td>2</td></tr><tr><td>sema file channel format</td><td></td><td>3.7.2, 7.2.1, 7.6.2</td></tr><tr><td>void</td><td></td><td>1.2.3</td></tr><tr><td>[]</td><td>( )</td><td>5.5.1.3</td></tr><tr><td>10</td><td>\</td><td>5.5.1.1</td></tr><tr><td>(i.e. a blank)</td><td>±</td><td>5.5.1.1</td></tr></table>

The bold words defined in the standard-prelude as operators, however, are
not reserved (you can redeclare them if you like). Moreover, where several symbols are declared as operators with the same function, they really ought not to be regarded as alternative versions of the same symbol for, if you redeclare the meaning of not, for example, the meaning of ⌜ and of ~ remains unchanged, unless you redeclare them too. Bearing this in mind, we give now a list of all those functions for which several operators are defined:

<table><tr><td>not</td><td></td><td></td><td>6.1.1</td></tr><tr><td>entier</td><td></td><td></td><td>6.1.1</td></tr><tr><td>i</td><td></td><td>+x</td><td>6.1.2</td></tr><tr><td>↑</td><td>**</td><td>up</td><td>6.1.2</td></tr><tr><td>shl</td><td>up</td><td></td><td>6.1.2</td></tr><tr><td>shr</td><td>down</td><td>↓</td><td>6.1.2</td></tr><tr><td>÷</td><td>%</td><td>over</td><td>6.1.2</td></tr><tr><td>mod</td><td>÷x</td><td>%x</td><td>6.1.2</td></tr><tr><td>x</td><td>*</td><td></td><td>6.1.2</td></tr><tr><td>elem</td><td>□</td><td></td><td>6.1.2</td></tr><tr><td>&lt;</td><td></td><td>lt</td><td>6.1.2</td></tr><tr><td>≤</td><td>&lt;=</td><td>le</td><td>6.1.2</td></tr><tr><td>≥</td><td>&gt;=</td><td>ge</td><td>6.1.2</td></tr><tr><td>&gt;</td><td></td><td>gt</td><td>6.1.2</td></tr><tr><td>=</td><td></td><td>eq</td><td>6.1.2</td></tr><tr><td>‡</td><td>/=</td><td>ne</td><td>6.1.2</td></tr><tr><td>∧</td><td>&amp;</td><td>and</td><td>6.1.2</td></tr><tr><td>V</td><td></td><td>or</td><td>6.1.2</td></tr><tr><td>timesab</td><td>x:=</td><td>*:=</td><td>6.3</td></tr><tr><td>overab</td><td>÷:=</td><td>:=</td><td>6.3</td></tr><tr><td>divab</td><td>/:=</td><td></td><td>6.3</td></tr><tr><td>modab</td><td>÷x:=</td><td>%x:=</td><td>6.3</td></tr><tr><td>plusab</td><td>+:=</td><td></td><td>6.3</td></tr><tr><td>plusto</td><td>+:=</td><td></td><td>6.3</td></tr><tr><td>minusab</td><td>-:=</td><td></td><td>6.3</td></tr><tr><td>lwb</td><td></td><td></td><td>6.3</td></tr><tr><td>upb</td><td></td><td></td><td>6.5</td></tr></table>
## APPENDIX 2. Sample Declarations

The following is a summary of the sample declarations introduced in Chapter 0, with some others from R 1.1.2.

int i, j, k, m, n;

real a, b, x, y;

real e = c a real value close to the base of natural logarithms,
         i.e. 2.718281828...c;

bool p, q, overflow;

char c;

ref real xx, yy;

compl w, z;

format f;

bytes r;

bits t;

mode vec = struct (real xcoord, ycoord, zcoord);

vec v1, v2, v3;

mode rational = struct (int numerator, denominator);

rational r1, r2, r3;

string s;

union (int, real) uir;

proc void task1, task2;

[1 : n] real x1, y1;

flex [1 : n] real a1;

[1 : m, 1 : n] real x2;

[1 : n, 1 : n] real y2;

[1 : n] int i1;

[1 : m, 1 : n] int i2;

[1 : n] compl z1;

proc x or y = ref real: (random < .5 | x | y);

proc ncos = (int i) real: cos (2 x pi x i/n);

proc nsin = (int i) real: sin (2 x pi x i/n);

proc finish = void: goto stop;

mode book = struct (string text, ref book next);

book draft;

op i = (int a) compl: (0, a);

op i = (real a) compl: (0, a);

princeton: grenoble: st pierre de chartreuse: kootwijk:

warsaw: zandvoort: amsterdam: tirrenia: north berwick: munich:
## APPENDIX 3. Glossary

The Report defines a vast number of new technical terms. In this Informal Introduction we have used those of them which we think could or should come into general use within the computing community. We have also invented one or two of our own (we hope they will be acceptable to you — they are marked with an * in the lists below), and occasionally the meaning of one of our terms differs slightly from its meaning in the Report (as marked with a † below).

We define below the meaning of the principal terms. For the others, you may follow the references given to their "defining occurrences" in our text. Usually, there are two such references — one to the basic concept in Chapter 1, and one to its practical realisation in Chapters 2 through 7.

### 1. Internal objects and modes

<table><tr><td>internal object</td><td>1.1.1</td><td>An object which is stored and manipulated inside the computer; i.e. an instance of a value.</td></tr><tr><td>* instance (of a value)</td><td>1.1.1</td><td>a:=2; b:=2; There are now two instances of the value "2". If we assign to h a "3", then we may say "an instance of 2 has been superseded by an instance of 3", but not that "the value of b, which was 2, is now 3".</td></tr><tr><td>mode</td><td>1.1.1 1.2.3</td><td>The property of a value (and therefore of an instance) which defines the class to which it belongs, i.e. the amount of storage space it requires, its compatibility with other values with which it may be confronted, etc. A mode can also be a property of an external object if that object yields a value of that mode.</td></tr><tr><td>value</td><td>1.1.1</td><td>The ultimate object processed by the operations of the language; e.g. a number, a character, a structure, etc.</td></tr></table>

In our text, we use formal-declarers (e.g. **int**, **ref real**, [ ] **ref compl**) to specify modes, and also to indicate values of those modes. There is no
ambiguity. If we use such a declarer as a noun, it indicates (an instance of) a value. If we use it as an adjective, it is a mode — "The mode of an int is int".

<table><thead><tr><th>primitive modes</th><th></th><th></th></tr></thead><tbody><tr><td></td><td>1.2.3 2.1.1</td><td>The built-in modes in terms of which all other modes may be constructed.</td></tr><tr><td>int</td><td>2.1.1</td><td></td></tr><tr><td>real</td><td>2.1.1</td><td></td></tr><tr><td>bool</td><td>2.1.1</td><td></td></tr><tr><td>char</td><td>2.1.1</td><td></td></tr><tr><td>bits</td><td>2.7.1</td><td></td></tr><tr><td>bytes</td><td>2.7.1</td><td></td></tr><tr><td>void</td><td>1.2.3</td><td></td></tr><tr><td>ref</td><td>1.2.3</td><td rowspan="2">Prefixes used to construct declareders (e.g. ref real, union (int, real), proc (real) int) or to specify all the modes of the appropriate class (e.g. proc modes, 'row of' modes, etc.), or to indicate values of those classes of modes.</td></tr><tr><td>'row of' rowed<br/>[]</td><td>1.4.0 2.5.1</td></tr><tr><td>struct</td><td>1.2.3 2.4.1</td><td rowspan="5">Derived modes built into the language.</td></tr><tr><td>union</td><td>1.2.3 2.6.1</td></tr><tr><td>proc</td><td>1.2.3 4.2.1</td></tr><tr><td>long</td><td>1.2.3 2.7.2</td></tr><tr><td>short</td><td>1.2.3 2.7.2</td></tr><tr><td>string</td><td>2.5.3</td><td rowspan="5">A value of mode int, real, bool, char, bits or bytes.</td></tr><tr><td>sema</td><td>3.7.2</td></tr><tr><td>file</td><td>7.2.1</td></tr><tr><td>channel</td><td>7.2.1</td></tr><tr><td>format</td><td>7.6.2</td></tr><tr><td>primitive value</td><td></td><td>A value whose mode is ref some other mode, and which refers to a value of that other mode.</td></tr><tr><td>name</td><td>1.1.1</td><td></td></tr><tr><td>subname</td><td>1.4.1.2</td><td>If a name N refers to a multiple (a structure) V then the sub-names of N refer to the sub-values (the fields) of V.</td></tr><tr><td>fixed name</td><td>2.5.2.1</td><td>The bounds of a multiple assigned to a fixed name must match the existing bounds.</td></tr><tr><td>flexible name</td><td>1.5.3 2.5.2.1</td><td>Assignation of a multiple to a flexible name may change the existing bounds.</td></tr><tr><td>transient name</td><td>5.5.1.3</td><td>A subname of a flexible name.</td></tr></tbody></table>
<table><tr><td>* structure<br>structured value<br>struct<br>field<br>multiple value<br>* multiple</td><td>1.4.0 2.4.1<br>1.4.0<br>1.4.0.1.5.1</td><td>A value consisting of several<br>fields, each being a value of<br>some other mode.</td></tr><tr><td>element<br>subvalue</td><td>1.4.0 1.5.1<br>1.5.2 5.5.1.3</td><td>A value consisting of a sequence of values, its "elements",<br>of some (same) mode, together with a descriptor.</td></tr><tr><td>descriptor<br>routine</td><td>1.5.1<br>1.1.4 4.2.2</td><td>A subset of the elements of a<br>multiple, as specified by a<br>different descriptor.<br>See under external objects.<br>The internal equivalent of a<br>routine-text - a value of a<br>proc mode.</td></tr><tr><td>† constant</td><td>1.1.1 1.2.2.1</td><td>A value which has been ascribed<br>to an external object. Therefore,<br>no name refers to it, and it<br>cannot be changed. See also<br>under external objects.</td></tr><tr><td>† variable</td><td>1.1.2.1 1.2.2.4</td><td>An instance of a value to<br>which a name refers (so that<br>it can be changed), together<br>with that name.</td></tr><tr><td>subscript<br>boundpair</td><td>1.5.1<br>1.5.1</td><td></td></tr></table>

## 2. External objects

Most of the terms defined below are in fact what the Report would class as "paranotions" (see R 1.1.4.2). For this reason, at their defining occurrences in our text they are enclosed between single quotes (e.g. 'serial-clause') and they are hyphenated, whereas our defining occurrences of other technical terms are in double quotes.

<table><tr><td>construct (or external<br>object)</td><td>1.1.1</td><td>A part of a program text, as<br>classified below.</td></tr><tr><td>program</td><td>1.1</td><td>The program text provided by<br>the user, together with the<br>standard- and library-preludes<br>and the standard-postlude.</td></tr><tr><td>particular-program</td><td>1.1 3.1</td><td>The program text provided by<br>the user, on its own.</td></tr></table>
<table><tr><td>standard-prelude</td><td>1.1 4.1 6</td><td>The declarations already built into the language.</td></tr><tr><td>library-prelude</td><td>1.1</td><td>Additional built in declarations, peculiar to the particular implementation.</td></tr><tr><td>* standard-postlude</td><td>1.1</td><td>The administration of the completion of the program, following the label stop.</td></tr><tr><td>phrase</td><td>1.1.3</td><td>A declaration or a clause.</td></tr><tr><td>declaration</td><td>1.1.3 2</td><td></td></tr><tr><td>* collateral-declaration</td><td>1.1.3 2.1.2</td><td>A list of declarations, separated by commas.</td></tr><tr><td>identifier-declaration</td><td>1.1.2 2.2</td><td></td></tr><tr><td>identity-declaration</td><td>1.2.2 2.2.1</td><td>Ascribes a value to an identifier</td></tr><tr><td>variable-declaration</td><td>1.1.2.1 2.1.2</td><td></td></tr><tr><td>routine-identity-declaration</td><td>1.2.3.1 4.2.2.1</td><td></td></tr><tr><td>routine-variable-declaration</td><td>4.2.2.1</td><td></td></tr><tr><td>mode-declaration</td><td>1.3.3.1</td><td>Causes a mode-indication to specify a mode.</td></tr><tr><td>mode-indication</td><td>1.3.3.1</td><td>A bold word that has been declared to specify a mode.</td></tr><tr><td>priority-declaration</td><td>1.3.3.3 4.3.1</td><td></td></tr><tr><td>operation-declaration</td><td>1.3.3.2 4.3.2</td><td>Ascribes a routine to an operator.</td></tr><tr><td>declarer</td><td></td><td>An external object which specifies some mode.</td></tr><tr><td>actual-declarer</td><td>2.1.2 2.2.2 2.5.2.2</td><td></td></tr><tr><td>formal-declarer</td><td>1.2.2 2.2.1</td><td></td></tr><tr><td>† descriptor</td><td>1.5.1</td><td>At run time, an internal object has to be kept for each multiple value and subvalue to record the values of its bounds. This is called, in the Report, a "descriptor". We also apply this term to that external object which conveys the same information, viz. the list of boundpairs enclosed between "[" and "]" which appears in the actual-declarer of a 'row of' mode.</td></tr></table>
<table>
  <tbody>
    <tr>
      <td>boundpair</td>
      <td>1.5.1</td>
      <td></td>
    </tr>
    <tr>
      <td>bound</td>
      <td>1.5.1</td>
      <td></td>
    </tr>
    <tr>
      <td>parameter</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>formal-parameter</td>
      <td>1.2.2 2.2.1</td>
      <td></td>
    </tr>
    <tr>
      <td>actual-parameter</td>
      <td>1.2.2 2.2.1</td>
      <td></td>
    </tr>
    <tr>
      <td>clause</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>ENCLOSED-clause</td>
      <td>3.2.4</td>
      <td></td>
    </tr>
    <tr>
      <td>closed-clause</td>
      <td>1.1.3 3.2.4.1</td>
      <td>A serial-clause enclosed between begin and end or "(" and ")".</td>
    </tr>
    <tr>
      <td>collateral-clause</td>
      <td>3.7.1</td>
      <td></td>
    </tr>
    <tr>
      <td>row-display</td>
      <td>3.5.1</td>
      <td></td>
    </tr>
    <tr>
      <td>vacuum</td>
      <td>3.5.1</td>
      <td></td>
    </tr>
    <tr>
      <td>structure-display</td>
      <td>3.4</td>
      <td></td>
    </tr>
    <tr>
      <td>and-also-symbol</td>
      <td>1.1.3</td>
      <td></td>
    </tr>
    <tr>
      <td>parallel-clause</td>
      <td>3.7.2</td>
      <td>A void-collateral-clause preceded by par.</td>
    </tr>
    <tr>
      <td>conditional-clause</td>
      <td>3.2.4.2</td>
      <td>if XXXX then XXXX else XXXX fi</td>
    </tr>
    <tr>
      <td>case-clause</td>
      <td>3.2.4.3</td>
      <td>case XXXX in XXXX, XXXX out XXXX esac</td>
    </tr>
    <tr>
      <td>conformity-clause</td>
      <td>1.6.2 3.6</td>
      <td></td>
    </tr>
    <tr>
      <td>specification</td>
      <td>3.6</td>
      <td></td>
    </tr>
    <tr>
      <td>loop-clause</td>
      <td>3.5.2</td>
      <td></td>
    </tr>
    <tr>
      <td>serial-clause</td>
      <td>1.1.3 3.1 3.1.5</td>
      <td></td>
    </tr>
    <tr>
      <td>completer</td>
      <td>3.1.4</td>
      <td rowspan="2">Constituents of serial-clauses.</td>
    </tr>
    <tr>
      <td>label</td>
      <td>3.1.2</td>
    </tr>
    <tr>
      <td>go-on-symbol</td>
      <td>1.1.3 3.1</td>
      <td rowspan="2">A semicolon.</td>
    </tr>
    <tr>
      <td>enquiry-clause</td>
      <td>3.2.4.2</td>
    </tr>
    <tr>
      <td>range</td>
      <td>1.1.3 3.2.1</td>
      <td>A piece of program text (usually a serial-clause) which demarcates the scope of the variables which are locally generated during its elaboration.</td>
    </tr>
    <tr>
      <td>reach</td>
      <td>3.2.1</td>
      <td>A range, with the exclusion of all ranges contained within it.</td>
    </tr>
    <tr>
      <td>unit</td>
      <td>1.1.3 5.1</td>
      <td></td>
    </tr>
    <tr>
      <td>coercend</td>
      <td>5.1.0.1</td>
      <td></td>
    </tr>
    <tr>
      <td>* quaternary</td>
      <td>5.1.0.1</td>
      <td rowspan="2">The same thing as a unit.</td>
    </tr>
    <tr>
      <td>assignation</td>
      <td>1.1.2.2 5.1.4.1</td>
    </tr>
  </tbody>
</table>
<table>
  <tbody>
    <tr>
      <td>destination</td>
      <td>1.1.2.2</td>
      <td>The LHS of an assignation</td>
    </tr>
    <tr>
      <td>source</td>
      <td>1.1.2.2</td>
      <td>The RHS of an assignation</td>
    </tr>
    <tr>
      <td>identity-relation</td>
      <td>1.7.2 5.7.4</td>
      <td>:= or :&plusmn;</td>
    </tr>
    <tr>
      <td>routine-text</td>
      <td>1.1.4 4.2.2.1</td>
      <td></td>
    </tr>
    <tr>
      <td>tertiary</td>
      <td>5.1.0.1</td>
      <td></td>
    </tr>
    <tr>
      <td>formula</td>
      <td>1.1.4 5.1.0.1 5.1.3</td>
      <td></td>
    </tr>
    <tr>
      <td>operator</td>
      <td>1.1.4 6.1</td>
      <td></td>
    </tr>
    <tr>
      <td>monadic-operator</td>
      <td>1.3.3.2 5.1.3</td>
      <td>With one following operand.</td>
    </tr>
    <tr>
      <td>dyadic-operator</td>
      <td>1.3.3.2 5.1.3</td>
      <td>Between two operands.</td>
    </tr>
    <tr>
      <td>operand</td>
      <td>1.1.4 5.1.3</td>
      <td>A secondary or another formula.</td>
    </tr>
    <tr>
      <td>secondary</td>
      <td>5.1.0.1</td>
      <td></td>
    </tr>
    <tr>
      <td>selection</td>
      <td>5.4.2</td>
      <td>of</td>
    </tr>
    <tr>
      <td>field-selector</td>
      <td>1.4.1 2.4.1</td>
      <td></td>
    </tr>
    <tr>
      <td>generator</td>
      <td>1.2.2.3 5.7.2</td>
      <td>The means of making storage space available for variables.</td>
    </tr>
    <tr>
      <td>loc generator</td>
      <td>1.2.2.3 5.7.2.1</td>
      <td></td>
    </tr>
    <tr>
      <td>heap generator</td>
      <td>5.7.2.2</td>
      <td></td>
    </tr>
    <tr>
      <td>primary</td>
      <td>5.1.0.1</td>
      <td></td>
    </tr>
    <tr>
      <td>denotation</td>
      <td>5.1.1.1</td>
      <td>Denotations are provided for ints, reals, bools, chars, strings, bits, and the long(s) versions (if any) of these.</td>
    </tr>
    <tr>
      <td>cast</td>
      <td>1.2.2.5 5.1.1.3</td>
      <td></td>
    </tr>
    <tr>
      <td>format-text</td>
      <td>7.6.1</td>
      <td>The specification of the layout of the characters produced or expected during transput.</td>
    </tr>
    <tr>
      <td>picture</td>
      <td>7.6.1</td>
      <td>To be matched against a single value.</td>
    </tr>
    <tr>
      <td>insertion</td>
      <td>7.6.1</td>
      <td></td>
    </tr>
    <tr>
      <td>literal</td>
      <td>7.6.1.1</td>
      <td></td>
    </tr>
    <tr>
      <td>alignment</td>
      <td>7.6.1.2</td>
      <td></td>
    </tr>
    <tr>
      <td>frame</td>
      <td>7.6.1.3</td>
      <td></td>
    </tr>
    <tr>
      <td>replicator</td>
      <td>7.6.1.4</td>
      <td></td>
    </tr>
    <tr>
      <td>dynamic replicator</td>
      <td>7.6.1.4</td>
      <td></td>
    </tr>
    <tr>
      <td>† collection</td>
      <td>7.6.1.4</td>
      <td>A collection of pictures, to be replicated.</td>
    </tr>
    <tr>
      <td>identifier</td>
      <td>1.1.2 5.1.1.2</td>
      <td></td>
    </tr>
  </tbody>
</table>
<table>
  <tr>
    <td>defining-identifier</td>
    <td>3.2.3</td>
    <td></td>
  </tr>
  <tr>
    <td>applied-identifier</td>
    <td>3.2.3 5.1.1.2</td>
    <td></td>
  </tr>
  <tr>
    <td>call</td>
    <td>5.2.1</td>
    <td>Of a procedure with parameters.</td>
  </tr>
  <tr>
    <td>slice</td>
    <td>1.5.4 5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>† indexer</td>
    <td>1.5.2 5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>trimscript</td>
    <td>1.5.2.1 5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>trimmer</td>
    <td>1.5.2.1 5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>subscript</td>
    <td>1.5.2.1 5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>revised-lower-bound</td>
    <td>5.5.1.3</td>
    <td></td>
  </tr>
  <tr>
    <td>expression</td>
    <td>3.1 5.1.0.1</td>
    <td>A unit which yields a value.</td>
  </tr>
  <tr>
    <td>statement</td>
    <td>3.1 5.1.0.1</td>
    <td>A unit which yields void.</td>
  </tr>
  <tr>
    <td>† constant</td>
    <td>1.2.2.1</td>
    <td>A coercend (usually an identifier) which yields a value which is not a name. See also under internal objects.</td>
  </tr>
  <tr>
    <td>variable</td>
    <td>1.2.2.4</td>
    <td>A coercend (usually an identifier) which yields a name. See also under internal objects.</td>
  </tr>
  <tr>
    <td>* procedure</td>
    <td>4.2.1</td>
    <td>A coercend (usually an identifier or a routine-text) which yields a value of a proc mode.</td>
  </tr>
  <tr>
    <td>* LHS</td>
    <td>1.1.2.2</td>
    <td>The left hand side of an assignment or identity-declaration.</td>
  </tr>
  <tr>
    <td>* RHS</td>
    <td>1.1.2.2</td>
    <td>The right hand side.</td>
  </tr>
  <tr>
    <td>symbol</td>
    <td>1.3.1</td>
    <td>The smallest external object, out of which all the others are constructed, e.g. a, +, begin, etc.</td>
  </tr>
  <tr>
    <td>* bold word</td>
    <td>1.3.2</td>
    <td>A symbol, made up of underlined or bold faced characters (or otherwise), invented for use as a mode-indication or an operator.</td>
  </tr>
  <tr>
    <td>indicator</td>
    <td>1.1.1</td>
    <td>an identifier, a mode-indication or an operator.</td>
  </tr>
  <tr>
    <td>comment</td>
    <td>1.3.2</td>
    <td>May be inserted between any two symbols (except within a denotation or an identifier).</td>
  </tr>
  <tr>
    <td>pragmat</td>
    <td>1.3.2</td>
    <td></td>
  </tr>
</table>
3. Technical terms

<table><tr><td>contraction</td><td>1.1.3 2.1.2</td><td>Omission of redundant declarers, as in real a, b.</td></tr><tr><td>sublanguage</td><td>Appendix 4</td><td>A language (not ALGOL 68) all of whose particular-programs are also particular-programs of ALGOL 68 and have the same meaning [see R 2.2.2.c].</td></tr><tr><td>superlanguage</td><td>Appendix 4</td><td></td></tr><tr><td>* to stop</td><td>1.3.2</td><td>To construct bold words out of sequences of letters and digits by underlining, prefixing with a point, etc.</td></tr><tr><td>firmly related modes</td><td>4.3.3</td><td></td></tr><tr><td>* instance</td><td>1.1.1</td><td>Values have instances</td></tr><tr><td>occurrence</td><td>1.1.5</td><td></td></tr><tr><td>defining occurrence</td><td>1.1.5 3.2.3</td><td>Constructs have occurrences.</td></tr><tr><td>applied occurrence</td><td>1.1.5 3.2.3</td><td></td></tr><tr><td>scope</td><td>1.1.3 3.2.2</td><td>The scope of a value is the range (possibly the whole program) in which it is available for use.</td></tr><tr><td>reach (of a defining-indicator)</td><td>3.2.3</td><td>The part of a program text from which the given defining-indicator may be identified.</td></tr><tr><td>to yield</td><td>1.1.1</td><td>A construct yields a value.</td></tr><tr><td>to refer to</td><td>1.1.1</td><td>A name refers to a value.</td></tr><tr><td>to conform to</td><td>1.6.2 3.6</td><td>The yield of a union conforms to the mode actually in residence.</td></tr><tr><td>to identify</td><td>1.1.5 3.2.3</td><td>An applied occurrence identifies a defining occurrence.</td></tr><tr><td>to specify</td><td>1.4.1</td><td>A declarer specifies a mode.</td></tr><tr><td>to select</td><td>5.4.2</td><td>A field-selector selects a field from a structure.</td></tr><tr><td>to develop</td><td>1.3.3.1</td><td>To derive the mode specified by a mode-indication.</td></tr><tr><td>elaboration</td><td>1.1.1</td><td>The process of inspecting a construct and causing the corresponding actions (as specified by the semantics of the Report) to take place.</td></tr></table>
<table>
  <tr>
    <td>actions</td>
    <td>1.1.1</td>
    <td>The elementary operations (how elementary is not defined) which, when performed in the appropriate sequence, constitute the elaboration of a construct.</td>
  </tr>
  <tr>
    <td>collateral elaboration</td>
    <td>1.1.2.2 3.7.1</td>
    <td>An elaboration in which the actions required to elaborate certain phrases are merged in time, in a manner left undefined.</td>
  </tr>
  <tr>
    <td>* to supersede</td>
    <td>1.1.2.2</td>
    <td>To replace an instance of a value by another instance of a value.</td>
  </tr>
  <tr>
    <td>to call</td>
    <td>1.1.4 4.2.2</td>
    <td>To initiate the elaboration of a procedure.</td>
  </tr>
  <tr>
    <td>to parametrize</td>
    <td>1.2.3.2.1</td>
    <td>To substitute actual-parameters for formal ones.</td>
  </tr>
  <tr>
    <td>to complete</td>
    <td>3.1.4</td>
    <td>To finish the elaboration of a serial-clause by yielding a value, or void (from its final unit, or from an exit).</td>
  </tr>
  <tr>
    <td>to terminate</td>
    <td>3.1.4</td>
    <td>To finish the elaboration of a serial-clause abruptly, as when a jump is made out of it, or when some other elaboration collateral with it is terminated.</td>
  </tr>
  <tr>
    <td>to halt</td>
    <td>3.7.2</td>
    <td>To suspend the elaboration of a serial-clause temporarily, as in the operator down.</td>
  </tr>
  <tr>
    <td>to resume</td>
    <td>3.7.2</td>
    <td>To resume the elaboration of a clause that had been halted, as in the operator up.</td>
  </tr>
  <tr>
    <td>to ascribe</td>
    <td>1.1.1</td>
    <td>A value is ascribed to an indicator.</td>
  </tr>
  <tr>
    <td>to assign</td>
    <td>1.1.2.2</td>
    <td>A value is assigned to (the location addressed by) a name.</td>
  </tr>
  <tr>
    <td>coercion</td>
    <td>1.1.6 5.1.0</td>
    <td>The changing of the mode of a coercend to that required by its context, with a corresponding modification to the actions performed upon elaboration of that coercend.</td>
  </tr>
  <tr>
    <td>dereferencing</td>
    <td>1.1.6 5.1.0.3</td>
    <td></td>
  </tr>
  <tr>
    <td>widening</td>
    <td>5.1.0.4</td>
    <td></td>
  </tr>
</table>
<table>
  <tbody>
    <tr>
      <td>deproceduring</td>
      <td>4.2.2.2</td>
      <td>5.2.0.2</td>
      <td></td>
    </tr>
    <tr>
      <td>rowing</td>
      <td>5.5.0</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>uniting</td>
      <td>5.6.0</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>voiding</td>
      <td>5.7.0.1</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>balancing</td>
      <td>5.2.0.1</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>context</td>
      <td>5.1.0.2</td>
      <td></td>
      <td>The context of a coercend is its relationship to the clause in which it occurs. With each such context is associated a strength.</td>
    </tr>
    <tr>
      <td>strong</td>
      <td>5.1.0.2</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>firm</td>
      <td>5.1.0.2</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>weak</td>
      <td>5.1.0.2</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>meek</td>
      <td>5.1.0.2</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>soft</td>
      <td>5.1.0.2</td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td>STOWED</td>
      <td>1.4.0</td>
      <td></td>
      <td>Structured or rowed.</td>
    </tr>
    <tr>
      <td>stack (the)</td>
      <td>1.2.2.3</td>
      <td></td>
      <td>That part of the storage of the computer where internal objects created by <i>loc</i> generators are kept.</td>
    </tr>
    <tr>
      <td>heap (the)</td>
      <td>5.7.2.2</td>
      <td></td>
      <td>That part of the storage of the computer where internal objects that cannot be held on the stack are kept.</td>
    </tr>
    <tr>
      <td>flat descriptor</td>
      <td>1.5.1</td>
      <td>2.5.2.2</td>
      <td>A descriptor in which at least one upper-bound is less than its matching lower-bound.</td>
    </tr>
    <tr>
      <td>acceptable</td>
      <td>1.6.1.1</td>
      <td></td>
      <td>A value is acceptable to a <b>union</b> mode if its mode can be united to that <b>union</b>.</td>
    </tr>
    <tr>
      <td>garbage collection</td>
      <td>5.7.2.2</td>
      <td></td>
      <td>The process of recovering storage space on the heap from internal objects that are no longer accessible to the program.</td>
    </tr>
    <tr>
      <td>undefined</td>
      <td>1.1.2.2</td>
      <td></td>
      <td>If the result of some elaboration is said to be undefined, then the Report does not oblige an ALGOL 68 implementation to produce any specific result. In practice, implementations may produce</td>
    </tr>
  </tbody>
</table>
<table><tr><td>environment enquiry</td><td>6.2.1</td><td>diagnostic message, or go completely haywire.<br/>A constant made available by the standard or library prelude to convey information about some property of a particular implementation.</td></tr><tr><td>transput</td><td>7.1</td><td>Input and output and transfers to backing media.</td></tr><tr><td>formatless transput</td><td>7.1</td><td></td></tr><tr><td>formatted transput</td><td>7.6</td><td></td></tr><tr><td>binary transput</td><td>7.7</td><td></td></tr><tr><td>book</td><td>7.2.1</td><td>The input/output medium in use, together with its contents.</td></tr><tr><td>current position</td><td>7.2.1</td><td>The current page, line and character number of the book.</td></tr><tr><td>logical end of file</td><td>7.2.1</td><td>The last used page, line and character number of the book.</td></tr><tr><td>physical end of file</td><td>7.2.1</td><td>The last existing page, line and character number of the book.</td></tr><tr><td>channel</td><td>7.2.1</td><td>The facility through which transput to (from) the book takes place.</td></tr><tr><td>data list</td><td>7.1.1 7.1.2</td><td>A row-display of values used as a parameter of a transput procedure.</td></tr><tr><td>to open</td><td>7.2.1 7.2.3</td><td>To attach a book to a <b>file</b> through a <b>channel</b>.</td></tr><tr><td>to close</td><td>7.2.3</td><td>To disconnect a book from a <b>file</b>.</td></tr><tr><td>to straighten</td><td>7.4.1 7.5.1</td><td>To cause the elements of a multiple value or the fields of a structure to be presented in sequence as a stream of primitive (also <b>compl</b> or <b>string</b>) values.</td></tr></table>
# APPENDIX 4. The Sublanguage

The language realised by a particular implementation may differ from ALGOL 68 as defined by the Report. The differences may be of two sorts:

**Sublanguages.** If we omit some features of the language, or impose extra restrictions, then we have a "sublanguage" [R 2.2.2.c]. A particular-program written in a sublanguage should run without further ado on an implementation of the full language.

**Superlanguages.** If we add new features, or define the results of programs whose results are at present left undefined, then we have a "superlanguage". A particular-program written in canonical ALGOL 68 is therefore automatically correct in any superlanguage.

Although many sublanguages of ALGOL 68 are possible, there is one particular sublanguage that has been accorded official recognition by IFIP Working Group 2.1*, and which is usually referred to as "ALGOL 68S".

ALGOL 68S is intended for use primarily in numerical and related areas. In spite of the various features of full ALGOL 68 that have been left out of it, it is still a viable language in its own right, within its field of application.

The omitted features have been chosen principally with a view to simplifying the compilation process, enabling the sublanguage to be implemented on mini computers with as little store as 16K words of 16 bits. Another design aim was to ensure that programs could be parsed and object code generated in one pass through the source text. Although this, of course, aids compilation on small machines, it has the further advantage, even on large machines with complex operating systems, that overlaying of the compiler is avoided. Since the operating-system overhead associated with bringing the compiler and/or its overlays into store may account for the bulk of the compilation cost for sufficiently small programs, it is expected that implementations of this sublanguage will be used for teaching purposes, since students' programs are typically small, but large in number.
# Restrictions

## 1. Modes

There are fewer modes than in the full language:

* There are no **unions**.

* There is no **flex** (but there are special provisions for **string**).

* Structures may not contain multiples (e.g. no `struct(int no, [] real elems)`) and multiples of multiples (such as `[] [] int`) are forbidden.

* In an actual-declarer, you may not write `[3] int` meaning `[1:3] int` (see 2.5.2.2.E7*), and quirks like `mode a = [1:/a b = (4, 6, 8); b[i]] int` (observe how `a` is used in the actual-bounds before its declaration is complete) are forbidden.

* You must not expect standard-prelude operators to work (even with restricted precision) on **long** or **short** modes (2.7.2) beyond those implied by `int lengths`, `int shorths`, etc. (6.7.1).

* If your implementation forces you to use `("` and `")` in place of `"["` and `"]"`, you are not allowed to omit the `loc` in variable-declarations such as `loc (1:n) real x1`.

## 2. Omitted constructs

* **No heap generators (5.7.2.2)** (this immediately rules out all applications of a "list processing" nature, but it simplifies the run-time system considerably by removing the need for a garbage collector).

* **No parallel-clauses (3.7.2)** (i.e. no **up**, **down** or **sema**).

* **No void-collateral-clauses (3.7.1).**

* **No vacuums (3.5.1.E4)** (you don't really need them, because of the absence of **flex**).

* **Jumps must be explicit (i.e. go to *l* or goto *l*, but not just *l* – see 4.7.1.E2).**

* **No conformity-clauses (3.6)** (because there are no **unions**).

* **No empty (5.6.1)** (no **unions** again).

* **No `10` (or its alternative `\`)**. This is no hardship because you just use `1230e-1` in place of `123010-1` (5.1.1.1). (See also Appendix 5).

* **No procedured jumps (4.7.2).**

## 3. Textual order

The following restrictions arise because of the requirement for one-pass compilation:

* All declarations of indicators (i.e. of identifiers, operators and mode-indications) must precede the first applied occurrences (3.2.3) which
identify them. This is normally good programming practice anyway (moreover, see 3.2.3.E7) and the only case where you might regret the restriction is that of mutually recursive pairs of procedures (you would have to declare one of them as a *proc* variable in the sublanguage) or of mode-indications (but, the sublanguage not being suitable for list processing anyway, the need for these is less likely to arise).

Priority-declarations of operators (4.3.1) must precede their corresponding operation-declarations (4.3.2) and, once a priority has been given for an operator, it may not be changed again within an inner range (which prevents you, among other things, from altering the priority of the standard-prelude operators). Also, a bold word declared as an operator may not subsequently be used as a mode-indication in an inner range, and vice-versa.

The "firmly related" restriction on declaring a given operator to apply separately to not-too-different modes, as given in 4.3.3, is made more severe. The new "meekly related" condition applies whenever there exists a common mode to which the two modes in question can be meekly coerced (e.g. *proc real* and *ref real* are meekly related) *.

Structure- and row-displays (3.4 and 3.5.1) may not be used in the strong position of a firm (or weaker) balance (5.2.0.1). I.e. although $z := (p | x | w)$ would be accepted in the sublanguage (because of the balancing, $x$ gets widened to *compl* even though the conditional-clause is in a firm context), $z := (p | (+1, -1) | w)$ would not. Likewise, structure- and row-displays may not occur as the first (effectively the only) unit of a closed-clause (as in $((+1, -1))/)$). These restrictions are no great hindrance to the programmer (a cast (5.1.1.3) can always resolve the matter) but, for the compiler writer, they mean that as soon as he starts to compile such a display, he knows what its mode is meant to be.

*loc* generators (5.7.2.1) may not precede the first declaration in their range (the compiler must be able to know, at the time it encounters the *loc*, whether the range in question is going to be a local one or not (5.7.2.1), they may not stand as bounds in actual-declarers (but who would want to write [*l:loc int] real* anyway), and they may not be operands (as in *loc int + 1* — again not in the least useful).

A jump may not cause the elaboration of a declaration to be bypassed (as in $((p | goto l); real x; c$ statements involving $x$; $c$: c statements not involving $x$; $c$) which is legal, though hardly good style, in the full language).

<footnote>* Moreover, the new operator may not be meekly related even to another operator declared in an outer reach.</footnote>
### 4. Strings

string is actually a different mode from [] `char` in the sublanguage.

However, many operations (e.g. slicing) work with both modes and a strong
coercion from `string` to [] `char` is provided, so that you will hardly notice the
difference. The following are the few cases which might arise:

The operators `<`, `≤`, `=`, `‡`, `≥`, `>`, `+`, `×`, `plusab` and `plusto` work as usual for
`string`, but not for [] `char`.

Slices work for both modes, but in the case of **string** the slice cannot yield a
name (thus `s[2] := "A"` is excluded, but not `char c := s[2]`).

The lower-bound of a **string** is always *l* (and hence revised-lower-bounds (5.5.1.3) are never needed).

Contexts (even strong ones) expecting a **string** cannot accept a [] `char` (as in
**proc p = (string s) void: skip; [1:n, 1:m] char rrc; p(rrc[i, ]))**. The
converse (**string** where [] `char` is expected) is all right, because of the
extra strong coercion (as in `rrc[i, ] := s`).

The rowing coercion can never yield a name (see 5.5.1.3.E20).

### 5. Transput

Many of the less used and more exotic transput features are omitted, as
follows:

There are no **formats**.

Omitted procedures are **stand conv (7.4.3)**, **make conv, make term (7.4.2)**, **on format end (7.4.4.5)**, **on value error (7.4.4.6)**, **on char error (7.4.4.7)**, **reidf, lock, scratch, create (7.2.3)**, **backspace, set char number (7.2.5)** and **char in string (7.5.2)**.

All the environment enquiries given in 6.2.1, 6.7.1, 7.2.2 and 7.5.3 are omitted, with the exception of **max int**, **max real**, **small real** (and their **long(s) versions**), **chan**, **stand in channel**, **stand out channel** and **stand back channel**.

## Conclusion

It will thus be seen that most of the restrictions in ALGOL 68S will hardly be noticed by the average programmer (although they all help the compiler writer considerably). It will be noticed that, in the lists above, those restrictions likely to be of practical importance have been given first. These include the lack of **unions**, **flex**, **parallel-clauses**, **heap generators**, the requirement for defining before applying and **formats**. Even without all these, you still have a very powerful language.
## APPENDIX 5. The Standard Hardware Representation

Of the large number of symbols that could be used in an ALGOL 68 program (see Appendix 1), most computer installations will be able to use but a few due to the limitations of their character codes. Indeed, the symbols used in this book (especially those such as x, V, Λ, ⊖ and 10 and the bold words) have been chosen, from amongst those permitted by the Report, for their clarity and conciseness rather than for their ready availability on real computers.

It is thus the responsibility of each implementor to choose which symbols he will represent (where there are alternatives he is not obliged to provide more than one) and how he will represent them. In order to give guidance to implementors and to facilitate the portability of programs between different implementations, IFIP Working Group 2.1 has approved a standard representation* to which it is expected that many implementations will adhere.

The standard seeks to represent all ALGOL 68 programs using only 60 "worthy characters", which have been chosen because of their ready availability in the majority of modern character codes, such as ISO (including its American version ASCII) and EBCDIC (although even these are not as well standardized as is popularly imagined, there being problems with specialized National Characters in ISO and various positions for (or even a complete absence of) [ and ] in EBCDIC). The 60 worthy characters are:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
space "# $%" ( ) *+,-./:;< => @[ ]_!

This is not to say that all these will appear on your keyboard. A local convention may tell you to punch "←" for "_" and "a" for "A". The important thing is that there should be a one-to-one correspondence between the worthy characters and the codes recognized by your machine so that, at the worst, transferring a program to another machine should require only a one-to-one transliteration of codes. To these 60 worthy characters may be added, optionally, a second alphabet ("a" to "z") but, except in the case of

<footnote>* Wilfred J. Hansen and Hendrik Boom, The Report on the Standard Hardware Representation for ALGOL 68, ALGOL Bulletin, AB40, also in SIGPLAN Notices 12 (5) (1977).</footnote>
UPPER stropping and strings (see below), "a" means the same as "A" and "Z" means the same as "Z".

The manner in which these worthy characters are used to represent ALGOL 68 symbols such as ":=", "::" and "+:=" is quite obvious. For the symbols not immediately representable (e.g. ≠, x, ≤, ⊢) Appendix 1 gives representable alternatives (e.g. /=, *, < =, %) and for 10 or \ you can always write "e" (5.1.1.1). The letters A to Z can obviously be used to represent identifiers, which leaves us with just the "stropping convention" (1.3.2) to be used for the bold words - i.e. for mode-indications such as real and int, for operators such as abs and entier, and for delimiter words such as begin and end. For this, three distinct conventions, "POINT", "UPPER" and "RES", are prescribed.

## 1. POINT stropping

Each bold word is preceded by a point and followed by a "disjunctor". A "disjunctor" is anything other than a letter or a digit or an underscore (so that, if the bold word is to be followed by an identifier (which starts, of course, with a letter) you had better insert a space in between to act as the disjunctor - so that. REAL X means real x but .REALX means realx). Even if a second alphabet of letters ("a" to "z") is provided, no distinction is made between "a" and "A", so that .real x is no different from .REAL X.

Example:

```
.BEGIN .REF .LONG .REAL X := .LOC .LONG .REAL :=
  .LONG 3.141592654; X .MINUSAB LONG PI;
  PRINT(X)
.END
```

If you want to see which spaces were actually essential as disjunctors, observe that the following is exactly (but confusingly) equivalent:

```
.BEGIN.REF.LONG.REAL X:=.LOC.LONG.REAL:=
  .LONG 3.141592654; X.MINUSAB LONGPI;PRINT(X).END
```

The POINT stropping regime is introduced by the pragmat (1.3.2) pr point pr (which will usually appear as .PR POINT .PR) but, since point stropping continues to be valid even in the other two regimes about to be introduced, the chief effect of this pragmat is to turn those other regimes off.