perm filename SAIL.PUB[10X,AIL] blob sn#432874
filedate 1979-04-09 generic text, type T, neo UTF8
.require "pubmac" source!file;
.<<xgpcol - not at Rutgers>>
This section describes changes and additions to Sail since the August 1976
Double precision floating-point arithmetic is available.
Use the <type!qualifier> LONG in declarations. For example,
LONG REAL X, Y, Z;
LONG REAL ARRAY XA[0:N];
Currently LONG has meaning only when it appears as part of LONG REAL.
(At some future time LONG INTEGERs may also exist.)
The runtime routines LREALIN and LREALSCAN operate the same as REALIN and
REALSCAN, except for returning LONG REAL values. The routine CVEL takes a
LONG REAL value and returns a string representation like that of CVE,
except that "@@" is used to signify LONG when delimiting the exponent.
Any of "@", "@@", "E", or "D" are acceptable exponent delimiters to
LREALIN and LREALSCAN.
Variables which are declared LONG REAL are represented in KI10 hardware
format double precision, take two consecutive words of storage, and
provide 62 bits of precision (approximately 18 decimal digits) to
represent the fraction part of a floating-point number. Regular REAL
variables occupy a single word and have 27 bits (8 decimal digits) of
precision. The exponent range of both REAL and LONG REAL variables
is from -128 to 127, where 2↑127 is approximately 10↑38.
LONG REAL is a dominant type in arithmetic operations +-*/%↑ MAX MIN and
arithmetic relationals <>= LEQ GEQ NEQ. If one operand is LONG REAL then both
operands will be converted to LONG REAL (if necessary) before performing
the operation. An exponentiation involving a LONG REAL raised to a positive
integer constant is an exception to this rule. The type coercion path is
linear: STRING -> INTEGER -> REAL -> LONG REAL. Conversion from REAL to
LONG REAL is performed by assigning the (only) word of the REAL to the
most significant word of the LONG REAL and setting the second (least
significant) word of the LONG REAL to zero. Conversion from LONG REAL to
REAL is by UUO which rounds.
Arithmetic and assignment operations are compiled into DFAD, DFSB, DFMP,
DFDV, DMOVE, DMOVEM instructions. The Sail operations ASH, LSH, ROT,
LAND, LOR, EQV, XOR are performed on both words (ASHC, LSHC, ROTC, 2 ANDs,
2 IORs, etc.). LOCATION of a LONG REAL variable gives an address E such
that DMOVE AC,E fetches the appropriate words of memory. When passed by
value as an actual parameter to a procedure, both words are placed on the
P stack: PUSH P,X ; PUSH P,X+1. LONG REAL fields in record classes are
handled much like STRING fields, except that the address in the record
field points to the first word of a 2-word block (rather than to the
second word as in the case with STRINGs).
LONG REAL ARRAYs are stored as contiguous blocks of 2-word values.
ARRTRAN done on two LONG REAL arrays is a transparent operation, but for
ARRYIN, ARRYOUT, or ARRBLT the actual word count is specified; think `βout
whether you should multiply by 2! At runtime the array descriptor for a
LONG ARRAY has bit 12 (40,,0 bit) set in MULT(n), the multiplier for the
last dimension (which would otherwise be =1). Similarly, a LONG ARRAY is
allocated by setting bit 12 (40,,0) bit in the parameter which specifies
the number of dimensions to ARMAK.
Runtime support for LEAP items with LONG REAL datums does not yet
exist, although the compiler does generate suitable code.
Runtime support for double precision exponentiation is also limited
for the moment. Any exponentiation X↑K where K is a positive
integer constant is compiled inline using the binary ("Russian peasant")
method, regardless of the type of X. Other exponentiations involving
LONG REALs are merely translated into procedure calls on
LONG REAL PROCEDURE DPOW (INTEGER EXPONENT; LONG REAL BASE);
LONG REAL PROCEDURE DLOGS (LONG REAL EXPONENT, BASE);
depending on the type of the exponent. The Sail runtime system
does not yet contain such procedures, so you will have to roll your own.
.ss|Declarations and Scope|
Sail declarations must occur
before use. For example, in the following program the argument to PRINT
is interpreted as the K on line 2, even though by the ALGOL60 notion of
scope it should be interpreted as the K on line 5.
INTEGER K; COMMENT this is line 2;
PROCEDURE BAR; BEGIN PRINT(K) END;
INTEGER K; COMMENT this is line 5;
The compiler now recognizes "**" for "↑", ":=" for "←",
"<=" for "LEQ", and ">=" for "GEQ".
REQUIRE OVERLAP!OK; will suppress the message which occurs at initialization
when two programs have declared items.
REQUIRE VERIFY!DATUMS; causes the compiler to generate three additional instructions
for each DATUM reference, to make sure (dynamically, at run time) that the type
of the item in the DATUM construct is the same as the compiler expected.
This is similar to (the unimplimented effect of) declaring all itemvars CHECKED.
It is planned that VERIFY!DATUMS will soon be a bit in the /A switch
and that the corresponding REQUIRE will disappear.
REQUIRE PROCESSES; insures that MAINPR, the main process, is initialized.
You need not specify this REQUIRE if you use APPLY or SPROUT, but if the
only use of processes is via INTSET then you must REQUIRE PROCESSES;.
In an explicitly numbered CASE statement the word ELSE can appear where
a bracketed case number is normally used. The statement following the ELSE is a
catch-all for any case number not mentioned, including anything which
would otherwise generate a CASE index error. For example,
CASE K OF BEGIN  J←3; ELSE J←4;  J←5 END
is another way of accomplishing
IF K=3 THEN J←3
ELSE IF K=5 THEN J←5
A CASE statement containing an ELSE case does not generate a call to the CSERR
runtime routine, and in addition the jump table usually contains only
max_case - min_case +1 words (rather than max_case +1).
To define two record classes, both of which contain RECORD!POINTER fields
refering to the other class, say
FORWARD RECORD!CLASS BAR (RECORD!POINTER (ANY!CLASS) Q2);
RECORD!CLASS FOO (RECORD!POINTER (BAR) Q1);
RECORD!CLASS BAR (RECORD!POINTER (FOO) Q2);
In general, declare one class to be FORWARD and list its RECORD!POINTER
fields as pointers to ANY!CLASS. This breaks the circularity and allows
maximum compile-time type checking.
.sec|Support for Tops-20|
The "Tenex" version of SAIL has been modified slightly to support
Tops-20. In general SAIL should work the same on Tops-20 as it does
on Tenex. In particular, both the compiler and compiled SAIL programs
can be moved between vanilla Tenex and Tops-20 sites and do the
equivalent things. This is possible because all tests for Tops-20
or Tenex-specific code are made at run-time. Code for both will
be present in all Tenex versions. Note however that there are
assembly switches that allow the compiler to use instructions peculiar
to the KI-10 or KL-10. While these instructions are always available
on Tops-20, not all Tenex systems have the KI-10 instructions, and
no currently existing one has the KL-10 instructions. The default in
the exported edition is not to use any of these special instructions,
for the sake of compatibility. However many 20 sites will want to
change TENXSW and recompile so as to make use of the KI-10
instructions. This is known to work. I have not tested the KL-10
version, but it should also work. KI and KL instructions can be
used in compiled SAIL code by setting the /ARITHMETIC switch
(documented in the SAIL manual as /A) when the program is compiled.
The one exception to the happy picture of Tenex/Tops-20 compatibility
is with runtimes that are
named after JSYS's and are documented as simply doing that JSYS.
SAIL makes no attempt to insulate you from subtle differences in
the meaning of bits, or the fact that some of the JSYS's do not
exist in one of the systems. The most infamous of these problems
is the removal of the STDIR JSYS in Tops-20. That means that
SAIL programs using STDIR will blow up on Tops-20. (However
similar results may be obtained using the RCDIR and RCUSR routines,
which support the corresponding JSYS's in Tops-20.)
The following differences in behavior follow from the desire to
make SAIL on Tops-20 look like a "real" Tops-20 system:
When the compiler is run directly on Tops-20, a new command
scanner is used. It follows the new DEC standards and uses the COMND
jsys. It expects a list of file names, with switches being
allowed before or after any file name. The switch names have
been changed to be longer than the one-character names documented
in the manual. However the names fit the descriptions given
in the manual, so you should hae no problem identifying
which switch is which if you type ?. Switches that take numerical
values use the new syntax: /SWITCH:value. Switches that take
octal numbers to specify sets of options have an additional
form, thogh the old octal values will still work. The additional
form involves the syntax /SWITCH:option or /SWITCH:(opt1,opt2,...),
where option is a keyword. If you type /SWITCH:? you should have
no trouble identifying the options with those described in the
manual. By default the compiler will produce a binary output
file and no listing. To produce a listing, use /LIST, or /CREF if it
is to be a CREF listing. To suppress the binary file, use /NOBIN.
To use non-standrad filenames, /LIST, /CREF, or /BINARY can be used
with filenames as arguments.
The compiler can be called by the EXEC for the COMPILE, EXECUTE,
LOAD, and DEBUG commands. The command expected is the usual
format, i.e. a Tops-10 format command of the form BIN,LIST=SOURCES.
However the EXEC is assumed to pass directory names rather than
PPN's. If your EXEC passes PPN's you will only be able to compile
files on your connected directory. This scanner is used when
the compiler is started at the starrting address + 1 on Tops-20.
On Tenex, certain files are expected to be on <SAIL> or <SUBSYS>.
The most important examples are <SAIL>T-6-SAISG8.SAV and
<SUBSYS>LOADER.SAV. On Tops-20, such files are looked for
on logical devices SAI: and SYS: respectively. It is assumed that
any site using SAIL will define SAI: as a system-wide logical
device, probably referring to PS:<SAIL>. By using SAI: instead
of <SAIL>, we allow users to redefine SAI:, for testing private
versions of the sharable segment, etc. It also means that it is
not necessary to have a separate <SAIL> directory on each mountable
structure, as would be needed if <SAIL> were used. Also, files
having the extension .SAV on Tenex are assumed to have .EXE on
Tops-20. E.g. the sharable segment is gotten from SAI:T-6-SAISG8.EXE,
and the loader from SYS:LINK.EXE.
On Tops-20, the default line-editors for TTY input use the RDTTY
JSYS. RDTTY will be used whether the user specifies the "Tenex-style"
or "Tops-10 style" line editor, since RDTTY is sort of a merging of
features of both. The RDTTY JSYS implements the standard Tops-20
editing characters, for which we refer you to DEC's Tops-20
In the compiler, when an error is detected you are asked to type
a character indicating what to do. The E and T responses are
now implemented for Tops-20. (They are implemented only at
Sumex and IMSSS on Tenex.) Both of these responses call your
default editor, i.e. whatever is the value of the logical
device EDIT:. (Implementors are warned that DEC will probably
adopt this feature in some future monitor release, but use
a different name for the logical device.) Most sites will define
EDIT: as their most popular editor by a system-wide logical
definition. Users can supercede that defintion with their own
if they desire. SAIL can link to any editor that can be called
by the EXEC's EDIT command. This includes SOS, TVEDIT, EMACS,
and various versions of DEC's EDIT. A fake EDIT command
("EDIT filename") is put in the RSCAN buffer, and the editor is
started at the normal start address. For editors that want a
smoother interface, certain extra data is sent to the editor
via the PRARG jsys. Editors that do not know about this will
still edit the proper file, but will not know here in the file
to go. The format of the data block passed via PRARG was chosen
so that Tops-10 programs running under the emulator can retrieve
the 4 words of data by openning TMPCOR file 'EDI'. Tops-20
programs should check the word with 'EDI' in the left half to
be sure that the argument is meant for them.
1 ;number of arguments
2 ;relative address of 1st
ascii /line/ ;line number for SOS, etc.
line ;line number for non-SOS
character ;char on line
In some cases, user programs may wish to determine which operating
system they are running on. At startup time, the SAIL runtimes
execute a special GETTAB UUO that is supposed to return a code
indicating the operating system. This GETTAB is implemented on
all known operating systems that use PDP-10 hardware, except for
the Stanford A.I. Lab monitor, and possible certain out-of-date
Tenex systems. It is even implemented on ITS! The value returned
by this UUO is put in a variable $OS, which may be declared
as an EXTERNAL INTEGER by your program so you can look at it.
The codes are returned in bits 18-23:
1 - Tops-10
2 - ITS
3 - Tenex
4 - Tops-20
5 - Stanford A.I. Lab monitor
The other bits in this word are reserved for indicating subversions
of these various operating systems. We believe that the code has
been set up so that even operating systems that do not implement
the GETTAB will end up with the proper value, if you use
the version of the runtimes intended for them.
For the Tenex SAIL system only, there is another EXTERNAL INTEGER
variable, $OSTYP. This is set to 0 for Tenex and 2 for anything
else. This is the variable actually used by the runtimes to
determine whether to execute Tenex or Tops-20 code.
.ss|New runtimes for Tops-20|
In an effort to support programming on Tops-20, the following
runtimes have been added. Note that they will result in errors
if executed on Tenex systems, since they call JSYS's that do not
exist on Tenex. No attempt is made to prevent these errors, on
the theory that some Tenex system might decide to implement one
of them. So we recommend that these be used only in programs
that test $OS or $OSTYP and provide special code for both
Tenex and Tops-20.
SUCCESS ←← ACCES("DIRECTORY","PASSWORD",FLAGS,JOBNO)
This runtime calls the ACCES JSYS. It gives the specified job
access to the requested directory. Only the first argument
is required. Defaults are
Jobno\the current job.
Note that because of the implementation of defaults in SAIL, it
is not possible to specify a jobno of 0. However on Tops-20
job 0 is part of the operating system, so this does not seem to
be a serious limitation. (A SAIL program running as part of
job 0 would of course be able to specify the current job.)
'400#000#000#000\Equivalent to CONNECT monitor command
'200#000#000#000\Equivalent to ACCESS monitor command
'100#000#000#000\Equivalent to END-ACCESS monitor command
JOBNO is the number of the job, or -1 for current job.
(Requires privileges to set for other jobs).
On success, returns true; on failure, false, with TENEX
error code in !SKIP!.
DIRNUM ←← RCDIR(@"DIRECTORY",@DIRNO,@FLAGS)
This procedure calls the RCDIR JSYS.
A 36-bit directory number is returned as the value of the call and
also put in the reference parameter DIRNO (useful for stepping
If recognition is not specifically disabled, the reference string
DIRECTORY is updated.
Input FLAGS are:
'10#000#000\Allow partial recognition
#'4#000#000\Step to next directory in group (Previous
directory number is in DIRNO, and the "wildcard" bit must be set)
#'2#000#000\Allow wildcards in "DIRECTORY"
#'1#000#000\Match given string exactly (suppresses recognition)
The flags returned by the monitor are put in the reference
On failure, zero is returned with !SKIP! set to:
1\string does not match
2\string is ambiguous
3\no more in this group (while stepping)
On error, zero is returned with !SKIP! set to the TENEX
error code. (Note the subtle difference here: an error involves
an illegal format for a directory name, or some other invalid
argument. Such an error generates a Tenex error code of the
usual sort. A directory name which is valid, but just does
not happen to exist on this system does not generate a Tenex
error code, but is simply called a failure.)
USRNUM ←← RCUSR(@"USER",@USRNO,@FLAGS)
This translates a user name string to its corresponding
user number in the identical manner as RCDIR does for
directory strings. See RCDIR for details. Note that a
valid directory name always has < > around it, while a
user name does not.
SUCCESS ←← RSCAN(FUNCTION,STRING)
This procedure calls the RSCAN JSYS.
This allows the program to replace the string
in the rescan buffer, set input to come from that
buffer, or determine how many characters are still to be read
from that buffer.
Both arguments are optional. If omitted, the values used are
The values of FUNCTION mean:
0\Set input to come from the rescan buffer.
1\Return number of characters still to be read
from that buffer.
The value returned by the call is the number of characters
in the buffer for FUNCTION 0, and number of characters
left for FUNCTION 1.
If STRING is non-null, FUNCTION is ignored, the string
is placed in the rescan buffer, and the value returned by
the call will be true on success.
On failure or error, zero is returned and !SKIP! is set to
the TENEX error code.
errmessage ← ERSTRING(ERRNO, FORKNO)
This is similar to ERSTR. It will get the error message
corresponding to the given error number on the given fork.
However instead of printing it on the terminal, as ERSTR does,
it returns it as a string. !SKIP! will be set if the error
number is illegal. In that case no guarantee is made about
what is returned. ERRNO and FORKNO are both optional. The
default values are the most recent error (-1) for ERRNO, and
the current fork for FORKNO.
.ss|Changes to existing procedures to support Tops-20|
CLOSF now takes an optional extra argument, CLOSF(chan,bits).
This argument is an integer. Its left half will be put in the
left half of AC1 in the CLOSF jsys. The most useful option
is bit '4#000#000#000. This specifies that the file is to be
aborted, rather than closed normally. If the file is on disk,
it will not appear (unless it has been closed and reopened).
If it is on tape, the 2 EOF's will not be written.
Note that the SAIL runtimes have a strange habit of closing and
reopenning files, to try to get read/write mode. If you want to
be able to abort creation of a file, you will have to open it
"RW". If you do, then CLOSF with bit '4000000000 set will cause
it not to show up on disk at all. If you had specified only "W",
SAIL would have created the file, closed it, and reopened it, in
order to get it in "RW" mode, which the runtimes prefer to use.
Then it would not be possible to abort creation of the file by
doing an abort close, since it has already been closed normally.
Note that CLOSF always sets bit '400#000#000#000 (do not release
the jfn). To release the jfn, you can do a RLJFN after the CLOSF.
If the extra argument is omitted, no bits other than '400#000#000#000
DELF now takes an extra optional argument, DELF(chan,bits). This
argument specifies bits to go in the left half of AC1 in the
DELF jsys. The most useful bit is '200#000#000#000. Setting this
bit will cause the file to be expunged as well as deleted. Note
that DELF always sets bit '400#000#000#000 (do not release
the jfn). To release the jfn, you can do a RLJFN after the DELF.
If the extra argument is omitted, no bits other than '400#000#000#000
IDTIM now takes an extra optional argument, IDTIM(datime,bits).
This argument specifies certain details of the format expected
by the jsys. The default value if this argument is omitted is 0.
Openfile uses a somewhat obscure algorithm to determine the setting
of bit '400#000#000#000 in the GTJFN jsys. This is the bit that
determines whether an existing version will be used if there is
one, or whether the next higher version number will be used.
If you specify "O" or "N", this bit is never used, since it is
meaningless in that case. Otherwise, the next higher version is
always used when "W" is set, and the highest existing version
when "W" is not set. (The one exception is that "W" with "A" will
still use an existing version, for obvious reasons.) This causes
problems for people who wish to open an existing file for "RW"
access, since "RW" will cause the bit to be set that moves one to
a new version. "ORW" will cause you to update an existing version,
but it will then give an error if there is no existing version.
In many cases you want to use the existing version if there is one,
else create a new file. This corresponds to setting no special
bits in the GTJFN at all.
To allow this useful case, we have added an option "U" (Update)
to OPENFILE. This is like "RW", except that it does not set the
bit causing the version number to be advanced. So it will use an
existing version if there is one, else create a new file.
RUNPRG will now supply a default extension if you leave it out
in the string. This is to allow people to write programs that
will work on both Tenex and Tops-20 without changing the file
name, since the normal extensions for executable files are
different on these two systems. The default extension supplied
will be .SAV for Tenex and .EXE for Tops-20.
.require "lies" source!file;