In the mid-70's I went to a talk by Charles Lindsey about Algol 68. He is an expert of course, and a very entertaining speaker as well.
Some colleagues used it but my work was not suitable. However, at the time I thought is looked powerful and clear. Very recently I decided to look back at it, and was interested to see its influences on C, Ada, and C++. In fact, Barne Stroustroup in his book 'The C++ Programming Language' says that he initially wanted to create an Algol 68 with objects!
Others have written recent articles about the language, and I won't repeat their work. You might want to take a look at:
Firstly an oldie-but-goodie: 'Algol 68 Without Tears', Excellent de-mystifying paper by Charles Lindsey:
Now, more recently:
Marcel van der Veer maintains the Algol 68 Genie compiler, For Linux and Windows. This site also takes you to a download of a compiler, which I am using: https://jmvdveer.home.xs4all.nl/en.algol-68-genie.html
The Wikipedia entry has much about its creation and definition. The formal definition issue was massive - it was very difficult for most mortals to understand, and some said that it made compiler-writing difficult and error-prone. https://en.wikipedia.org/wiki/ALGOL_68
Exploring Algol 68 in the 21st century - by Chris Hermansen https://opensource.com/article/20/6/algol68
Learn a new old language by programming a game in Algol 68: by Chris Hermansen https://opensource.com/article/20/12/learn-algol-68
Rosetta Code - lots of little examples: https://rosettacode.org/wiki/Category:ALGOL_68
If - like me - you like a paper textbook, some are still available. I got 'A Practical Guide To Algol 68' by Pagan quite cheaply.
Most recent articles assume Linux, but here we use Windows. I will cover downloading, installing, and a simple way of using it that avoids the command-line.
Choose the Windows 32-bit command line item. (Though 32 bit, it works fine on 64-bits)). The downloaded file has a name similar to: algol68g-2.8.3.win32.zip (depending on the version number).
This unzips into a folder named: algol68g-2.8.3.win32. It contains a68g-2.8.3.exe, which is the compiler and interpreter.
There are also some files without an extension. They are text files, and you might choose to rename them, adding a ".txt" to the name.
For simplicity, store your programs inside the same folder.
If you like, you can store your code in txt files, but I use an a68 extension, and I set up Windows to open a text editor for this extension. I use the Notepad++ editor but you can use the basic Notepad editor if you really want to. For compiling and running programs, you can use any editor, but I provide my own one below.
At this stage, the Linux user would type instructions at the command-line. However we will work with mouse clicks. Here is how. In the same folder as above, create 2 files. The first one should be named run68.bat, and must contain the two lines:
"a68g-2.8.3.exe" "demo.a68" pause
(If you know something about bat files, you might wonder about the quotes. There are there for future use, to allow spaces in file paths.)
Here is the second file, named pp68.bat - containing:
echo off rem: delete old backup,backup new, delete any old pp result if exist "aademo.a68.bak" erase "aademo.a68.bak" copy "aademo.a68" "aademo.a68.bak" if exist "aademo.f" erase "aademo.f" rem: try to pp "a68g-2.8.3.exe" --pretty-print "aademo.a68" rem: worked if there is a .f file if not exist "aademo.f" goto errors rem: erase old source, rename prettied .f file to it erase "aademo.a68" rename "aademo.f" "aademo.a68" goto done :errors echo echo FILE COULD NOT BE PRETTIED - MIGHT HAVE SYNTAX ERRORS :done pauseThis second file is optional, but useful. It uses the pretty-print facility in the compiler, which can indent your code neatly. It is more complex because the pretty-print checks your program, and it does not create a new ".f" file if it has errors. If there are no errors, the bat command updates your source file.
To try the commands, create a file called demo.a68, containing:
print("Hello from 1968")
View the above folder in Windows Explorer, and run the run68.bat file by double-clicking. You will see any warnings, and the output,
To try the pretty-printing, insert a lot of spaces before the print instruction, save the file, and close the editor. Run pp68.bat. The updated file will not include the extra spaces.
In general you will have Explorer open, alongside a text editor. This is where Notepad is not great. If its source file gets updated by pretty-printing, Notepad will not detect this, so you need to keep closing it. If you use e.g. Notepad++, it detects the updating, and prompts you to load the new version. Thus, it can stay on-screen all the time.
To work with a new program, edit the 2 commands, replacing "demo" by the new name. (If you know bat programming, you might think about using a parameter). Below, I provide a simple editor which generates the bat files behind the scenes.
Here, we will download and run a program. I will choose 'bubble sort' from Rosetta code, at:
Copy and paste the code into a file named e.g. bubble.a68, in the same folder as above. Edit the 2 bat files to use 'bubble', and run the code. Add a few spaces to screw up the indenting, and try a pretty-print.
There are various ways of typing the words. In oldish academic papers and books, you will see this style:
if maxval > 0 then print(maxval) fiHere the bold if, then and fi (the reverse spelling of "if", to terminate it) are in bold. The 'print' is a function, not a key word.
The more modern way - which works with simple text editors - is to put:
IF maxval > 0 THEN print(maxval) FIIn this scheme, reserved words are in capitals. We are also allowed to put spaces and underscores in the middle of a variable name - though not capital letters.
There are several ways to comment code. The easiest for typing is to use # to start and end a comment, as in:
maxval:= 200; #not possible #You might get irritated by the reverse words: FI, OD, ESAC etc - why not just a } for everything? I think that the Algol 68 (and Ada ) way is much better. At the very least, the compiler can produce a 'DO without a matching OD' message, rather than a vague 'missing }' message.
Here is a program which reads a text file and displays it, along with the length of each line.
PROC process line = (STRING line) VOID: #todo: work on one line... # (print (("Got ", line, " - length is ", UPB line, newline))); #-----------------------------------# PROC read all = (STRING filename) STRING: (FILE filein; BOOL endfile := FALSE; INT linecount := 0; STRING line, contents := ""; CHAR eol = REPR (10); open (filein, filename, stand in channel); #set up eof event handling: # on logical file end (filein, (REF FILE f) BOOL: endfile := TRUE); get (filein, (line, newline)); WHILE NOT endfile # endfile set AFTER attempt to read beyond # DO process line (line); linecount +:= 1; contents:= contents + line + eol; get (filein, (line, newline)) OD; #return this value: # contents); #-----------------------------# print (read all ("intest.txt")) #call the proc #
About the programHere, I'm not going to use the precise Algol 68 terminology, and will stick to more familiar words.
Note the keywords in capitals, and the #comments#
In some cases - such as enclosing the body of a PROC (actually known as a 'function'), we can use brackets or BEGIN/END.
Variable names can contain spaces and underscores, but not capitals.
The term for an array is a 'multiple'. To use 'print' for more than one item, we must make them into a multiple, hence the two sets of brackets. We can get the upper bound via UPB.
End-of-file, when it is triggered, it is regarded as an event, and we set up a kind of event-handler with 'on logical file end'. We set a boolean to true, and when the WHILE is reached, the loop terminates.
Among other things, the 'read all' function returns a long string containing all of the lines. We mark the end of one line with the newline character - code 10. Not really in the Algol 68 spirit though!
We can use + to join strings and characters. Quite powerful for 1968!
The last item evaluated in a PROC is returned as its result.
We call the function with a file name string. We could have asked the user to type it in, or, more usefully, get the name from command-line arguments. We can use argc (argument count) and the argv function, e.g. argv(3).
Though strings are defined in the language, and they can be joined and used like any multiple, there is no powerful string library. Perhaps this was not common at the time? I decided to write 2 useful string functions (a 'contains substring' and a 'replace substring' function). The code is below. I chose to put them in a separate file, and use an 'include' feature. Firstly we have a tiny demonstration program, then the functions. (They are not bulletproof yet, as indicated in the comments).
Here is the demo:
# string-functions-demo.a68 # #Includes my string functions - PR is a kind of pragma (pragment!!)# PR include "stringfuncs.a68" PR print ((contains ("BC", "AABC"), newline)); #expect +3 # #expect "My fish fishalog" # print ((replace ("cat", "fish", "My cat catalog"), newline))and here are the functions:
#stringfuncs.a68 (the functions only) # PROC replace = (STRING old, STRING bynew, STRING big) STRING: # replace old by new in big # (STRING answer := big; INT start := 1; IF contains (old, bynew) > 0 THEN #todo: prevent infinite looping# big ELSE INT pos := contains (old, answer); WHILE pos > 0 DO answer := answer[1 : (pos - 1)] + bynew + answer[pos + UPB old : UPB answer]; pos := contains (old, answer) OD; answer FI); #------------------------------------------------------# PROC contains = (STRING tofind, STRING original) INT: # does original contain tofind? - return its position, or 0 # (BOOL found := FALSE; INT place := 0; #0 = not there # IF (UPB tofind = 0) OR (UPB original = 0) #todo: check to find not "" # THEN 0 ELSE INT lenwanted := UPB tofind; FOR i TO UPB original - (lenwanted - 1) WHILE NOT found DO STRING onesubstring := original[i : i + (lenwanted - 1)]; IF onesubstring = tofind THEN found := TRUE; place := i FI OD; place FI);The form of a function definition is as follows, but we can choose to use BEGIN/END,
PROC name = (any arguments and their types) return-type: ( ...code body ); #or# PROC name = (any arguments and their types) return-type: BEGIN ...code body END;The 'for' statement is very powerful. Look at the FOR and WHILE in the 'contains' function. In fact, the WHILE is part of the FOR. The full form is FOR...FROM...TO...BY...FROM...WHILE.
We have UPB and LWB to provide the upper and lower bounds of a multiple.
The x : y form, with a colon, provides a slice from a multiple.
Looking back it is interesting to see what influence Algol 68 had on languages which followed. Not in the language specification area, but in features. Not every feature was inherited, but some were, You won't get a job based on your Algol 68 knowledge, but you might find it interesting to explore. Long story short: read the Lindsey paper mentioned at the top of this page.
Here is a small editor, written in Lazarus Pascal, reconfigured to run Algol 68. It has built-in buttons to compile and run a program, and to pretty-print it. It is set to use the ',a68' file extension. Download, unzip, and look at the help file. Good Luck!
Here is the download - it is 8 MB.