WAITS: Programming in SAIL
Today we'll look at SAIL, which was derived from Algol 60 and was developed and used on WAITS for both system programs and research projects.
There was a compiler named SAIL,
Assembled and coded in FAIL.
Its authors, they say
(one glorious day)
Were run out of town on a rail.
Comment in the source code for the SAIL compiler, SAIL[S,AIL]
History
SAIL was a combination of work done on two languages. The first was Gogol, which was a simplified version of Algol 60 for the PDP-1. Not much information on this remains apart from a list of its error messages.
The other source - primarily for its associative arrays - was the LEAP language, which was written by Jerome Feldman and Paul Rovner for the Lincoln Labs Tx-2 machine; there's a paper describing this at the ACM.
The compiler was written by SAIL members Don Swinehart and R. Sproull, with the first version being available in November 1969. As the manual puts it
SAIL in a sense has something for everyone. For those who think in ALGOL, SAIL has ALGOL. For those who want the most from the PDP-10 and the time-sharing system, SAIL allows flexible linking to hand-coded machine language programs. For those who have complex input/output requirements, the language provides complete access to the I/O facilities of the PDP-10 system. For those who aspire to speed, SAIL generates fairly good code.
It achieved its goal, with wide use at Stanford and it spread to other PDP-10 sites.
In 1980, there was a commercial spin off of SAIL called MAINSAIL. This was cross-platform, with initial versions on other PDP-10 and -11 operating systems, and possibly VAX and System/360 also. The language had some success (one user was VLSI Technologies for electronic design tools) and was available for at least HP-UX, AIX and IRIX up to the early 2000s. Bitsavers has some documentation.
SAIL features
Like every other Algol 60 implementation, program format and I/O is slightly different, so to set the scene, here's a simple hello world program.
BEGIN
INTEGER I;
COMMENT Print Hello World 5 times;
FOR I ← 1 STEP 1 UNTIL 5 DO
OUTSTR("HELLO, WORLD" & '15 & '12)
END PROGRAM
This follows the typical Algol 60 block structure, using BEGIN …
END and having statements separated rather than terminated by
semicolons, so the last statement in a block should not have a
semicolon at the end. Comments are statements as well so need to be
terminated depending on their position.
The assignment operator ← is an arrow, which was typeable using the
Stanford keyboard; on a teletype you could use _ instead. A ↔ B
would swap the values of A and B.
For I/O there is an extensive set of routines that can handles files
and different devices, but for console I/O you can use OUTSTR to
print strings (adding a CR/LF line terminator in the above example)
and read a line of input to a string with INCHWL.
Real, integer and boolean types are provided, along with arrays.
Strings are internally represented as a two word value, the first
being a character count and the second a pointer to an array of 7 bit
characters. The body of the OUTSTR shows concatenation of a string
literal with two characters, CR/LF, to produce a new string.
Procedures take value or reference parameters, can be called
recursively (with the keyword RECURSIVE PROCEDURE). Procedures can
also be passed into other procedures.
The LEAP facilities allow sets (PUT item IN set) and associative
arrays (MAKE key ⊗ object ≡ value). You can then do search operations
on these using FOREACH. An example adapted from the manual:
FOREACH x,y,z SUCH THAT father ⊗ x ≡ y AND father ⊗ y ≡ z DO
PUT z IN grandfathers
Macros are similar to C's macro processor: you can define constants and then they get expanded in the program when used:
DEFINE ARRAY_SIZE="11";
...
INTEGER ARRAY DATA[1:ARRAY_SIZE];
or to take parameters.
DEFINE APPEND(x, y)="x ← x & y";
TPK in SAIL
Let's use the compiler to run the TPK algorithm. The source code can be found here. This can be loaded onto the disk using the techniques described in this post.
The full program looks like this:
BEGIN
COMMENT TPK algorithm in SAIL for WAITS;
REQUIRE "{}{}" DELIMITERS;
COMMENT Size of array to use for TPK;
DEFINE N = {11};
COMMENT Macro definitions to print a string with CR/LF at the end;
DEFINE CRLF={('15 & '12)};
DEFINE TYPE(MSG)={OUTSTR(MSG & CRLF)};
REAL PROCEDURE FN(REAL X);
BEGIN
RETURN(SQRT(ABS X) + 5*X↑3)
END;
COMMENT Main program;
INTEGER J;
REAL ARRAY A[1:N];
TYPE("Please enter 11 numbers");
FOR J ← 1 STEP 1 UNTIL N DO
BEGIN
STRING REPLY;
BOOLEAN BRCHAR;
REPLY ← INCHWL;
A[J] ← REALSCAN(REPLY, BRCHAR)
END;
TYPE("Results are");
FOR J ← N STEP -1 UNTIL 1 DO
BEGIN
REAL RESULT;
RESULT ← FN(A[J]);
IF RESULT > 400.0 THEN
TYPE("Too large")
ELSE
TYPE(CVF(RESULT))
END;
END
One additional trick is used for macros:
REQUIRE "{}{}" DELIMITERS;
DEFINE TYPE(MSG)={OUTSTR(MSG & CRLF)};
The first line redefines the start and end delimiters for macros to be
curly brackets rather than double quotes; if this is not done, any
double quotes in the text being expanded, for example a string
constant TYPE("Hello") would not work.
The procedure FN shows use of ABS as a unary function, and ↑ as
the exponentiation operator.
We use several type conversion functions here. REALSCAN takes a
string and a boolean and returns a real value if found, otherwise it
will set the boolean to true (we ignore this in the program). CVF
conversed a real to a string.
To compile and run, assuming the program is stored in a file
tpk.sai, use exec:
.exec tpk SAIL: TPK 1 LOADING LOADER 2K CORE EXECUTION Please enter 11 numbers
Errors found in compilation are handled interactively. If for some
reason I had put UNREAL PROCEDURE it would halt with
.comp tpk
SAIL: TPK 1
UNDECLARED IDENTIFIER: UNREAL
TPK, PAGE 1
01100 UNREAL
PROCEDURE FN(REAL X);
^
At this prompt, you can press Enter to continue: in some cases it may
be able to correct the situation but here it would ignore the
statement. You could press E and it would open the file at that line
in the SOS editor; T would do the same in TV. X would exit.
Pressing ? shows a full list of what options are available
Further information
The main manual for SAIL can be found in SAIL.DCS[S,DOC] or on Bitsavers as a PDF.
Dan Swinehart gave a talk on the history of SAIL (and some background on its name) at a 2009 reunion - the video is at the Stanford Archives.
Questions, corrections, comments
I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com and I will add it here and update the main text.