SAIL (programming language)
Template:Short description Template:Infobox programming language SAIL, the Stanford Artificial Intelligence Language, was developed by Dan Swinehart and Bob Sproull of the Stanford AI Lab. It was originally a large ALGOL 60-like language for the PDP-10 and DECSYSTEM-20. The language combined the earlier PDP-6/-10 language GOGOL compiler, essentially an integer-only version of ALGOL, with the associative store from the LEAP language. The first release was in November 1969 and it saw continued development into the 1980s, including a commercial derivative, MAINSAIL.
SAIL's main feature is a symbolic data system based upon an associative store based on LEAP by Jerry Feldman and Paul Rovner. Items may be stored as unordered sets or as associations (triples). Other features include processes, procedure variables, events and interrupts, contexts, backtracking and record garbage collection. It also has block-structured macros, a coroutining facility and some new data types intended for building search trees and association lists.
HistoryEdit
The GOGOL compiler was originally written by Bill McKeeman on the PDP-1. It was essentially an integer-only version of ALGOL-60 with a number of additions to provide direct access to the memory and other hardware to allow it to be used as a systems programming language. It reduced arrays to a single dimension, removed any ability to perform dynamic memory allocations, but did add some additional string functionality. A greatly updated version by John Sauter, GOGOL II, was written as part of a port of the underlying operating system from ODIN to THOR. When the Stanford AI Lab received their PDP-6, Sauter, Pettit and (mostly) Dan Swinehart wrote GOGOL III for the new machine.Template:Sfn
Swinehart, joined by Robert Sproull, merged the GOGOL syntax with additions from the contemporary versions of the LEAP language to produce the first version of SAIL in November 1969. The main feature of LEAP as a language was its use of associative storage, more commonly known today as a Map or Dictionary. In LEAP, one could set the value of a field in a type using a triple, with the first entry being the variable name, the second being the field name, and the third the value.Template:Sfn
Further improvements were added by Russell Taylor, Jim Low and Hana Samet, who added processes, procedure variables, interrupts, context, matching procedures, a new macro system, and other features. Development then passed to Taylor, John Reiser and Robert Smith, who added a debugger, a system-level print statement, records, and performed the conversion from Standord's own SUAI to TENEX. It was later ported to DEC's TOPS-10 as well, while the original TENEX version worked without modification under TOPS-20.Template:Sfn
DescriptionEdit
Basic structure and statementsEdit
Like many ALGOL systems, and the later Pascal, the basic structure of SAIL is based on the block, which is denoted by the code between the keywords <syntaxhighlight lang="text" class="" style="" inline="1">BEGIN</syntaxhighlight> and <syntaxhighlight lang="text" class="" style="" inline="1">END</syntaxhighlight>. Within a block there is further structure, with the declarations of local variables at the top, if any, and the code, or statements, following. In contrast to most dialects, SAIL allowed one to place a string after the <syntaxhighlight lang="text" class="" style="" inline="1">BEGIN</syntaxhighlight>, like <syntaxhighlight lang="text" class="" style="" inline="1">BEGIN "program"</syntaxhighlight>, and then end the block with <syntaxhighlight lang="text" class="" style="" inline="1">END "program"</syntaxhighlight>. The compiler would use these, if entered, to check for proper bracketing.Template:Sfn SAIL did not include the equivalent of a <syntaxhighlight lang="text" class="" style="" inline="1">PROGRAM</syntaxhighlight> block as in Pascal, nor a <syntaxhighlight lang="text" class="" style="" inline="1">main</syntaxhighlight> as in C, execution started with the first line of code in the outermost block.Template:Sfn
Standard statements included <syntaxhighlight lang="text" class="" style="" inline="1">IF...THEN...ELSE</syntaxhighlight>,Template:Sfn <syntaxhighlight lang="text" class="" style="" inline="1">FOR...STEP...UNTIL...DO</syntaxhighlight>,Template:Sfn <syntaxhighlight lang="text" class="" style="" inline="1">WHILE...DO</syntaxhighlight> for top-tested loops, <syntaxhighlight lang="text" class="" style="" inline="1">WHILE...UNTIL</syntaxhighlight> for bottom-tested, and <syntaxhighlight lang="text" class="" style="" inline="1">GOTO</syntaxhighlight> which used a label.Template:Sfn The <syntaxhighlight lang="text" class="" style="" inline="1">CASE</syntaxhighlight> was similar to <syntaxhighlight lang="text" class="" style="" inline="1">switch</syntaxhighlight> in C, but normally used a somewhat different syntax, like <syntaxhighlight lang="text" class="" style="" inline="1">CASE i OF ("Zero","One","Two");</syntaxhighlight>, which returns the appropriate string based on the value of i.Template:Sfn If one wanted to test explicit values in the CASE, the values had to be in square brackets:
<syntaxhighlight lang=Pascal> CASE I OF
BEGIN [0] 10; [4] 25; [6][7] 50 END;
</syntaxhighlight>
This code will ignore values like 1 to 3, and only return a value for the listed values. Note that the last item cannot have a semicolon following.Template:Sfn
<syntaxhighlight lang="text" class="" style="" inline="1">DONE</syntaxhighlight> exited from a block, typically used in loops, and <syntaxhighlight lang="text" class="" style="" inline="1">CONTINUE</syntaxhighlight> returned to the top of the block. An infinite loop was typically implemented with <syntaxhighlight lang="text" class="" style="" inline="1">WHILE TRUE DO...</syntaxhighlight>.Template:Sfn
Procedure declarationsEdit
Procedures were implemented in a fashion similar to the C programming language, with the return type, if any, in front of the name, for instance, <syntaxhighlight lang="pascal" class="" style="" inline="1">STRING PROCEDURE toUpper(STRING originalStr);BEGIN...</syntaxhighlight>. Note the uncommon use of the semicolon here, whereas Pascal would immediately follow with a block, typically a <syntaxhighlight lang="text" class="" style="" inline="1">BEGIN</syntaxhighlight>.Template:Sfn
In order to improve performance, SAIL added two procedure qualifiers, <syntaxhighlight lang="text" class="" style="" inline="1">SIMPLE</syntaxhighlight> and <syntaxhighlight lang="text" class="" style="" inline="1">RECURSIVE</syntaxhighlight>. <syntaxhighlight lang="text" class="" style="" inline="1">RECURSIVE</syntaxhighlight> told the compiler that the procedure might call itself, and thus its local variables had to be written to the stack, not just the subroutine return information. <syntaxhighlight lang="text" class="" style="" inline="1">SIMPLE</syntaxhighlight> did the opposite, demanding the procedure have no local variables at all, not allowing <syntaxhighlight lang="text" class="" style="" inline="1">GOTO</syntaxhighlight> out of the function, and could not refer to enclosing procedure's variables. These directives could avoid the requirement of filling out a complete activation record, thereby improving performance.Template:Sfn This also had the side-effect of meaning that variables declared within a procedure that was not marked <syntaxhighlight lang="text" class="" style="" inline="1">RECURSIVE</syntaxhighlight> would not be reset between calls,Template:Sfn acting similar to C's <syntaxhighlight lang="text" class="" style="" inline="1">static</syntaxhighlight>.
SAIL also included the <syntaxhighlight lang="text" class="" style="" inline="1">FORWARD</syntaxhighlight> qualifier, used to insert forward declarations, typically when two procedures call each other.Template:Sfn <syntaxhighlight lang="text" class="" style="" inline="1">RETURN</syntaxhighlight> worked as in C, exiting the procedure and returning to the caller, as well as optionally returning a value if the procedure uses one.Template:Sfn Parameters passed to the procedures could be by <syntaxhighlight lang="text" class="" style="" inline="1">VALUE</syntaxhighlight> or <syntaxhighlight lang="text" class="" style="" inline="1">REFERENCE</syntaxhighlight>, the later allowing values to be passed back.Template:Sfn
Basic data types and operatorsEdit
The basic variable types in SAIL are integers, reals (floating point), booleans, and strings.Template:Sfn Type conversions were automatic, so <syntaxhighlight lang="pascal" class="" style="" inline="1">INTEGER i;i←SQRT(5);</syntaxhighlight> would convert the value 5 to a double as that is what SQRT requires, and then cast the result to an integer.Template:Sfn Any of these types can be turned into an array by adding the <syntaxhighlight lang="text" class="" style="" inline="1">ARRAY</syntaxhighlight> qualifier and placing the array bounds in brackets, for instance, <syntaxhighlight lang="pascal" class="" style="" inline="1">REAL ARRAY weeks[1:52]);</syntaxhighlight>. SAIL supported 1-d and 2-d arrays.Template:Sfn
The language used the left-arrow for assignment, <syntaxhighlight lang="text" class="" style="" inline="1">←</syntaxhighlight>, or the underscore on platforms that did not have Stanford ASCII.Template:Sfn It included a number of standard functions like square root, all of the common math operators, and was otherwise similar to most ALGOL derivatives for normal programming.Template:Sfn
Strings were manipulated using array slicing, with <syntaxhighlight lang="text" class="" style="" inline="1">aStr[i TO j]</syntaxhighlight> returning the substring with characters from i to j, or <syntaxhighlight lang="text" class="" style="" inline="1">aStr[i FOR j]</syntaxhighlight> which returned the substring starting at i and running for j characters.Template:Sfn The <syntaxhighlight lang="text" class="" style="" inline="1">INF</syntaxhighlight>(inity) keyword represented the end of the string, so one could <syntaxhighlight lang="text" class="" style="" inline="1">aStr[i TO INF]</syntaxhighlight> to return everything from i on.Template:Sfn String functions and operators included <syntaxhighlight lang="text" class="" style="" inline="1">EQU</syntaxhighlight> for testing if two strings were equal,Template:Sfn the ampersand for concatenation, <syntaxhighlight lang="text" class="" style="" inline="1">LENGTH</syntaxhighlight>, and <syntaxhighlight lang="text" class="" style="" inline="1">LOP</syntaxhighlight> which removes the first character from the string.Template:Sfn There was no way to compare strings other than <syntaxhighlight lang="text" class="" style="" inline="1">EQU</syntaxhighlight>, operators like <syntaxhighlight lang="text" class="" style="" inline="1"><</syntaxhighlight> were defined only for numbers.Template:Sfn
Records and pointersEdit
The concept of records as a data type had only recently been introduced when SAIL was being written. This feature thus shows the signs of being "bolted on" to the language syntax. For instance a record structure was defined using the <syntaxhighlight lang="text" class="" style="" inline="1">RECORD!CLASS</syntaxhighlight> statement: <syntaxhighlight lang="pascal" class="" style="" inline="1">RECORD!CLASS person (STRING name, address; INTEGER accountnum; REAL balance)</syntaxhighlight>. This statement worked in a fashion similar to the <syntaxhighlight lang="text" class="" style="" inline="1">RECORD</syntaxhighlight> statement in Pascal, defining the template for the record. To create a record, one used the <syntaxhighlight lang="text" class="" style="" inline="1">NEW!RECORD</syntaxhighlight> statement, which returned a <syntaxhighlight lang="text" class="" style="" inline="1">RECORD!POINTER</syntaxhighlight>. Pointers were typed, and could be typed to more than one type, for instance, <syntaxhighlight lang="pascal" class="" style="" inline="1">RECORD POINTER (person,university) rp;</syntaxhighlight> defines rp, a pointer to either a person or university record.Template:Sfn Pointers could also be declared to point to <syntaxhighlight lang="text" class="" style="" inline="1">ANY!CLASS</syntaxhighlight>.Template:Sfn Accessing the data in a record was similarly idiosyncratic; to print the name file of a person, for instance, the syntax was <syntaxhighlight lang="text" class="" style="" inline="1">PRINT(person:name[rp]);</syntaxhighlight>.Template:Sfn
String scannerEdit
In addition to basic string functionality, SAIL included a string scanner system as part of the basic language. <syntaxhighlight lang="text" class="" style="" inline="1">SCAN</syntaxhighlight> worked on string variables, while the otherwise similar <syntaxhighlight lang="text" class="" style="" inline="1">INPUT</syntaxhighlight> was used to scan strings being read from a file. Both used a system known as a "break table" which consisted of a set of characters that represented places to stop reading, examples include linefeeds, various whitespace, and punctuation. These tables were stored in special structures, and the system allowed only 54 of these, a number that is not explained in the documentation.Template:Sfn
To build a new table, one first called <syntaxhighlight lang="text" class="" style="" inline="1">GETBREAK</syntaxhighlight> which returned the next free slot in the table, or "table number". This would be followed by a <syntaxhighlight lang="text" class="" style="" inline="1">SETBREAK</syntaxhighlight>, which took the table number, a string with the break characters, another string of "omit characters" which were simply ignored during reading (as if they were not in the string) and finally the "modes", flags that indicated how the system should work. Once set, the program could then repeatedly call <syntaxhighlight lang="text" class="" style="" inline="1">SCAN</syntaxhighlight> or <syntaxhighlight lang="text" class="" style="" inline="1">INPUT</syntaxhighlight> and be returned complete strings.Template:Sfn This included a reference parameter, normally brkchar, that contained the character that caused the break, allowing one to test, for instance, for end-of-file characters. The system is conceptually similar to C's <syntaxhighlight lang="text" class="" style="" inline="1">strtok</syntaxhighlight> functionality, which is part of stdlib<ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref> as opposed to being part of the language itself as in SAIL.
Input/OutputEdit
SAIL's input/output system was based on the idea of numbered "channels" in a fashion somewhat similar to the scanner entries. To open a file, one first called <syntaxhighlight lang="text" class="" style="" inline="1">GETCHAN</syntaxhighlight> to return a value of a free channel, and then <syntaxhighlight lang="text" class="" style="" inline="1">OPEN</syntaxhighlight>ed it with various parameters to describe the file and modes of operation. <syntaxhighlight lang="text" class="" style="" inline="1">RELEASE</syntaxhighlight> was equivalent to close. Once opened, the file could be read, subject to the scanning rules noted above, by calling <syntaxhighlight lang="text" class="" style="" inline="1">INPUT</syntaxhighlight> and looking for the end-of-file. Files did not have names as part of the OPEN, instead, <syntaxhighlight lang="text" class="" style="" inline="1">LOOKUP</syntaxhighlight> could be used to point a channel at a given file, <syntaxhighlight lang="text" class="" style="" inline="1">ENTER</syntaxhighlight> made a new file associated with a channel, and <syntaxhighlight lang="text" class="" style="" inline="1">RENAME</syntaxhighlight> allowed an existing file name to be changed.Template:Sfn One can open an existing file for writing using <syntaxhighlight lang="text" class="" style="" inline="1">GETCHAN... OPEN... LOOKUP... ENTER</syntaxhighlight>.Template:Sfn
There were numerous special handlers and variables that were used during I/O. For instance, the <syntaxhighlight lang="text" class="" style="" inline="1">INCHWL</syntaxhighlight> function was an INPUT hard-wired to the user terminal and always open, and it returns its break character in the system variable <syntaxhighlight lang="text" class="" style="" inline="1">!SKIP!</syntaxhighlight>.Template:Sfn The <syntaxhighlight lang="text" class="" style="" inline="1">PRINT</syntaxhighlight> function normally output to the same terminal channel, but could also be directed at any other opened channel.Template:Sfn
Compiler directivesEdit
As a systems programming language, performance was important and to help with this, SAIL included a <syntaxhighlight lang="text" class="" style="" inline="1">DEFINE</syntaxhighlight> which used string-replacement in a fashion similar to C's <syntaxhighlight lang="text" class="" style="" inline="1">#define</syntaxhighlight> macros.Template:Sfn A difference was that the delimiters around the substitution had to be defined, for instance <syntaxhighlight lang="text" class="" style="" inline="1">REQUIRE "[][]" DELIMITERS;DEFINE maxSize=[100];</syntaxhighlight>. One common use of these macros was to define character constants like <syntaxhighlight lang="text" class="" style="" inline="1">CRLF</syntaxhighlight>, as these were not part of the basic language.Template:Sfn Another was to redefine the <syntaxhighlight lang="text" class="" style="" inline="1">COMMENT</syntaxhighlight> statement to the shorter <syntaxhighlight lang="text" class="" style="" inline="1">!</syntaxhighlight>.Template:Sfn
The system also included a conditional compilation system using statements, as opposed to pre-processor directives as found in C. <syntaxhighlight lang="text" class="" style="" inline="1">IFCR</syntaxhighlight> would compile the blocks between the corresponding <syntaxhighlight lang="text" class="" style="" inline="1">THENC</syntaxhighlight> and <syntaxhighlight lang="text" class="" style="" inline="1">ELSEC</syntaxhighlight> or <syntaxhighlight lang="text" class="" style="" inline="1">ENDC</syntaxhighlight>. The condition in the IFCR must be known at compile time, so, like C, was normally a <syntaxhighlight lang="text" class="" style="" inline="1">DEFINE</syntaxhighlight>d value.Template:Sfn
LEAP dataEdit
The main difference between SAIL and other ALGOL-derived languages was its inclusion of the associative store from the LEAP language. This system provided a system that allowed data to be placed in record-like structures and then saved, retrieved and searched. In this respect it was similar to the data handling features in COBOL. The basis for the store was the association or triple, which allowed a data value to be associated with a named slot in a record. For instance, one might make a record of the type <syntaxhighlight lang="text" class="" style="" inline="1">Family_Member</syntaxhighlight> with <syntaxhighlight lang="text" class="" style="" inline="1">Name</syntaxhighlight> "Tom" and set the <syntaxhighlight lang="text" class="" style="" inline="1">Father</syntaxhighlight> field to "Harry". This results in a triple of the form (Father, Tom, Harry). The associated libraries could then find all the <syntaxhighlight lang="text" class="" style="" inline="1">Family_Member</syntaxhighlight>s with "Harry" as the <syntaxhighlight lang="text" class="" style="" inline="1">Father</syntaxhighlight>, perhaps returning "Tom" and "Alice".Template:Sfn
ExampleEdit
The following code, found in the Tutorial, converts an input string to upper case.Template:Sfn
<syntaxhighlight lang="text"> STRING PROCEDURE upper(STRING rawstring);
BEGIN "upper" STRING tmp; INTEGER char; tmp←NULL; WHILE LENGTH(rawstring) DO BEGIN char←LOP(rawstring); COMMENT LOP returns the first character and moves the pointer past it tmp←tmp&(IF "a" LEQ char LEQ "z" THEN char-'40 ELSE char); END; RETURN(tmp); END "upper";
</syntaxhighlight>
UsesEdit
A number of interesting software systems were coded in SAIL, including some early versions of FTP and TeX, a document formatting system called PUB,<ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref> and BRIGHT, a clinical database project sponsored by the National Institutes of Health.<ref>Template:Cite journal</ref><ref>Template:Cite book</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref><ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref>
In 1978, there were half a dozen different operating systems for the PDP-10: ITS (MIT), WAITS (Stanford), TOPS-10 (DEC), CMU TOPS-10 (Carnegie Mellon), TENEX (BBN), Tymcom-X (Tymshare), and TOPS-20 (DEC, based on TENEX).
SAIL was ported from WAITS to ITS so that MIT researchers could make use of software developed at Stanford University. Every port usually required the rewriting of I/O code in each application.
Template:AnchorA machine-independent version of SAIL called MAINSAIL was developed in the late 1970s and was used to develop many eCAD design tools during the 1980s. MAINSAIL was easily portable to new processors and operating systems, and was still in limited use Template:As of.
See alsoEdit
- Stanford Extended ASCII (SEASCII)