This manual documents how to run, install and use the Algol 60 Interpreter.
This Algol 60 interpreter is based upon the “Revised Report on the Algorithmic Language Algol 60” [RRA60].
At school, a long time ago, I learned Algol 60 in a completely theoretical manner. Later I learned Algol 68 and C (and more ...).
The concept of call-by-name never left my mind, and so I started to write this Algol 60 interpreter: Made for fun and a call-by-name.
Here is an example:
'begin' 'integer' 'procedure' one; 'begin' write (`one called \n'); one := 1 'end'; 'procedure' foo (n); 'integer' n; 'if' n > 0 'then' foo ( n - one ); foo (5) 'end'
The parameter `n' in `foo (n)' is called by name. Every time `n - one' is evaluated, `n' is evaluated by name. Guess how many times `one' is called: 5, 10, 15 ?
Guess or prove ? – I want to run the example and see the result. And now you can do like me.
This was the main goal: call-by-name.
Many things were later added, and now the defining description of the “Revised Report on the Algorithmic Language Algol 60” is nearly (hopefully) fulfilled.
A60 now runs on Un*x machines and PC's.
Since version v0.18 a configure script is provided.
Simply run ./configure
followed by make
.
For your convenience the old Makefile is still avail as Makefile.unx.
If configure does not work for you, follow this old instructions:
Glance through the Makefile and change the FLAGS as appropriate:
_POSIX_SOURCE
USG
VPRINTF_MISSING
REALLOC_MISSING
ALLOCA_MISSING
NO_LIMITS_H
LONG_MIN
and LONG_MAX
. (don't care: set it if
you're in doubt)
NO_ENUMS
DEBUG
PARSEDEBUG
MEMORY_STATISTICS
For installation adjust BINDIR to point to the destination for the “a60” binary, and LIBDIR to point to the destination of the “a60-mkc.inc” file. If you don't want this, set them to `/tmp'; they are only used, if C output is being compiled. MANDIR and MANSUFF are used to install the “a60.man” manual page.
Ah, we are back to normality:
Say make
to compile.
If you would like to make the simple edit-and-go xa60 application, say
make xa60
.
If you would like to run the test suite, say make test
, and
hopefully no differences between the expected output and the actual
output will be found.
Say make install
to install the binary, the manpage and the
include-file.
Say make xa60-install
to install the xa60 binary and the xa60
manpage.
I've compiled the sources with QuickC v2.0 using qc-makeit.bat. The project file is qc-a60.mak. The compiler itself runs short of memory when running the optimiser, so the a60-ptab.c module had better be compiled without it.
C code generation is possible, but I've tried it only with few examples, because the large generated macros cannot be compiled properly.
When you invoke Algol 60 ...
Without arguments, the program text is read from standard input, and executed upon reaching EOF.
The available options:
There is a strict form of the input which conforms to RRA60 and also a simple form.
The strict form:
Keywords are expected to be enclosed in single quotes: '. For example: 'begin', 'for', 'if', 'end'.
The case of letters is insignificant in keywords. For example: 'begin' is the same as 'Begin', 'integer' loopvar is the same as 'INTEGER' loopvar.
Whitespace characters are skipped in the input, except in strings. For example: 'integer' greatnumber is the same as 'integer' great number, and the same as ' i n t e g e r' great n u m b e r.
Strings are expected to be enclosed in double quotes, or in a backquote and a quote. For example: "This is a string", `This is a string'. The '\' is recognized as a escape character (like C syntax). "\n" is a linefeed, "\"" is a double-quote and "\\" is a backslash.
The simple form:
Keywords are written like identifiers. For example: begin, for, if, end. White spaces are recognized to separate tokens. Therefore, it is illegal to use: integer great number;
The simple form is used if no quoted keyword is scanned. RRA60 conformance can be forced with the `-strict' option.
entier, abs, sign, sqrt, sin, cos, arctan, exp: implemented as described in RRA60.
rand, pi: random number generation and the constant “pi”:
'real' 'procedure' rand; 'code'
returns a random number between 0.0 (inclusive) and 1.0 (exclusive). The randomness of “rand” is not very robust.
'real' 'procedure' pi; 'code'
returns the constant “pi”.
length, outstring, insymbol, outsymbol
'integer' 'procedure' length (string); 'string' string; 'code';
returns the length of the string string.
'procedure' outstring (channel, value); 'value' channel; 'integer' channel; 'string' value; 'code';
send the string value to the channel channel. Currently, the only channel implemented is 1 (standard output).
'integer' 'procedure' write (string); 'string' string; 'code';
Prints the string string to standard output. This is the same behavior as outstring (1, string).
'integer' 'procedure' insymbol (channel, string, value); 'value' channel; 'integer' channel, value; 'string' string; 'code';
A character is read from channel channel. Currently, the only channel implemented is 0 (standard input). If the character is found in string, the index is returned. If the character is not found, the negative character code is returned.
'procedure' outsymbol (channel, string, source); 'value' channel, source; 'integer' channel, source; 'string' string; 'code';
Prints the character at the source position of string string to channel channel. Currently, the only channel implemented is 1 (standard output). If source is a negative value, -source is used; string is ignored.
'procedure' print (value, f1, f2); 'value' value, f1, f2; 'real' value; 'integer' f1, f2; 'code';
The value value is printed with f1 and f2 used as format. [ still missing: *** describe f1 and f2 *** ] The output is printed to standard output.
'procedure' inreal (channel, value); 'value' channel; 'integer' channel; 'real' value; 'code';
Reads a real number from channel channel and assigns them to value. Currently, the only channel implemented is 0 (standard input).
'procedure' outreal (channel, value); 'value' channel, value; 'integer' channel; 'real' value; 'code';
Prints the value value to channel channel. Currently, the only channel implemented is 1 (standard output).
'procedure' outinteger (channel, value); 'value' channel, value; 'integer' channel, value; 'code';
Prints the value value to channel channel. Currently, the only channel implemented is 1 (standard output).
'procedure' vprint (...); 'code';
Vprint prints the variable arguments to the standard output.
The output is terminated with a newline-character. Numbers are
printed width a fixed with (about 14 characters).
For example: vprint ("Foo: ", 12, 99.9).
[** Still not finished **]
C-code creation for less complex programs is now possible. The resulting code is somewhat faster (example whetstones: about a factor of 50).
Call-by-name procedures must be expandable into C macros. The other procedures are translated into C functions.
Problems / Restrictions:
Example 1:
'begin' write ("Hi!\n") 'end'
Assume these three lines are in a file named `hi.a60'. Run it with the call `a60 hi': It produces the output:
Hi!
Example 2:
'begin' 'integer' 'procedure' fakul (n); 'value' n; 'integer' n; 'begin' 'if' n < 1 'then' fakul := 1 'else' fakul := n * fakul (n - 1) 'end'; 'integer' result; outstring (1, "See fakul (5): "); result := fakul (5); outinteger (1, result); outstring (1, "\n"); 'end'
This will produce the output:
See fakul (5): 120
Example 3:
The classic call-by-name example: The “Jensen Device”:
[ Note: Here the keywords are not quoted; this is not RRA60 compliant, but usable as an extension of NASE A60. ]
begin procedure jdev ( i, n, s, x ); begin s := 0; for i := 1 step 1 until n do s := s + x; end; integer NN; NN := 100; begin integer i; real sum; integer array arr [1 : NN]; for i := 1 step 1 until NN do arr[i] := i; jdev (i, NN, sum, arr [i]); outstring (1, `See the sum: '); outreal (1, sum); outstring (1, `\n') end end
This will produce the output:
See the sum: 5050
The clever part is the loop-variable used in jdev which is passed by name and used as index in the array “arr [i]”.
[ *** not yet - sorry *** ]
Surely there are many bugs. Of interest are any core dumps: regardless of correct input or not and compile-time and run-time misbehavior, this should never happen. Secondary are the elegance and efficiency of the implementation.
Please report bugs to Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de). Hopefully I will have enough time to reply.