I/O Operations in ALGOL 60
Console output, reading input, formatted reports, and file I/O through shell redirection in ALGOL 60 - all runnable with GNU MARST and Docker
Introduction
Here is the surprising truth about input and output in ALGOL 60: the language never defined any. The 1960 Report deliberately left I/O out so the committee could concentrate on algorithmic expression, and they assumed each implementation would supply whatever its host machine needed. The practical cost was that no ALGOL 60 program doing I/O was ever truly portable between compilers.
The gap was eventually filled by the Modified Report (1976), which standardised a set
of I/O procedures. GNU MARST - the implementation used throughout this series - follows the
Modified Report and gives us outstring, outinteger, outreal for output and
ininteger, inreal for input. Every procedure takes a channel number as its first
argument; channel 1 is the standard console, which is why every program in this series
writes to channel 1. The input procedures read from that same standard channel.
This tutorial goes well beyond the single outstring call from Hello World. You will print
mixed text and numbers, build a small formatted report and a table, read numbers typed at
the terminal, and finally do real “file I/O” the way ALGOL 60 programs actually do it - by
letting the shell redirect files into and out of the standard channel. Because ALGOL 60 is
an imperative, procedural language, all of this reads as a straightforward sequence of
procedure calls.
Output in Depth
You met outstring in Hello World. The other two core procedures are outinteger and
outreal. One quirk is worth committing to memory: outinteger and outreal always
print the number followed by a single trailing space, while outstring prints its text
exactly as written. That trailing space conveniently separates values, so you rarely add
one yourself.
Create a file named io_output.alg:
begin
comment ALGOL 60 defined no I/O of its own; these procedures come
from the Modified Report that GNU MARST implements. Channel 1 is the
standard console. This program shows the three core output verbs;
integer items;
real price, total;
items := 3;
price := 4.50;
total := items * price;
comment outstring prints text exactly as written, including any \n;
outstring(1, "=== Order Summary ===\n");
comment outinteger and outreal each print their number followed by a
single space, so you normally do not add one yourself;
outstring(1, "items = "); outinteger(1, items); outstring(1, "\n");
outstring(1, "price = "); outreal(1, price); outstring(1, "\n");
outstring(1, "total = "); outreal(1, total); outstring(1, "\n");
comment A whole multi-line block can live in one string literal;
outstring(1, "\nThanks for your order!\nCome again.\n")
end
Notice how a real value carries no fixed number of decimal places: 4.50 prints as 4.5
and 13.5 prints as 13.5. MARST formats reals in their shortest faithful form rather than
padding them, which is something to plan around when you want neat columns.
Building a Formatted Table
Combining outstring for labels and spacing with outinteger/outreal for values lets you
assemble reports row by row inside a loop. This example prints a Celsius-to-Fahrenheit
conversion table using a for loop with a step of 10.
Create a file named io_table.alg:
begin
comment A formatted table assembled from the output procedures. Each
row prints a Celsius value and its Fahrenheit equivalent. Recall that
outinteger and outreal print their number followed by a space;
integer c;
real f;
outstring(1, "Celsius Fahrenheit\n");
outstring(1, "------- ----------\n");
for c := 0 step 10 until 40 do
begin
f := c * 9.0 / 5.0 + 32.0;
outstring(1, " ");
outinteger(1, c);
outstring(1, " ");
outreal(1, f);
outstring(1, "\n")
end
end
Because the standard output procedures give you no field-width control, perfectly aligned
columns are genuinely hard in ALGOL 60 - you nudge things into place with literal spaces in
outstring. This limitation is a direct consequence of the language leaving I/O to
implementations: there was never a standard printf-style format string.
Reading Input
Input mirrors output. ininteger(1, var) reads one integer from the standard channel into a
variable, and inreal(1, var) reads one real. Both skip any leading spaces and newlines
before the number, so values may be separated by spaces or spread across several lines.
Create a file named io_input.alg:
begin
comment ininteger reads an integer from the standard channel (1),
skipping any leading spaces or newlines. We read two integers and
report a few results computed from them;
integer a, b;
outstring(1, "Reading two integers from standard input...\n");
ininteger(1, a);
ininteger(1, b);
outstring(1, "a = "); outinteger(1, a); outstring(1, "\n");
outstring(1, "b = "); outinteger(1, b); outstring(1, "\n");
outstring(1, "a + b = "); outinteger(1, a + b); outstring(1, "\n");
outstring(1, "a * b = "); outinteger(1, a * b); outstring(1, "\n")
end
Since the program reads from standard input, you feed it values by piping them in (shown in the Docker section below). The numbers you supply are not echoed back automatically - only what the program explicitly prints appears in the output.
File I/O Through Redirection
The Modified Report procedures read and write the standard channel; ALGOL 60 has no portable
“open this named file” statement. In practice you do file I/O exactly the way Unix tools do:
let the shell connect a file to standard input or standard output with < and >. The
program below reads a count n, then n real values, and reports their average - perfect
for driving from a data file.
Create a file named io_average.alg:
begin
comment Read a count, then that many real numbers, and report the
average. Because we read and write the standard channel, the shell
can redirect a file in and capture the result out - the practical
way to do file I/O with ALGOL 60;
integer n, i;
real x, total;
ininteger(1, n);
total := 0.0;
for i := 1 step 1 until n do
begin
inreal(1, x);
total := total + x
end;
outstring(1, "count = "); outinteger(1, n); outstring(1, "\n");
outstring(1, "total = "); outreal(1, total); outstring(1, "\n");
outstring(1, "average = "); outreal(1, total / n); outstring(1, "\n")
end
This program needs a data file to read. Create a file named numbers.txt:
| |
The first line gives the count; the second line holds the four values. Note that total is
declared real, so dividing it by the integer count n performs real division and yields
a fractional average when the numbers do not divide evenly.
Running with Docker
Use the same GNU MARST image as the rest of this series. Pull it once:
| |
Output-only programs run exactly like Hello World:
| |
Programs that read input need the -i flag so Docker keeps standard input connected. Pipe
values in for the interactive example, and redirect the data file for the averaging example:
| |
Expected Output
io_output.alg:
=== Order Summary ===
items = 3
price = 4.5
total = 13.5
Thanks for your order!
Come again.
io_table.alg:
Celsius Fahrenheit
------- ----------
0 32
10 50
20 68
30 86
40 104
io_input.alg, given the input 5 7:
Reading two integers from standard input...
a = 5
b = 7
a + b = 12
a * b = 35
io_average.alg, reading numbers.txt:
count = 4
total = 100
average = 25
When you run the last command with > results.txt, nothing prints to the terminal; the same
report is written to results.txt instead.
Key Concepts
- ALGOL 60 defined no I/O. The original 1960 Report left input and output to each implementation; the procedures used here come from the Modified Report (1976) that GNU MARST follows. This is why I/O code is not portable across historical ALGOL 60 compilers.
- Channels identify streams. Every I/O procedure takes a channel number first; channel
1is the standard console, used for bothout*(writing) andin*(reading) in MARST. - Three output procedures cover the basics:
outstring(1, s)prints text verbatim,outinteger(1, n)prints an integer, andoutreal(1, x)prints a real. - Numbers print with a trailing space. Both
outintegerandoutrealappend a single space after the value, which separates consecutive numbers without extra effort. - Reals use shortest-form output.
outrealprints the minimal faithful representation (4.50becomes4.5), so there is no built-in control over decimal places or field width. - Reading skips whitespace.
ininteger(1, var)andinreal(1, var)skip leading spaces and newlines, so input values can be space-separated or split across lines. - File I/O is shell redirection. Lacking a portable file-open statement, ALGOL 60
programs read and write the standard channel and rely on the shell’s
<and>to attach files - remember to add Docker’s-iflag so standard input stays connected. - Declarations precede statements. As with every ALGOL 60 block, all variables are
declared at the top of the
begin ... endblock before any I/O or computation occurs.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/algol60:latest
Comments
Loading comments...
Leave a Comment