Algol 68 has influenced programming languages in many ways. Daniel James reminds us just how many.
This month marks the 50th anniversary of the inception of the Algorithmic Language Algol 68 – the first programming language I ever learned, back in 1974 when I first encountered these things called computers, as an undergraduate.
I wrote ‘inception’ … perhaps a little background overview is required.
Nowadays we have more programming languages than you can shake the proverbial stick at, and computers that can shake the stick for you, but in the early 1960s there were really only three major languages available: COBOL for business programming, and FORTRAN and Algol for scientific work (LISP was also around, and deserves an honourable mention, but I’d hesitate to call it ‘major’). The latter two were designed with slightly different goals in mind: FORTRAN ( FOR mula TRAN slation) was developed at IBM specifically for programming computers, while Algol ( ALGO rithmic L anguage), developed by a European and American team at ETH Zurich, was designed also to enable the expression of algorithms in a concise but human-readable form.
FORTRAN was the more widely used – in part because it had IBM behind it, but also because it was seen as the more portable language. The designers of Algol decided not to specify standard input and output operations as they felt that language implementers were better placed to define these facilities for the platform on which they were working. This meant that each new implementation of Algol had its own non-portable i/o functions, and this lack of portability had an impact on the acceptance of Algol.
As the 1960s progressed, a number of new languages appeared and the existing languages were further developed. The IFIP Algol Working Group 2.1 [ Wikipedia-1 ] was formed in 1962 to design a replacement for Algol 60 that was then code-named Algol X. Many ideas were discussed, some in the light of experience of similar features in other languages, but no complete implementation of any proposed candidate for Algol X was produced before the language was formally accepted. This acceptance came when the WG 2.1 members met in December 1968 and voted to accept the language specification [ Original ] as it then stood, without ever seeing a working prototype. This is the language that became known as Algol 68.
Their decision was by no means unanimous, with some of the committee saying that the language had become over-complex and had lost the simplicity of Algol 60. Some of these famously went on to publish their dissent as the ‘Minority Report’ [ Minority ], in which they claimed that the language was a failure.
The style of the language reports deserves a mention. The reports are written using a two-level grammar in which the first level defines a meta-language, and the second defines Algol 68 in that meta-language. This style is known as a Van Wijngaarden grammar, after Adriaan van Wijngaarden who invented it and was also instrumental in bringing about the final design of Algol 68. The style of the reports also accounts for their legendary impenetrability to the casual reader.
In July 1970 a conference to discuss Algol 68 implementation [ Peck70 ] took place. While many of the delegates presented papers that discussed the difficulty of implementation of the new language, the small team from the Royal Radar Establishment presented their working compiler for a substantially complete subset of the language that they called Algol 68-R [ Wikipedia-2 ]. Algol68-R was already in daily use for production code on the ICL 1907F computer at RRE, where it had replaced Algol 60 for new development. The Algol 68-R compiler was later distributed without charge by ICL to other users of 1900-series hardware, and it was this compiler that I first used when I went to University.
Development of Algol 68 continued into the 1970s and a revised edition of the Algol 68 Report [ Revised ] was published in 1975. The team at RRE (by then known as the Royal Signals and Radar Establishment) produced a new version of their compiler called Algol 68-RS, which ran on, among other things, the newer ICL 2900-series mainframes and Dec VAX minicomputers.
A brief overview
So, what sort of language is Algol 68? I’m going to talk mostly about the language of the Revised Report because it is a little more complete than the original language and has fewer idiosyncrasies, but the differences are slight and mainly cosmetic.
An expression-oriented, block-structured, procedural language
Algol 68 is an ‘expression-oriented’ language in that almost every statement – what the Revised Report calls a
unit
(the original report used the term ‘unitary clause’) – delivers a value, and so can be treated as an expression. Every expression can also legally be used as a statement. If a
unit
has no value to deliver, it returns the special type
VOID
. If an expression that yields a value but doesn’t do anything with it, such as
41+1
appears as a statement on its own, the compiler is likely to offer a warning that the result is to be discarded, but the code is legal.
Declarations aren’t classed as unit s, and aren’t expressions. A sequence consisting of unit s or declarations and unit s separated by semicolons is called a series (originally ‘serial clause’) and has the value of its last unit . Note that the semicolon is a separator, not a terminator: there shouldn’t be one after the last unit in a series .
Algol 68 is a block-structured language in that a program is composed from nested lexical blocks. Each new block introduces a lexical scope that limits the lifetime and visibility of constructs declared within that scope. Each new scope inherits from any containing scope. A block – and everything it contains – is syntactically a unit whose value is the value of the last statement in the block.
A
block
may simply be one or more statements enclosed between
BEGIN
and
END
, or may be a conditional such as
IF
or
CASE
, or a loop.
Algol 68 is a procedural language in that its programs are built-up from procedures. A
procedure
in Algol 68 may be a function that returns a result, or may be a pure procedure that returns no result, in which case its return type is specified as
VOID
. The body of a procedure is a
unit
.
As is the case in Algol 60 and some other languages (such as Pascal), but not C or C++ (at least until lambda functions were introduced in C++11) procedures in Algol 68 do not have to be declared at the outermost lexical scope but can be declared within a program block, even a block of another procedure.
Algol 68 also supports user-defined operators, which are defined identically to procedures except that operators can have only one or two arguments. The user can set the priority (from 1 to 9) of an operator symbol, and can define new operator symbols. Operators can be overloaded, however, while procedures cannot.
Basic types
Data types in Algol 68 are called
MODE
s. The
MODE
s provided as standard are mostly unsurprising (see Table 1).
INT
|
Signed Integer. Single machine word. |
REAL
|
Single-precision floating point number. |
COMPL
|
Complex number. |
BITS
|
Binary value, packed Booleans. |
BYTES
|
Packed characters (provided for efficiency on architectures that are not byte-addressable, such as the ICL1900) |
All of the above modes may be prefixed with LONG or LONG LONG to get double or higher precision, depending on the implementation. | |
CHAR
|
Character. Implementation defined representation. |
BOOL
|
Boolean value |
Table 1 |
Additional
MODE
s are defined in terms of these simple types. A
MODE
declaration associates an identifier with a
MODE
as an alias for the full definition.
Derived types
References
Algol 68 supports reference types using the
REF
keyword, so a reference to an
INT
type would be written
REF INT
. Syntactically Algol 68 references are more like C pointers than Java references, and they can be set to a null value which is written
NIL
.
Algol 68 uses the term ‘name’ when talking about anything that has a reference type. This term is equivalent to ‘lvalue’ in C, and means that a value can be assigned to it. The term ‘identifier’ is used to refer to symbolic names used in source code.
References can be compared for equality using the built-in
IS
and
ISNT
operations.
Arrays
Algol 68 supports single- and multi-dimensional arrays. Subscripts are written between square brackets.
MODE MATRIX = [1:5,1:5] REAL
The lower bound of an array defaults to 1, but may be any value less than the upper bound – even negative. An array ‘knows’ its bounds, and these can be queried at runtime using
LWB
and
UPB
. Like Algol 60 and C (but unlike FORTRAN) Algol 68 stores arrays in row major order.
Arrays can be flexible. The built-in
STRING
datatype is defined as a flexible array of character values:
MODE STRING = FLEX [1:0] CHAR
Arrays can be sliced. If
r
is a
[1:10]INT
then
r[3:7]
is a
[1:5]INT
.
The use of flexible arrays implies the use of dynamic (heap) allocation. No explicit deallocation is necessary as this is managed using garbage collection.
Structures
Data structures are defined with the keyword
STRUCT
. For example the standard type
COMPL
is defined as:
MODE COMPL = STRUCT( REAL re, im )
Fields of a structure are selected using the
OF
keyword (not an operator):
re OF complexvalue
A structure type may not contain members of that type, but may contain references to that type, so it is possible to write linked lists, binary trees, etc. Listing 1 shows how this may be used to implement linked list functionality.
# (Unordered) Linked List example # # Demonstrates using HEAP storage # MODE ELEMENT = STRING; MODE NODE = STRUCT ( ELEMENT value, REF NODE next ); MODE LIST = REF NODE; LIST empty = NIL; # Add an element to the end of the list # PROC append = ( REF LIST list, ELEMENT val ) VOID: BEGIN IF list IS empty THEN list := HEAP NODE := ( val, empty ) ELSE REF LIST tail := list; WHILE next OF tail ISNT empty DO tail := next OF tail OD; next OF tail := HEAP NODE := ( val, empty ) FI END; # Add an element to the beginning of the list # PROC prepend = ( REF LIST list, ELEMENT val ) VOID: list := HEAP NODE := ( val, list ) # Print the list out - using a loop # PROC print list = ( LIST start ) VOID: BEGIN IF start ISNT empty THEN REF NODE ptr := start; WHILE print(( "-- ", value OF ptr, newline )); next OF ptr ISNT empty DO ptr := next OF ptr OD FI; print(( "End of list", newline )) END; # Print the list out - using recursion # PROC print list recursively = ( LIST start ) VOID: BEGIN IF start IS empty THEN print(( "End of list", newline )) ELSE print(( "-- ", value OF start, newline )); print list recursively( next OF start ) FI END; |
Listing 1 |
The identifiers given to the fields of a structure are part of its type, so two structures containing the same types of fields but with different field names would not be the same type.
Unions
Unions are defined with the keyword
UNION
.
MODE STRINT = UNION( STRING, INT )
An Algol 68 union ‘knows’ the type of its current value, and this may be queried at runtime.
Declaration and assignment
A declaration associates an identifier with some value, and uses the ‘equals’ symbol
=
. The following introduces a new identifier called
ultimate answer
that represents the integer value 42:
INT ultimate answer = 42
Note that white space is not significant within an identifier, so this could equally well be written
ultimateanswer
or
ulti mate answ er
.
A variable can be created simply by naming it and its type:
REAL half pi
The example above introduces a new identifier
half pi
and associates it with the storage for a variable in the current scope. This is shorthand for:
REF REAL half pi = LOC REAL
which says that
half pi
is a constant identifier that represents a reference to a
REAL
and is initialized to some location allocated on the stack. Although this long form is used by a lot of the early Algol 68 literature, it isn’t really necessary. It is a bit like saying that the declaration of a float variable in C++ is equivalent to:
float & half_pi = *(float*)alloca( sizeof(float) );
It does, however introduce the concept of a
generator
. In the example above,
LOC REAL
is a
generator
that allocates local (stack-based) storage for a
REAL
variable. Whilst it is never necessary to use this long form with the explicit
LOC
generator
to create storage for a local variable, the use of a
HEAP
generator
is the only way to allocate variables on the heap.
A value can be assigned to a variable using the ‘becomes’ symbol
:=
in what Algol 68 calls an ‘assignation statement’.
half pi := pi/2
Declaration and initialization can be combined into a single statement:
REAL half pi := pi/2
Note that
pi
is a built-in constant of type
REAL
(higher precision versions –
long pi
, etc. – also exist).
The difference between the constant declaration (using the ‘equals’ symbol,
=
) and the declaration and initialization of a variable (using the ‘becomes’ symbol,
:=
) is slight, and they are easy to confuse.
Algol 68 also provides ‘updating’ operators like
PLUSAB
(‘
PLUS
A
nd
B
ecomes’) which can be abbreviated
+:=
. This syntax has been adopted by many other languages since.
Control flow
Conditions are supported by the choice statements,
IF
and
CASE
. These are identical in structure but the
IF
statement bases its selection on a
BOOL
value, while the
CASE
bases its on an
INT
value:
IF boolvalue THEN some expression ELSE other expression FI CASE intvalue IN expr1, expr2, …, exprN OUT another expr ESAC
IN
and
OUT
are
CASE
’s equivalents of
THEN
and
ELSE
.
ELIF
and
OUSE
are provided as shorthand forms of
ELSE IF
and
OUT CASE
.
That these really are equivalent constructions becomes more apparent when we learn that a
BOOL
value can be converted to an
INT
using the
ABS
operation, and that
ABS TRUE
has the value 1, while
ABS FALSE
is 0.
As with all statements in Algol 68, a choice statement may return a value, the value returned is the value of whatever expression is chosen (so long as all the expressions return the same
MODE
). While C and some other languages have a ‘ternary operator’ that allows one of two values to be used depending on some boolean condition. Algol 68 has no need of such a construction because the structure of the language allows an ordinary
IF
statement to be used.
This allows for constructions like:
days in month := CASE month OF date IN 31, IF is leap year( year OF date ) THEN 29 ELSE 28 FI, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ESAC
IF
and
CASE
introduce lexical scopes, just as
BEGIN
does. The scope ends with the closing
FI
or
ESAC
statement.
Spelling
IF
and
CASE
backwards to indicate the end of the block that they introduce is a device that Algol 68 uses in a number of places. The use of
FI
and
ESAC
has been adopted in some other languages, notably in the Bourne shell, while still more have taken up the idea but opted for keywords such as
ENDIF
– perhaps we should be grateful that
END
is not spelt
NIGEB
in Algol 68!
It’s interesting that C++17 introduces new ‘
if
with initializer’
[P0305R0]
and ‘
switch
with initializer’ features that let one declare variables in the condition part of an
if
or
switch
statement that have the scope of the whole statement. This enables one to write things like:
if( int val = get_value(); is_valid( val ) ) { do_stuff_with( val ); }
which is directly equivalent to the Algol 68 code
IF INT val := get value(); is valid ( val ) THEN do stuff with( val ) FI
except that the Algol 68 form is more general.
Note that with the Algol 68
CASE
statement there is no possibility that one case can run on into the next (even should you want it to) so there is need for any break-type statement, as in C (nor does the language support one).
Loops are supported by the very versatile Algol 68
DO
loop, which has the general form:
FOR counter FROM start BY step TO stop WHILE condition DO something OD
Everything here is optional, apart from the
DO something OD
part, which is the loop itself, the other parts just provide conditions that control the termination of the loop.
The
counter
, if present, is an integer whose scope is limited to the loop; by default it counts from 1 in increments of 1 but that can be changed using the
FROM
and
BY
parts. The loop terminates when the variable reaches the
stop
value, if specified, or when the condition becomes true … otherwise it will run for ever. The counter cannot be assigned to within the loop – it is not a variable but an
INT
constant that is re-created with a new value each time around the loop.
The condition of a loop including a
WHILE
part is syntactically a series of declarations and statements. This syntax caters for cases in which all or part of the body of the loop is to be executed before the
WHILE
condition is evaluated.
WHILE INT n; read( n ); is valid input( n ) DO process( n ) OD
If the whole of the loop is to be executed before the test (as with a
do ... while
loop in C, for example) the do-nothing operation
SKIP
can be used to satisfy the syntactic requirement for one or more statements between
DO
and
OD
. The Algol 68
DO
loop offers all the varieties of loop control that are provided by the
for
,
while
, and
do ... while
constructions in C but with greater flexibility.
Unlike most other constructions in Algol 68, a loop does not return a result.
Here are some examples. These also show three forms of
COMMENT
, and a call to the built-in
print
function. Note that the call to print uses two sets of parentheses because multiple values are being printed; the inner pair belong to the representation of the single argument, which is in effect an array of
UNION
s of various types.
# Zero all elements of ar from lower to upper bound # FOR index FROM LWB ar TO UPB ar DO ar[index] := 0 OD CO enhance a until it is greater than some threshhold CO FOR i WHILE a < threshhold DO print( ( "After ", i, " iterations a is ", a, newline ) ); a := enhance( a ) OD COMMENT sound an alarm 10 times COMMENT TO 10 DO sound alarm OD
For completeness, and to annoy purists, Algol 68 also supports
GOTO
.
Procedures
Algol 68 procedures take a number of parameters, possibly zero, and return a result or VOID. A procedure is defined like so:
PROC twice as much = (INT i) INT: i+i
This defines a procedure named
twice as much
which takes a single integer parameter by value, and returns an integer result. The body of this procedure is a single statement and so doesn’t need to be enclosed in a block, but most procedures do.
In this definition, the procedure denotation
(INT i) INT: i+1
is assigned to the identifier
twice as much
, which therefore has the mode
PROC (INT) INT
. As with data quantities, though, the procedure body could be assigned to a procedure variable identifier
PROC operation := (INT i) INT: i+i
We could then, elsewhere in the program, change the value of that procedure:
operation := (INT foo) INT: 3*foo+7
Listing 2 shows another example of a function denotation being used as a lambda.
# Print a table of values # # print a table of values of f(angle) # # for angle from start to stop (degrees) # PROC print trig = ( REAL start, REAL stop, PROC (REAL) REAL f ) VOID: BEGIN REAL val := start; printf( $" Deg |"$ ); FOR i FROM 0 TO 9 DO printf(( $z-d.dx,b(l,x)$, i/10, i=9 )) OD; printf( $5"-" "+" 71"-"l$ ); FOR col FROM 0 WHILE val < stop DO IF col MOD 10 = 0 THEN printf(( $zd.d" | "$, val )) FI; printf(( $+d.3d,b(l,x)$, f((val*pi)/180), col MOD 10 = 9 )); val +:= 1 OD END; # Print a table of sin(x) using the built-in sin function # print(( newline, "Printing sin x", newline )); print trig( 0, 90, sin ); # Print a table of sin^2(x)+cos^2(x) using a lambda # print(( newline, "Printing sin^2 x + cos x", newline )); print trig( 0, 90, (REAL n) REAL: sin(n)^2+cos(n)) |
Listing 2 |
The procedure body that we assign in this way is effectively a lambda function. No special syntax is needed for lambda, the functionality is a natural consequence of the design of the language.
Transput
Transput is the word used in the Algol 68 reports to refer to both input and output.
One of the big shortcomings that was recognized in Algol 60 was its lack of any standardized i/o system. The designers of Algol 68 addressed this lack by introducing a standard system for both formatted and formatless output. We have already seen the procedure
print
, which accepts any simple argument and outputs it in a standard way. This tends not to be very pretty as, for example, numbers are output in their maximum width and precision. This output can be tamed somewhat using built-in functions
whole
,
fixed
, and
float
that convert numbers to strings with specified width and precision.
There is also a system for formatted output that gives the programmer complete control over the format of the output by means of a format designator. This is similar to the format string of C’s
printf
, but is a special Algol68
FORMAT
type, delimited by
$
characters, and can be evaluated at compile-time for efficiency. A
FORMAT
consists of one or more ‘pictures’, separated by commas, each of which describes the layout of a single item.
Formatless input and output are achieved using the functions
put
and
get
. We have already seen the
print
function, which is equivalent to
put
but always uses the default standard output channel called
stand out
(similar to
cout
in C), there is also a
read
function that is equivalent to
get
using
stand in
. Formatted i/o uses
putf
and
getf
(and
printf
and
readf
).
These three produce identical output on
stand out
:
put( stand out, (i, blank, r, newline )); print(( i, blank, r, newline )); printf(( $gx,gl$, i, r ))
If
i
is an integer with the value 42 and
r
is a
REAL
with the value 22/7 then this would produce three identical lines of:
+42 +3.14285714285714e +0
In the
put
and
print
cases, the list of items to be printed are enclosed in brackets because they are conceptually an array of values to be output. These include blank and newline, which are
PROC(REF FILE) VOID
functions that are called to manipulate the output stream.
In the
printf
case, the argument list begins with a
FORMAT
containing two pictures using
g
tags meaning that the values should be printed in the same default format as is used for formatless output, and
x
and
l
tags that supply the blank and newline.
Printing values without formatting is not the point of formatted output, of course, and one might more typically see something like
printf(( $4z-dx,+3d.5dl$, i, r ))
The format string contains two pictures. The first depicts an integer with 4 digits that will be printed as blanks if they are all leading zeros (four
z
tags) followed by one digit that will always be visible (a
d
tag) and a space (
x
tag), with a sign character that will be a blank if the value is positive immediately to the left of the first non-zero digit (
-
tag) and then a blank (
x
tag). The second picture depicts a real number with a sign always shown (
+
tag), and with three digits (three
d
tags) before and five digits after (five
d
tags) a decimal point (
.
tag), and then a newline (
l
tag).
With the values of
i
and
r
above, this would produce:
42 +003.14286
Listing 2 shows some examples of formatted output.
Notation
In the Revised Report, Algol 68 is written in lower-case letters, with keywords emphasized in bold. Text files holding program source to be read by compilers don’t provide a mechanism for the representation of bold text, so keywords are typically written in upper-case, as I have done here. The original Algol 68-R compiler ran on ICL 1900 computers, which had a basic character set of only 64 characters. Lower-case characters were available only through a complicated system of shift prefixes, and weren’t used in programming. In Algol 68-R, keywords were distinguished from identifiers by enclosing them in single quotes, which was called ‘quote stropping’.
'BEGIN' 'INT' I := 42; PRINT(( I, NEWLINE )) 'END'
Other upper-case systems used ‘dot stropping’, in which a keyword was prefixed with a dot character.
I’ve deliberately chosen a rather ‘wordy’ notation for the examples in most places in this article, but it is worth noting that Algol68 provides symbolic short forms for many operations. For example the pseudo-operators
IS
and
ISNT
can be written
:=:
and
:/=:
and the
MOD
operator can be written
%*
.
Algol 68 also allows round brackets to be used for
BEGIN
and
END
… or to look at it another way, Algol 68 treats any expression in round brackets as a
BEGIN
/
END
block.
Round brackets can also be used for
IF
,
FI
,
CASE
, and
ESAC
; vertical bar characters for
THEN
,
ELSE
,
IN
, and
OUT
, and vertical bar followed by a colon for
ELIF
and
OUSE
. It is usually clearer to spell things out, but the short forms can be useful when writing a one-liner.
Implementations
Algol 68 has been implemented on quite a variety of hardware platforms. There’s a good summary in the Wikipedia article [ Wikipedia-3 ] and a lot of detail on the Software Preservation Society’s Algol 68 page [ SPS ]. In its heyday there were several implementations written in different countries – including the UK, the US, the Netherlands, and Russia – and supporting a wide range of hardware architectures. It was never as widely used as FORTRAN or COBOL, but it had a significant following.
Algol 68 was also the basis for a number of other languages, including the S3 job-control language of the VME/B operating system of ICL 2900 series mainframes, and influenced a good many more.
Most implementations of Algol 68 are no longer in use, as they were developed for computer architectures that are now obsolete. Some are still accessible in one form or another, for example the Algol-68R compiler can still be run under a GEORGE 3 emulator [ GEORGE ], part of the Algol 68RS compiler survives as the front end of the Algol 68 to C translator [ A68TOC ] from the ELLA project developed at RSRE and has been Open-Sourced, one of the two implementations named Algol 68S has been ported to a number of more modern platforms and Open-Sourced. A more recent implementation from 2001, Algol 68 Genie [ van der Veer16 ], runs on Windows, Linux, and Mac systems and is Open Source; if you run a Debian-derived Linux distro such as Ubuntu or Raspbian you will find it in the standard repository.
Algol 68 has always had the undeserved reputation of being a large, complex, language for mainframe computers only. The language is actually smaller than C [ Henney18 ], and certainly much smaller than many modern languages. I find it pleasingly ironic that the language I was always told would never catch on because it was too big for any but the largest of computers runs nicely on a Raspberry Pi Zero, on battery power, sitting on the palm of my hand – but perhaps that says more about developments in hardware in the last 50 years than it does about software.
Legacy
Algol 68 has influenced many other languages, many of which are still in widespread use today.
The influence of Algol 68 on C is clear, and Algol 68 is referred to many times by Bjarne Stroustrup when describing the development of C++ [ Stroustrup94 ]. Indeed, Stroustrup notes [ Stroustrup13 ] that “ … my ideal when I started on C++ was ‘Algol 68 with Classes’ rather than ‘C with Classes’. ”
Finally, no discussion of programming languages would be complete without an implementation of FizzBuzz, so I present a modest example in Listing 3. Note here that in Algol 68 the
AND
operator between two
BOOL
values does not short-circuit – that is, both
BOOL
terms are fully evaluated even if the first is found to yield
FALSE
. Many implementations provide an alternative short-circuiting form usually called
ANDF
or
ANDTH
(for ‘and false’ or ‘and then’).
# Fizzbuzz in Algol68 # print(( "Fizzbuzz from 1 to 100", newline )); PROC fizz = (INT n) BOOL: IF n MOD 3 = 0 THEN print( "fizz" ); TRUE ELSE FALSE FI; PROC buzz = (INT n) BOOL: IF n MOD 5 = 0 THEN print( "buzz" ); TRUE ELSE FALSE FI; FOR i TO 100 DO IF NOT fizz( i ) AND NOT buzz( i ) THEN print( whole( i, 0 ) ) FI; newline( standout ) OD |
Listing 3 |
References
[A68TOC] The ELLA and A68toC source is available from: https://cs.nyu.edu/courses/spring02/G22.3130-001/ella/
[GEORGE] Algol 68-R included with the GEORGE 3 Emulator on the BCS Software Preservation and Machine Emulation pages. http://sw.ccs.bcs.org/CCs/g3/index.html
[Henney18] Kevlin Henney. Procedural Programming: It’s Back? It Never Went Away. From the 2018 ACCU Conference. https://www.youtube.com/watch?v=mrY6xrWp3Gs This talk has a good 10-minute account of Algol 68 from about 12 minutes in.
[Minority] Published in the Algol Bulletin , archived online at: http://archive.computerhistory.org/resources/text/algol/algol_bulletin/A31/P111.HTM
[Original] The original report can be found here, scanned to PDF (without OCR): http://web.eah-jena.de/~kleine/history/languages/Algol68-Report.pdf
[P0305R0] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
[Peck70] Peck, J.E.L., ed. (1970), Proceedings of the IFIP working conference on ALGOL 68 Implementation , Munich: North-Holland, ISBN 0-7204-2045-8. Available online at: http://www.softwarepreservation.org/projects/ALGOL/paper/ALGOL_68-Implementation.pdf
[Revised] Revised Report on the Algorithmic Language Algol 68 . Edited by van Wijngaarden, et al. Springer-Verlag (1976). An HTML version is available at: https://jmvdveer.home.xs4all.nl/en.post.algol-68-revised-report.html
[SPS] The Software Preservation Society pages on Algol 68 http://www.softwarepreservation.org/projects/ALGOL/algol68impl/
[Stroustrup94] Bjarne Stroustrup. The Design and Evolution of C++ . Addison Wesley (1994).
[Stroustrup13] Bjarne Stroustrup. The C++ Programming Language , 4th Edition. Addison Wesley (2013). Sec. 1.2.2.
[van der Veer16] Algol 68 Genie. Marcel van der Veer. https://jmvdveer.home.xs4all.nl/en.algol-68-genie.html
[Wikipedia-1] IFIP Working Group 2.1: https://en.wikipedia.org/wiki/IFIP_Working_Group_2.1
[Wikipedia-2] ALGOL 68-R: https://en.wikipedia.org/wiki/ALGOL_68-R
[Wikipedia-3]AlLGOL 68: https://en.wikipedia.org/wiki/ALGOL_68
Daniel James has carried on programming in a variety of languages ever since that first brush with Algol 68 in 1974, and the sparkle has never quite worn off. He sometimes wonders how his life would have turned out if the friend who introduced him to computing had been a FORTRAN user, as all good scientists were supposed to be.