perm filename SAIL.UPD[NEW,AIL]1 blob
sn#408226 filedate 1979-01-08 generic text, type T, neo UTF8
STANFORD ARTIFICIAL INTELLIGENCE LABORATORY NOVEMBER 1975
SAIL USER MANUAL
UPDATE
James R. Low
John F. Reiser
Hanan J. Samet
Robert L. Smith
Robert F. Sproull
Daniel C. Swinehart
Russell H. Taylor
Kurt A. VanLehn
ABSTRACT
This document describes recent changes to the SAIL language since the
"new" manual (AIM-204) was published in July 1973. It reflects the
various new features implemented as of 20 November, 1975 for SAIL
version 18 and corrects a number of minor errors in the earlier
manual.
SAIL Addendum 1 TABLE OF CONTENTS
T A B L E O F C O N T E N T S
SECTION PAGE
1 INTRODUCTION 1
2 NUMERICAL ROUTINES 2
1 OVERFLOW 3
2 ENTRY POINTS 4
3 OVERFLOW IMPLEMENTATION 4
3 NEW PROCESS FEATURES 5
1 SPROUT APPLY 5
2 SPROUT!DEFAULTS 5
3 SUSPEND 7
4 FAIL AND SUCCEED 7
4 ERROR HANDLING 8
1 ERROR MODES 8
2 ALTMODE RESPONSE 8
3 USER ERROR PROCEDURES 8
5 INEXHAUSTIBLE STRING SPACE 10
SAIL Addendum 1 TABLE OF CONTENTS
6 RECORD STRUCTURES 12
1 INTRODUCTORY REMARKS 12
2 RECORD CLASS DECLARATIONS 12
3 RECORD POINTER DECLARATIONS 13
4 ALLOCATION 14
5 SUBFIELDS 14
6 GARBAGE COLLECTION 16
7 INTERNAL REPRESENTATIONS 16
8 HANDLER PROCEDURES 18
9 STRING SUBFIELDS 20
10 MORE ABOUT GARBAGE COLLECTION 20
7 PRINT 22
1 Default Formats for PRINT 22
2 SETPRINT and GETPRINT 23
3 Simple Uses of PRINT and SETPRINT 25
4 CPRINT -- Printing to a Channel 26
5 Design of PRINT 27
6 CAVEATS of PRINT and CPRINT 27
7 Hooks into the PRINT System 28
8 SAVE/CONTINUE 30
SAIL Addendum 1 TABLE OF CONTENTS
9 MISCELLANEOUS NEW FEATURES 33
1 NEW MTAPE OPTIONS 33
2 INITIALIZATION PHASES 33
3 CHNCDB 34
4 OVERFLOW 34
5 ARRCLR 34
6 SETPL 35
7 EVALREDEFINE 35
8 CVPS 35
9 EXPRESSIONS IN REQUIRES 35
10 RELEASE 36
11 TTYUP 36
12 BREAKSET MODES "K" AND "F" 36
13 INOUT 37
14 GETSTS & SETSTS 37
15 CHANGES TO "OPEN" ERROR HANDLING 37
16 ASH 38
17 ARG!LIST 38
18 CLOSE 38
19 TYPEIT 39
20 COMPARISON OF .REL FILES 39
21 SCAN Optimizations 39
22 BREAK TABLES 39
23 CV6STR 40
24 TENEX RUNTIMES 41
25 CVASTR 41
26 NEW SWITCHES 41
27 COMPILER!SWITCHES 42
28 COMPILER!BANNER 42
29 EDFILE 43
30 INIACS 43
31 GOGTAB 43
32 ARERR 44
10 MINOR CORRECTIONS TO AIM-204 45
SAIL Addendum 1 INTRODUCTION
SECTION 1
INTRODUCTION
The following short manual describes the changes that have happened
to SAIL since the publishing of the Manual in July 1973. It
accurately reflects the state of SAIL, version 18, which was last
modified on November 23, 1975. The reader should be warned that many
of these new features were designed for veteran SAIL hackers.
The reader may also want to refer to the following documents, which
are usually kept updated.
MACLIE.WRU[DOC,AIL] A summary of commonly made errors when using
macros and what to do about them.
TUTOR.DOC[DOC,AIL] In introduction to LEAP.
LEAP.WRU[DOC,AIL] A detailed description of the runtime environment
of LEAP for the hardy few who want to interface
to LEAP in assembly language.
SAIL.DOC[AIM,DOC] The July '73 manual (AIM-204) in LPT form.
Warning: this version is the Stanford character
set. It is also almost 300 pages long. You can
get a 120 page version, set in two columns of
nice type from the National Technical Information
Service, Springfield, Virginia 22151.
LIES[DOC,AIL] This file contains the know mistakes in the
Manual. Soon it will also contain the known
mistakes in this document.
1
SAIL Addendum 1 NUMERICAL ROUTINES
SECTION 2
NUMERICAL ROUTINES
A collection of numerical routines has been added to SAIL. These are
pre-declared in the compiler, and are loaded from the standard SAIL
library. The functions are quite standard; following are the
equivalent definitions:
1. The standard trigonometric functions. ASIN, ACOS, ATAN and ATAN2
return results in radians. The ATAN2 call takes arc-tangent of
the quotient of its arguments; in this way, it correctly
preserves sign information.
REAL PROCEDURE SIN (REAL RADIANS);
REAL PROCEDURE COS (REAL RADIANS);
REAL PROCEDURE SIND (REAL DEGREES);
REAL PROCEDURE COSD (REAL DEGREES);
REAL PROCEDURE ASIN (REAL ARGUMENT);
REAL PROCEDURE ACOS (REAL ARGUMENT);
REAL PROCEDURE ATAN (REAL ARGUMENT);
REAL PROCEDURE ATAN2 (REAL NUMERATOR,DENOMINATOR);
2. The hyperbolic trigonometric functions.
REAL PROCEDURE SINH (REAL ARGUMENT);
REAL PROCEDURE COSH (REAL ARGUMENT);
REAL PROCEDURE TANH (REAL ARGUMENT);
3. The square-root function:
REAL PROCEDURE SQRT (REAL ARGUMENT);
4. A pseudo-random number generator. The argument specifies a new
value for the seed (If the argument is 0, the old seed value is
used. Thus to get differing random numbers, this argument should
be zero.) Results are normalized to lie in the range [0,1].
REAL PROCEDURE RAN (INTEGER SEED);
2
SAIL Addendum 1 NUMERICAL ROUTINES
5. Logarithm and exponentiation functions. These functions are the
same ones used by the SAIL exponentiation operator. The base is
e (2.71828182845904). The logarithm to the base 10 of e is
.4342944819.
REAL PROCEDURE LOG (REAL ARGUMENT);
REAL PROCEDURE EXP (REAL ARGUMENT);
These functions may occasionally be asked to compute numbers that lie
outside the range of legal floating-point numbers on the PDP-10. In
these cases, the routines issue sprightly error messages that are
continuable.
2.1 - OVERFLOW
In order to better perform their tasks, these routines enable the
system interrupt facility for floating-point overflow and underflow
errors. If an underflow is detected, the results are set to 0 (a
feat not done by the PDP-10 hardware, alas). Be aware that such
underflow fixups will be done to every underflow that occurs in your
program. For further implementation details, see the section below.
If you would like to be informed of any numerical exceptions, you can
call the runtime:
TRIGINI ( LOCATION(simple-procedure-name) );
Every floating-point exception that is not expected by the interrupt
handler (the numerical routines use a special convention to indicate
that arithmetic exception was expected) will cause the specified
simple procedure to be called. This procedure may look around the
world as described in the Manual for 'export' interrupt handlers,
page 79. If no TRIGINI call is done, the interrupt routine will
simply dismiss unexpected floating-point interrupts.
3
SAIL Addendum 1 NUMERICAL ROUTINES
2.2 - ENTRY POINTS
In order to avoid confusion (by the loader) with older trig packages,
the entry points of the SAIL arithmetic routines all have a "$"
appended to the end. Thus, SIN has the entry point SIN$, etc.
WARNING: If a program plans to use the SAIL intrinsic numerical
routines, it should NOT include external declarations to them, since
this will probably cause the FORTRAN library routines to be loaded.
2.3 - OVERFLOW IMPLEMENTATION
This section may be skipped by all but those interested in
interfacing number crunching assembly code with SAIL routines where
overflow and underflow are expected to be a problem.
The SAIL arithmetic interrupt routines first check to see if the
interrupt was caused by floating exponent underflow. If it was, then
the result is set to zero, be it in an accumulator, memory, or both.
Then if the arithmetic instruction that causes the interrupt if
followed by a JFCL, the AC field of the JFCL is compared with the PC
flag bits to see if the JFCL tests for any of the flags that are on.
If it does, those flags are cleared and the program proceeds at the
effective address of the JFCL (i.e., the hardware is simulated in
that case). Note that no instructions may intervene between the
interrupt-causing instruction and the JFCL or the interrupt routines
will not see the JFCL. They only look one instruction ahead. Note
that in any case, floating exponent underflow always causes the
result to be set to zero. There is no way to disable that effect.
4
SAIL Addendum 1 NEW PROCESS FEATURES
SECTION 3
NEW PROCESS FEATURES
3.1 - SPROUT APPLY
The <procedure call> in a SPROUT statement may be an APPLY construct.
In this case SPROUT will do the "right" thing about setting up the
static link for the APPLY. That is, "up-level" references by the
process will be made to the same variable instances that would be
used if the APPLY did not occur in a SPROUT statement. (See page 77
of the manual.)
However, there is a glitch. The sprout mechanism is not yet smart
enough to find out the block of the declaration of the procedure used
to define the procedure item. It would be nice if it did, since then
it could warn the user when that block was exited and yet the process
was still alive, and thus potentially able to refer to deallocated
arrays and etc. What the sprout does instead is assume the procedure
was declared in the outer block. This may be fixed eventually, but
in the meantime some extra care should be taken when using apply
in sprouts to avoid exiting a block with dependents.
Similarly, be warned that the "DEPENDENTS (<blockid>)" construct
may not give the "right" result for sprout applies. Page 68 of
the Manual contains the description of this protection mechanism for
non-APPLY Sprouts.
3.2 - SPROUT!DEFAULTS
SAIL now provides a mechanism by which the user may specify the
"default" options to be used when individual procedures are sprouted.
5
SAIL Addendum 1 NEW PROCESS FEATURES
Syntax:
PROCEDURE <procid> ...
BEGIN
<some declarations>;
SPROUT!DEFAULTS <integer constant>;
<perhaps some more declarations>;
:
:
<statements>
:
END;
In other words, SPROUT!DEFAULTS is a declaration.
Semantics:
If one of the "allocation" fields of the options word passed to the
SPROUT routine -- i.e. QUANTUM,STRINGSTACK,PSTACK, or PRIORITY -- is
zero, then SPROUT will look at the corresponding field of the
specified <integer constant> for the procedure being sprouted. If the
field is non-zero, then that value will be used; otherwise the
current "system" default will be used.
NOTE: SPROUT!DEFAULTS only applies to "allocations", i.e. the
process status control bits (e.g. SUSPME) are not affected.
Example:
RECURSIVE PROCEDURE FOO;
BEGIN
SPROUT!DEFAULTS STRINGSTACK(10);
INTEGER XXX;
:
:
END;
:
SPROUT(P1,FOO,STRINGSTACK(3));
SPROUT(P2,FOO);
COMMENT P1 will have a string stack of 3*32 words.
P2 will have a string stack of 10*32 words;
6
SAIL Addendum 1 NEW PROCESS FEATURES
3.3 - SUSPEND
SUSPEND now behaves like RESUME in that it returns an item.
itm ← SUSPEND(<process item>)
Frequently, one is suspending some other process than the one that is
executing the SUSPEND statement. In this case, the item returned is
ANY. However, in cases like:
X ← SUSPEND(MYPROC);
where the process suspends itself, it might happen that this process
is made running by a RESUME from another process. If so, then X
receives the <return item> that was an argument to the RESUME.
3.4 - FAIL AND SUCCEED
FAIL and SUCCEED now behave like RESUME and SUSPEND in that they also
return an item. The item returned is ANY unless the Matching
Procedure containing the FAIL or SUCCEED was (1) sprouted as a
process, and (2) made running by a RESUME construct. In the latter
case, the item returned is the <return item> that was an argument to
the RESUME. [Note that the only case in which a Matching Procedure
can be reactivated at a FAIL is by being RESUMEd.]
7
SAIL Addendum 1 ERROR HANDLING
SECTION 4
ERROR HANDLING
4.1 - ERROR MODES
SAIL's error handler has at long last been modified to do what is
claimed it will do in Section 20 of the manual (pgs 95 - 97), and in
the description of USERERR (pg 42). In brief, it allows one to have
error messages automatically sent to a "log" file while one is
compiling, and to use USERERR as a trace statement.
The description given in the manual differs from reality in two ways:
"Keep" mode has not been implemented (the error handler will flush
all type-ahead except a <lf>); all of the other modes ("Quiet",
"Logging", and "Numbers") are implemented ONLY IN THE COMPILER.
However, one can get the effect of error modes at runtime by using a
brand new feature called user error procedures.
4.2 - ALTMODE RESPONSE
After an "E" or "T" response to the error handler, an altmode will
return to the question loop; i.e., you may change your mind if you do
not wish to edit. Normal monitor line editing of the file name is
allowed.
4.3 - USER ERROR PROCEDURES
A user error procedure is a user procedure that is run before or
instead of the SAIL error handler everytime an error occurs at
runtime. This includes all array errors, IO errors, Leapish errors
and all USERERRs. It does not include system errors, such as Ill Mem
Ref or Ill UUO.
8
SAIL Addendum 1 ERROR HANDLING
The procedure one uses for a user error procedure must be of the
following type:
SIMPLE INTEGER PROCEDURE proc (INTEGER loc; STRING msg, rsp);
Only the names proc, loc, msg, and rsp may vary from the example
above, except that one may declare the procedure INTERNAL if one
wishes to use it across files.
Whenever the external integer !ERRP! is loaded with LOCATION(proc),
the error handler will call proc before it does anything else. It
will set loc to the core location of the call to the error handler.
Msg will be the message that it would have printed. Rsp will be
non-NULL only if the error was from a USERERR which had response
string argument. Proc can do anything that a simple procedure can
do. When it exits, it should return an integer which tells the
error handler if it should do anything more. If the integer is 0,
the error handler will (1) print the message, (2) print the
location, and (3) query the tty and dispatch on the response
character (i.e ask for a <cr>, <lf>, etc.). If the right half of the
integer is non-zero, it is taken as the ascii for a character to
dispatch upon. The left half may have two bits to control printing.
If bit 17 in the integer is on, message printing is inhibited. If
bit 16 is on, then the location printing is inhibited. For example,
"X"+(1 LSH 18) will cause the location to be printed and the program
exited. "C"+(3 LSH 18) will cause the error handler to continue
without printing anything.
Note that simple procedures can not do a non-local GOTO. However,
the effect of a non-local GOTO can be achieved in a user error
procedure by loading the external integer !ERRJ! with the LOCATION of
a label. The label should be a on a call to a non-simple procedure
which does the desired GOTO. The error handler clears !ERRJ! before
calling the procedure in !ERRP!. If !ERRJ! is non-zero when the
user procedure returns, and continuing was specified, then the error
handler's exit consists of a simple transfer to that location.
Note that for this simple transfer to work properly, the place where
the error occurred (or the call to USERERR) must be in the same
static (lexical) scope as the label whose LOCATION is in !ERRJ!. If
this is really important to you, see a SAIL hacker.
WARNING! Handling errors from strange places like the string garbage
collector and the core management routines will get you into deep
trouble.
9
SAIL Addendum 1 INEXHAUSTIBLE STRING SPACE
SECTION 5
INEXHAUSTIBLE STRING SPACE
The string garbage collector has been modified to expand string space
(using discontiguous blocks) whenever necessary to satisfy the demand
for places to put strings. To take advantage of this feature, one
need not change his programs.
Here are some points which might be of interest, however:
1) Although we are going to provide user control over all size
parameters eventually, currently only the initial string
space size is settable by the user, either via REQUIRE or
the ALLOC sequence, as before. The size of each string space
increment will be the same as the original size, which need not
be monstrous any more unless you know that all runs of your
program will need a monstrous string space anyhow. The
threshold (see below) for expanding will be set at 1/8 the
string space size (increment size).
2) One can, in his program, modify these values independently, if he
is willing to use the USERCON function, and to follow this
format:
USER TABLE ENTRY NAME VALUE
STINCR lh: number of chars. in increment
rh: number of words in increment + 4
STREQD lh: number of chars. in threshold
rh: number of words in threshold.
3) The threshold. After garbage collection, let us say that M-1
discontiguous string spaces are full, and the M'th has n
free characters in it (available for new strings). The garbage
collector was called because some routine wanted to create a
string R characters long, and there were not that many available
(free). After garbage collection, the new algorithm
requires that N be greater than R+LH(STREQD). If it is not,
expansion takes place (to M+1 spaces), to satisfy this
requirement. In other words, if STREQD is 1/8 the size of the
current space, that space will not be allowed to become more
10
SAIL Addendum 1 INEXHAUSTIBLE STRING SPACE
than about 7/8 full. This helps avoid frequent, nearly
useless calls on the garbage collector when space is about gone.
All but the current space are allowed to become as full as
possible, however.
4) New statistics are maintained by the garbage collector.
Soon there will be a built-in routine you can use to print
them. For now, you may look at them using USERCON, although this
document does not say what they are. In order to
activate timing of the garbage collector (slows it down), set
SGCTIME in the user table to -1.
5) Future plans. The new structure not only allows expansion of
string space, it also will allow for partial garbage
collections (no visible benefits except increased speed,
since a partial collection will be almost as effective as a
complete one, and much faster), and the ability to move
string space blocks, in order to compact memory. Push on your
local representative to get these things done.
11
SAIL Addendum 1 RECORD STRUCTURES
SECTION 6
RECORD STRUCTURES
6.1 - INTRODUCTORY REMARKS
Record structures are a fairly recent addition to SAIL. Essentially,
they provide a means by which a number of closely related variables
may be allocated and manipulated as a unit, without the overhead or
limitations associated with using parallel arrays and without the
restriction that the variables all be of the same data type. In the
current implementation, each record is an instance of a user-defined
"record class", which serves as a template describing the various
subfields of the record. Internally, records are small blocks of
storage which contain space for the various subfields and a
pointer to a class descriptor record. Subfields are allocated
one per word and are accessed by constant indexing off the record
pointer. Deallocation is performed automatically by a garbage
collector or manually through explicit calls to a deallocation
procedure.
Records were originally added to SAIL to fullfill a number of very
specific needs at Stanford, and were subsequently generalized to the
form seen here. The structures described in this section are
implemented and, so far as is known, work correctly. (They have been
used successfully by several different people to produce a number of
sizable programs). Readers are strongly urged to look at the file
RECAUX.SAI[CSP,SYS], which contains a number of useful examples and
auxilliary functions.
6.2 - RECORD CLASS DECLARATIONS
RECORD!CLASS <classid> (<subfield declarations>)
For instance,
RECORD!CLASS VECTOR (REAL X,Y,Z);
RECORD!CLASS CELL (RECORD!POINTER(ANY!CLASS) CAR,CDR);
12
SAIL Addendum 1 RECORD STRUCTURES
RECORD!CLASS TABLEAU (REAL ARRAY A,B,C;INTEGER N,M);
RECORD!CLASS FOO(LIST L;ITEMVAR A);
Generally, the <subfield declarations> have the same form as a
procedure's formal paramter list, except that the words VALUE and
REFERENCE should not be used. Each record class declaration is
compiled into a "record descriptor" which is a record of constant
record class $CLASS and is used by the runtime system for allocation,
deallocation, garbage collection, etc.
6.3 - RECORD POINTER DECLARATIONS
RECORD!POINTER(<classid list>) <id list>
RECORD!POINTER(ANY!CLASS) <id list>
For instance,
RECORD!POINTER(VECTOR) V1,V2;
RECORD!POINTER(VECTOR,TABLEAU) T1,T2;
RECORD!POINTER(ANY!CLASS) R;
At runtime, these variables contain either the value NULL!RECORD
(internally, zero) or else a pointer to a record. The <classid list>
is used to make a compile-time check on assignments and subfield
references. The pseudo-class ANY!CLASS matches all classes, and
effectively disables this compile-time check. For instance:
RECORD!POINTER(FOO,BAR) FB1,FB2;
RECORD!POINTER(FOO) FB3;
RECORD!POINTER(CELL) C;
RECORD!POINTER(ANY!CLASS) RP;
:
COMMENT the following are all ok syntactically;
C←NEW!RECORD(CELL);
RP←C;
FB2←NEW!RECORD(FOO);
FB1←FB3;
FB3←RP; COMMENT Note that this is most likely a runtime bug
Since RP will contain a cell record. SAIL
won't catch it, however;
CELL:CAR[RP]←FB1;
CELL:CAR[RP]←FB1;
13
SAIL Addendum 1 RECORD STRUCTURES
COMMENT The compiler will complain about these: ;
FB1←C;
FB3←NEW!RECORD(CELL);
RP←CELL:CAR[FB3];
NO runtime class information is kept with the variable, and no
runtime class checks are made on record assignment or subfield
access. Record pointer variables are allocated quantities, and
should not appear inside SIMPLE procedures. They resemble lists in
that they are not given any special value upon block entry and they
are set to a null value (NULL!RECORD) when the block in which they
are declared is exited. (This is so that any records referred to
only in that block can be reclaimed by the garbage collector.)
6.4 - ALLOCATION
Records are allocated by means of the construct
NEW!RECORD(<classid>)
which returns a new record of the specified class. All subfields of
the new record are set to the "null" or "zero" value for that
subfield -- i.e., real & integer subfields will be set to 0, itemvar
subfields will be set to ANY, lists will be set to PHI, etc. Again,
note that entry into a block with local record pointer variables does
NOT cause records to be allocated and assigned to those variables.
6.5 - SUBFIELDS
Record subfields are referenced by means of the construct
<classid>:<fieldid>[<record pointer expression>]
and may be used wherever an array element may be used. For example
RECORD!POINTER(VECTOR) V;
RECORD!POINTER(CELL) C;
RECORD!POINTER(FOO) F;
:
14
SAIL Addendum 1 RECORD STRUCTURES
VECTOR:X[V]←VECTOR:Y[V];
CELL:CAR[C]←NEW!RECORD(CELL)]←V;
VECTOR:Z[V]←VECTOR:X[CELL:CAR[C]];
SUBLIS ← FOO:L[F][1 TO 3];
:
If the <record pointer expression> gives a null record, then a
runtime error message will be generated. This is the only runtime
check that is made at present. I.e., no runtime checks are made to
verify that the <classid> in the subfield statement matches the class
of the record whose subfield is being extracted.
An array subfield may be used as an array name, as in
RECORD!POINTER(TABLEAU) T;
:
TABLEAU:A[T][I,J] ← 2.5;
provided that you have stored a valid array descriptor into the
subfield. Unfortunately, SAIL does not provide any clean way to do
this. One unclean way is
INTEGER PROCEDURE NEWARY(INTEGER LB,UB);
BEGIN
INTEGER ARRAY A[LB:UB];
INTEGER AA;
AA←MEMORY[LOCATION(A)];
MEMORY[LOCATION(A)]←0;
COMMENT defeats deallocation;
RETURN(AA);
END;
:
RECORD!CLASS FUBAR(INTEGER ARRAY A);
RECORD!POINTER(FUBAR) FB;
:
MEMORY[LOCATION(FUBAR:A[FB])]←NEWARY(1,100);
(Warning: the above "advice" is primarily intended for hackers; we
make no promisses that it will never get you into trouble, although
this particular trick is unlikely to be made obsolete in the
forseeable future).
15
SAIL Addendum 1 RECORD STRUCTURES
6.6 - GARBAGE COLLECTION
The SAIL record service routines allocate records as "small blocks"
from larger "buffers" of free storage obtained from the normal SAIL
free storage system. (The format of these records will be discussed
in a later section). From time to time, a garbage collector is
called to reclaim the storage for records which are no longer
accessible by the user's program (i.e., are not pointed to by any
variables, aren't pointed to by any accessible records, etc.). The
garbage collector may be called explicitly from SAIL programs as
external procedure $RECGC, and automatic invocation of the garbage
collection may be inhibited by setting user table entry RGCOFF to
TRUE. (In this case, SAIL will just keep allocating more space, with
nothing being reclaimed until RGCOFF is set back to FALSE or $RECGC
is called explicitly). In addition, SAIL provides a number of
"hooks" that allow a user to control the automatic invocation of the
garbage collector. These are discussed in a subsequent section.
6.7 - INTERNAL REPRESENTATIONS
Each record has the following form:
-1: <pointers to ring of all records of class>
0: <garbage collector pointer>,,<pntr to class descriptor>
+1: <first subfield>
:
+n: <last subfield>
Record pointer variables point at word 0 of such records.
The predefined record class $CLASS is used to define all record
classes, and is itself a record of class $CLASS.
RECORD!CLASS $CLASS (INTEGER RECRNG,HNDLER,RECSIZ;
INTEGER ARRAY TYPARR;
STRING ARRAY TXTARR);
RECRNG is a ring (bidirectional linked list) of all records of the
particular class.
HNDLER is a pointer to the handler procedure for the class (default
$REC$).
RECSIZ is the number of subfields in the class.
16
SAIL Addendum 1 RECORD STRUCTURES
TYPARR is an array of subfield descriptors for each subfield of the
class.
TXTARR is an array of subfield names for the class.
The normal value for the handler procedure is $REC$, which is the
standard procedure for such functions as allocation, deallocation,
etc.
TYPARR and TXTARR are indexed [0:RECSIZ]. TXTARR[0] is the name of
the record class. TYPARR[0] contains type bits for the record class.
Example:
RECORD!CLASS FOO(LIST L;ITEMVAR A);
The record class descriptor for FOO would contain:
FOO-1: <pointers for ring of all records of $CLASS>
FOO: <pointer to $CLASS>
FOO+1: <pointers for ring of all records of class FOO
initialized to <FOO+2,,FOO+2> >.
FOO+2: <pointer to handler procedure: $REC$>
FOO+3: 2
FOO+4 <pointer to TYPARR>
FOO+5: <pointer to TXTARR>
The subfields of FOO will be:
$CLASS:FOO[RECRNG] = <initialized to null ring,
i.e., xwd(loc(FOO)+2,loc(FOO)+22)>
$CLASS:FOO[HNDLER] = $REC$
$CLASS:FOO[RECSIZ] = 2
$CLASS:FOO[TXTARR] [0] = "FOO"
$CLASS:FOO[TXYARR] [1] = "L"
$CLASS:FOO[TXTARR] [2] = "A"
$CLASS:FOO[TYPARR] [0] = <magic bits for garbage collector>
$CLASS:FOO[TYPARR] [1] = <descriptor for LIST>
$CLASS:FOO[TYPARR] [2] = <descriptor for ITEMVAR>
17
SAIL Addendum 1 RECORD STRUCTURES
6.8 - HANDLER PROCEDURES
SAIL uses a single runtime routine $RECFN(OP,REC) to handle such
system functions as record allocation, deallocation, etc. For
instance, the construct
r ← NEW!RECORD(foo)
is compiled as
PUSH P,[1]
PUSH P,[foo]
PUSHJ P,$RECFN
MOVEM 1,r
$RECFN performs a certain amount of type checking and then jumps to
the appropriate handler procedure for the class being operated on.
The normal value for this handler procedure is $REC$. It is possible
for a user to substitute his own handler procedure for a given class
of records by including the procedure name in brackets after the
record class declaration:
RECORD!CLASS <id> (<subfields>) [<handler>]
This handler must have the form
RECORD!POINTER(ANY!CLASS) PROCEDURE <procid>
(INTEGER OP;RECORD!POINTER(ANY!CLASS) R);
Where OP will be a small integer saying what is to be done. The
current assignments for OP are:
OP value meaning
0 invalid
1 allocate a new record of record class R
2 not used
3 not used
4 Mark all subfields of record R
5 Delete all space for record R
Macro definitions for these functions may be found in the file
SYS:RECORD.DEF, which also includes EXTERNAL declarations for $CLASS,
$REC$, and $RECFN.
$REC$(1,R) allocates a record of the record class specified by R,
18
SAIL Addendum 1 RECORD STRUCTURES
which must be a record of class $CLASS. All subfields (except
string) are initialized to zero. String subfields are initialized to
a pointer to a string descriptor with length zero (null string).
$REC$(4,R) is used by the garbage collector to mark all record
subfields of R.
$REC$(5,R) deallocates record R, and deallocates all string and array
subfields of record R. Care must be exercised to prevent multiple
pointers to string and array subfields, ie. DO NOT store the location
of an array in subfields of two different records unless extreme
caution is taken to handle deletion. This can be accomplished
through user handler procedures which zero array subfields (without
actually deleting the arrays) prior to the call on $REC$(5,R).
NOTE: When a user wishes to supply his own handler procedure, he
must be careful to furnish all the necessary functions. One good way
to do this is to test for those OPs that he wishes to handle and then
call $REC$ for all the rest. Also, if $REC$ was used to allocate
space for the record then it should also be used to release the
space. These points are illustrated by the following example:
RECORD!CLASS FOO(ITEMVAR IV)[FOOH];
RECORD!POINTER(ANY!CLASS) PROCEDURE FOOH(INTEGER OP;
RECORD!POINTER(ANY!CLASS) R);
BEGIN
OUTSTR("CALLING FOOH. OP = "&CVS(OP));
IF OP = 1 THEN
BEGIN
RECORD!POINTER(FOO) F;
F←$REC$(1,R);
FOO:IV[F]←NEW;
RETURN(F);
END
ELSE IF OP = 5 THEN
BEGIN
DELETE(FOO:IV[R]);
END;
RETURN($REC$(OP,R));
END;
19
SAIL Addendum 1 RECORD STRUCTURES
6.9 - STRING SUBFIELDS
String subfields presented an implementation difficulty due to the
fact that string discriptors require 2 words, but record subfields
are exactly one word. This problem was solved by making string
subfields contain a pointer to the descriptor for the string (like
REFERENCE STRING formal parameters).
When a record with string subfields is allocated by a call to
NEW!RECORD, the string descriptor blocks (2 words each) are allocated
from a linked list of free string descriptors. Likewise, when a
record is deallocated either explicitly or by the garbage collector,
the string subfield descriptors are released to the free list. The
free list is automatically expanded when exhausted.
6.10 - MORE ABOUT GARBAGE COLLECTION
The information used by the system to decide when to call $RECGC on
its own is accessible through global array, $SPCAR. In general,
$SPCAR[n] points at a "descriptor block" used to control the
allocation of small blocks of n words. This descriptor includes the
following fields:
BLKSIZ -- number of words per block in this "space"
TRIGGER -- a counter used to control when to garbage collect
TGRMIN -- described below.
TUNUSED -- number of unused blocks on the "free list"
TINUSE -- total number of blocks "in use" for this space.
CULPRIT -- the number of times this space has caused collection
The appropriate macro definitions for access of these fields may be
found in the source file "SYS:RECORD.DEF". As one might expect, the
decision to invoke the garbage collector is made as part of the
block allocation procedure, which works (roughly) as follows:
INTEGER spc,size;
size ← $CLASS:RECSIZ[classid]+2;
IF size>16 THEN
return a CORGET block;
spc ← $SPCAR[size];
L1: IF (MEMORY[spc+TRIGGER]←MEMORY[spc+TRIGGER]-1) < 0 THEN
BEGIN
IF NOT MEMORY[GOGTAB+RGCOFF] THEN
20
SAIL Addendum 1 RECORD STRUCTURES
BEGIN
MEMORY[spc+CULPRIT]←MEMORY[spc+CULPRIT]+1;
$RECGC;
GO TO L1;
END;
END;
<allocate the block from space spc, update counters, etc.>
Once $RECGC has returned all unused records to the free lists
associated with their respective block sizes, it must adjust the
trigger levels in the various spaces. To do this, it first looks to
see if the user has specified the location of an adjustment procedure
in TGRADJ(USER). If this cell is non-zero, then $RECGC calls that
procedure (which must have no parameters). Otherwise, it calls a
default system procedure that works roughly like this:
<set all TRIGGER levels to -1>
FOR size ← 3 STEP 1 UNTIL 16 DO
BEGIN
spc ← $SPCAR[size];
IF MEMORY[spc+TRIGGER]<0 THEN
BEGIN
t←MEMORY[spc+TINUSE]*RGCRHO(USER);
t←MAX(t,MEMORY[spc+TUNUSED],
MEMORY[spc+TGRMIN]);
END;
END;
RGCRHO(USER) is a real number currently initialized by the system to
0.33. Thus, users can modify the behavior or SAIL's automatic
garbage collection by some combination of:
(1) Setting RGCOFF(USER).
(2) Supplying their own procedure in TGRADJ(USER).
(3) Modifying RGCRHO(USER).
(4) Modifying the TGRMIN entries in the space descriptors.
One word of caution: User procedures that set trigger levels must be
sure not to leave the trigger level of the space that caused
collection to be set to zero. This will cause a runtime error
message to be generated.
21
SAIL Addendum 1 PRINT
SECTION 7
PRINT
SAIL has traditionally had very flexible input and output that
allowed the user essentially complete access to the time-sharing
system. Unfortunately, some of the simple and common things that the
user wants to do have been too difficult -- an example being printing
output. Typically, the user has done his own explicit conversions in
order to print the various SAIL data types. Thus, the following is
an example of the coding that has been common.
OUTSTR("The values are " & CVS(I) & " and " & CVG(X) &
" for item " & CVIS(IT,JUNK));
The PRINT statement solves this by printing out each value according
to the printing format for each argument and allowing an indefinite
number of arguments, each of which is separately printed without
concatenation. Thus, the above becomes:
PRINT("The values are ",I,X," for item ",IT);
The PRINT construction is both clearer and more efficient. The first
example has the disadvantage of doing unneeded concatenation, in the
sense that the string really doesn't have to be created; PRINT avoids
unnecessary concatenation and generally compiles less in-line code as
well.
7.1 - Default Formats for PRINT
Each syntactic type is formatted by PRINT in a standard way that will
hopefully satisfy most users. Strings are simply printed out.
Integers use the function CVS, with the current SETFORMAT positions.
Reals use CVG, also with the current SETFORMAT.
Item expressions use the print name for the item if one exists,
otherwise ITEM!xxx, where xxx is the item number. Sets and lists are
printed out showing their item components, separated by commas. Sets
22
SAIL Addendum 1 PRINT
are surrounded by single braces, and lists by double braces. PHI and
NIl are printed for the empty set and empty list respectively.
Record pointers are printed with the name of the record class,
followed by a ".", followed by the address in decimal of the record.
NULL!RECORD is printed for the empty record.
If the user wants some other format for a given syntactic type, it is
easy to make a function call as the argument to the PRINT statement.
For example,
PRINT(CVOS(I));
will print out I in octal, since CVOS is first called. (The
syntactic type of the expression CVOS(I) is of course STRING.)
There is also a way to entirely change the default formatting
function for a given syntactic type. It is described below, but is
considered to be for wizards only.
7.2 - SETPRINT and GETPRINT
The SETPRINT function sets the destination of the output from the
PRINT statement. Initially, the PRINT statement is set to output to
the user's terminal. This may be changed to be to a file or to both
the terminal and a file.
The call to SETPRINT is as follows:
SETPRINT("FILE!NAME", "MODE")
The file name is a (possibly empty) name for a file to which the
PRINTed text is to be printed. "MODE" is a single character
indicating how the PRINT statement is to function. SETPRINT may be
called many times -- it is a procedure with dynamic effects, not a
declaration.
Character Meaning
-----------------------
T the Terminal gets all PRINT output. if an
output file is open, it is to be closed. T is
the default mode in which PRINT is initialized.
F File gets PRINT output. If no file is open, one
will be opened, as described below.
23
SAIL Addendum 1 PRINT
B Both terminal and file get PRINT output. If
no file is open, it will be opened.
N Neither the file nor the terminal is getting
output. if a file is open, it will be closed.
S Suppress all output, but open a file if none
is open.
O a file is Open, but the terminal is getting
all output. opens a file if none is open.
C terminal gets output, but ignore whether or not
file is open and whether or not file is getting
output.
I terminal does not get output. ignore whether or
not a file is open and whether or not file is
getting any output.
The first 6 possibilities represent the logically possible states in
which the PRINT system can be. These are therefore the letters
returned by GETPRINT below. The "C" and "I" modes are added for
convenience, so that it is possible to terminal output on and off
without bothering to check, with GETPRINT, the current state of the
output.
The PRINT statement is initialized to mode "T" -- print to Terminal.
The user will probably find modes "T", "F" and "B" to be the most
useful. The other modes are included for completeness of the system,
and to allow the user to switch between various combinations
dynamically.
Should SETPRINT be called in such a way that a file has to be opened
-- e.g., mode "F" and no file is open -- then the first argument to
SETPRINT will be used ss the name for the output file. If the
filename argument is NULL, then the filename will be obtained from
the terminal. Thus, the statement:
SETPRINT(NULL,"F");
first types out the message
File for PRINT output *
and then waits for the user to type a filename, and then opens such a
file. On TENEX, GTJFN with filename recognition is used here. On
the DEC system and its variants, the filename is read in with the
INCHWL routine.
24
SAIL Addendum 1 PRINT
The file opened by SETPRINT will be closed when the program
terminates by falling through the bottom. It will also be closed if
the user calls SETPRINT with some mode that closes the file -- e.g.,
"T" will close an output file if one is open.
To determine the current mode of the PRINT system, the user can call
GETPRINT, which returns a letter indicating which of the modes is
currently set, using the same coding as SETPRINT above. Thus, the
call is
"MODE" ← GETPRINT;
SETPRINT and GETPRINT are related only to the PRINT statement and do
not effect CPRINT below.
7.3 - Simple Uses of PRINT and SETPRINT
We provide a few examples of common output situations.
1) PRINT to TERMINAL. Just call PRINT with your output, don't
bother with SETPRINT.
2) PRINT to FILE. Call
SETPRINT(NULL,"F");
and type the name of the output file, at runtime, when it asks.
3) PRINT to FILE and TERMINAL. Call, at the beginning of your
program,
SETPRINT(NULL,"B");
and type the name when asked.
4) PRINT to FILE always and sometimes also to TERMINAL. Call, at
the beginning
SETPRINT(NULL,"B");
25
SAIL Addendum 1 PRINT
and give the name of the file when it asks. This sets output to both
the terminal and the file. Now, to ignore the terminal (leaving the
file alone), call
SETPRINT(NULL,"I");
Likewise, to turn the teletype back on, call
SETPRINT(NULL,"C");
This is useful for obtaining a cleaned-up printout on the file, with
error messages going to the terminal.
The use of GETPRINT to determine the current state allows more
complex possibilities.
7.4 - CPRINT -- Printing to a Channel
CPRINT is similar to PRINT except that the first argument is assumed
to be a SAIL channel number. CPRINT then dispatches to the file the
appropriate printed formats of the rest of the arguments. Thus, the
following are functionally equivalent:
CPRINT(CHAN,"The value are ",I," and ",X);
OUT(CHAN,"The values are " & CVS(I) & " and " & CVG(X));
The user is responsible for obtaining and releasing the channel for
the CPRINT statement. As a very simple example on the DEC system:
OUTSTR("Type output file name *");
OPEN(CHAN ← GETCHAN,"DSK",0,0,2,0,0,0);
ENTER(CHAN,INCHWL,FLAG);
IF FLAG THEN USERERR(0,0,"CANNOT GET FILE ON DISK");
or for TENEX:
OUTSTR("Type output file name *");
CHAN ← OPENFILE(NULL,"W");
26
SAIL Addendum 1 PRINT
The statement RELEASE(CHAN) on DEC or CFILE(CHAN) on TENEX will close
and release the device/file open on CHAN.
7.5 - Design of PRINT
The PRINT statement was designed for those who miss the ALGOL W WRITE
and WRITEON statements, especially for new SAIL users who currently
have to learn too much about type conversion and file manipulation to
write simple SAIL programs. Notice that SAIL doesn't need both WRITE
and WRITEON, since manipulating lines can be done from SAIL by
printing out formatting characters. We recommend the following macro
DEFINE CRLF="('15 & '12)";
which the user may define to mean "carriage return - line feed".
Thus,
PRINT(CRLF,"Hi There");
is equivalent to the ALGOL W
WRITE("Hi There");
A READ statement was also considered for implementation. The
difficulty lies in defining how strings are input. SAIL has very
extensive input facilities, including break tables, which do many of
the common scanning operation.
Further consideration was given to a template-driven printing
function. This proved to be both inefficient in implementation, and
an added overhead to an already large runtime system.
7.6 - CAVEATS of PRINT and CPRINT
A problem with the PRINT construction, especially for experienced
SAIL users, is likely to occur when the user trys to exploit the
normal SAIL type conversions in the printing of strings. This is
especially common when the user wants to print out ASCII characters.
One often uses a number (i.e., an INTEGER expression) that, upon
default type conversion, becomes a one-character string. Thus,
27
SAIL Addendum 1 PRINT
OUTSTR(12)
prints a form-feed onto the terminal, whereas
PRINT(12)
prints "12" onto the terminal. The reason, of course, is the default
formatting for integers under PRINT or CPRINT.
This problem is especially confusing with macros that have been
defined with an integer to represent an ASCII character. For
example,
DEFINE TAB="'11";
will present the same problem. The solution is to define the macro
so that it expands to a STRING constant rather than an integer.
Also, beware that the first argument to CPRINT is the channel number.
7.7 - Hooks into the PRINT System
[This section is for wizards only.]
As is traditional with SAIL, there are user hooks to get hold of the
operation of the PRINT system. These hooks are obtained by setting
certain cells of the user table to the addresses of SIMPLE PROCEDURES
that the user has written.
All output going to either the PRINT or CPRINT statements can be
trapped by setting user table entry $$PROU to the address of a SIMPLE
procedure that has one string and one integer argument, e.g.,
SIMPLE PROCEDURE MYPRINT(INTEGER CHAN; STRING S)
The user could set this up by the assignment
GOGTAB[$$PROU] ← LOCATION(MYPRINT);
28
SAIL Addendum 1 PRINT
(See below in this manual for a description of the GOGTAB array as a
way of accessing the user table.)
The CHAN argument is then either the CHAN argument for CPRINT, or -1
for PRINT. If this trap is set up, all output from PRINT and CPRINT
goes through the user routine, and is not printed (unless the user
invokes OUT or OUTSTR from within the trap routine itself.)
To trap the formatting function for any syntactic type, the user
should set the appropriate user table address to the location of a
function that returns a string and takes as an argument the syntactic
type in question. For example, if the user wanted to trap integer
printing and print all integers out in octal, preceded by a "'", he
could do the following:
SIMPLE STRING PROCEDURE MYCVOS(INTEGER I);
RETURN("'" & CVOS(I));
GOGTAB[$$FINT] ← LOCATION(MYCVOS);
The names for the addresses in the user table associated with each
formatting function are:
User table index for syntactic type
-----------------------------------------
$$FINT INTEGER
$$FREL REAL
$$FITM ITEM
$$FSET SET
$$FLST LIST
$$FSTR STRING
$$FREC RECORD!POINTER
To restore any formatting function to the default provided by the
PRINT system, the user should zero the appropriate address of the
user table.
29
SAIL Addendum 1 SAVE/CONTINUE
SECTION 8
SAVE/CONTINUE
A save/continue facility has been implemented in the SAIL compiler.
This allows compiling header files, saving the state of the compiler,
and resuming compilation at a later time. The save/continue facility
works with files as the basic unit; compilation can be interrupted
only at the end of a file. The /X (eXtend) switch controls the new
feature. The examples shown here are for the DEC timesharing system.
Analogous commands work under TENEX, using the TENEX RUN and SAVE
commands. The dialog is similar, except that the TENEX command
language format is followed on TENEX. Example:
.R SAIL
*INTRMD.REL[PRJ,PRG]←A,B,C/X
A.SAI 1 etc.
SAVE ME FOR USE AS XSAIL.
EXIT
.SAVE XSAIL
JOB SAVED IN 25K
UPPER NOT SAVED!
.RU XSAIL
*FINAL←D,E,F
D.SAI
Copying DSK:INTRMD.REL[PRJ,PRG]
2 3 etc.
*↑C
The above is equivalent to
.R SAIL
*FINAL←A,B,C,D,E,F
On TENEX, the user will want to save core from 20 to 577777 in
creating the XSAIL.SAV file.
Information is saved in XSAIL.SAV and in the binary file from the
first "compilation" (in this case INTRMD.REL). When compilation is
resumed, the final binary file is initialized by copying the
intermediate file.
30
SAIL Addendum 1 SAVE/CONTINUE
Save/continue is not allowed if the file break occurs while scanning
false conditional compilation or actual parameters to a macro call.
A hint on using this feature: If the source term of your command
string consists of just one file, and this one file does REQUIREs of
other source files, the following setup works well.
Original file FOO.SAI:
BEGIN "FOO"
REQUIRE "[][]" DELIMITERS;
DEFINE !=[COMMENT];
REQUIRE "BAZ.SAI" SOURCE!FILE;
REQUIRE "MUMBLE.SAI" SOURCE!FILE;
:
<rest of file>
:
END "FOO"
New file FOO.SAI:
IFCR NOT DECLARATION(GARPLY) THENC
BEGIN "FOO"
REQUIRE "[][]" DELIMITERS;
DEFINE GARPLY=TRUE;
DEFINE !=[COMMENT];
REQUIRE "BAZ.SAI" SOURCE!FILE;
REQUIRE "MUMBLE.SAI" SOURCE!FILE;
ENDC;
:
<rest of file>
:
END "FOO"
New file FOO.HDR:
IFCR NOT DECLARATION(GARPLY) THENC
BEGIN "FOO"
REQUIRE "[][]" DELIMITERS;
DEFINE GARPLY=TRUE;
DEFINE !=[COMMENT];
REQUIRE "BAZ.SAI" SOURCE!FILE;
REQUIRE "MUMBLE.SAI" SOURCE!FILE;
ENDC;
Initial compilation:
.R SAIL
*FOO.INT[PRJ,PRG]←FOO.HDR/X
31
SAIL Addendum 1 SAVE/CONTINUE
SAVE ME!
.SAV XSAIL
Now the command string
FOO←FOO
will work both in the case of .R SAIL and in the case .RU XSAIL.
32
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
SECTION 9
MISCELLANEOUS NEW FEATURES
9.1 - NEW MTAPE OPTIONS
MTAPE(chan,NULL)
will cause an MTAPE 0 to be issued for channel chan. For mag. tapes,
this will cause you to wait until all activity ceases. For other
devices, various random things can happen, depending on the device
and system.
In export SAIL, MTAPE(chnl,"I") sets the 'IBM compatible' mode for a
tape drive. (It does an MTAPE chnl,101.)
These features do not work in TENEX SAIL. Full access to TENEX
magtapes is obtained through the MTOPR, GDSTS and SDSTS routines,
which are TENEX-only runtimes.
9.2 - INITIALIZATION PHASES
User initializations are now done in successive phases, with all
initializations required for one phase being done before
initializations required for the next phase.
Syntax:
REQUIRE <procid> INITIALIZATION;
REQUIRE <procid> INITIALIZATION [<phase no>];
where <phase no> is an integer constant.
Semantics:
<phase no> specifies the number of the user initialization phase.
33
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
If it is left out, then one is used. Currently, there are three
phases, numbered 0, 1, and 2. If the demand is great enough,
additional phases may be added later. (Note for assembly language
hackers: internally, user phases are numbered '400000, '400001, etc.)
9.3 - CHNCDB
val←CHNCDB(channel)
This integer procedure returns a pointer to the three word block used
to open the specified channel. It is provided for the benefit of
assembly language procedures that may want to do I/O inside some fast
inner loop, but which may want to live in a SAIL core image & use the
SAIL OPEN, etc.
This feature does not work in TENEX SAIL. See a hacker if you want
these features.
9.4 - OVERFLOW
The overflow-underflow handling routines have been upgraded to deal
with JFCL properly. See the section on trigonometric routines.
9.5 - ARRCLR
ARRCLR(arry)
This new runtime routine clears any kind of array. That is, arthmetic
arrays get filled with zeros, string arrays with NULLs, and itemvar
arrays with ANYs. One may use ARRCLR with set and list arrays, but
the set and list space will be lost (i.e. un-garbage-collectable).
The alternative form:
ARRCLR(arry,val)
where val is either an integer or a real number, will fill arry with
that value. Do not do this to string or list arrays unless you do
34
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
not care whether or not your program works. Also using a real val
for an itemvar array is apt to cause strange results. (If you use an
integer, arry will be filled with CVI(val).)
9.6 - SETPL
SETPL(channel, @linnum, @pagnum, @sosnum)
This new runtime routine allows one to keep track of the string input
from CHANNEL. Whenever a '12 is encountered, LINNUM is incremented.
Whenever a '14 is encountered, PAGNUM is incremented, and LINNUM is
zeroed. Whenever an SOS line number is encountered, it is placed
into SOSNUM. When fully implemented (soon), this will work on the
INPUT, INTIN, and REALIN functions as well.
9.7 - EVALREDEFINE
EVALREDEFINE bears the same relationship to REDEFINE as EVALDEFINE
does to DEFINE. See pages 47 and 50 of the Manual.
9.8 - CVPS
CVPS(<macro-parameter>) converts <macro-parameter> to a string and
returns the string. See about macro parameters on page 48 of the
manual.
9.9 - EXPRESSIONS IN REQUIRES
Previously, all REQUIRE constructs had to have only constants in
them. Now SAIL allows compile time expressions as well. See about
compile time expressions on page 47 of the Manual.
35
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.10 - RELEASE
RELEASE now takes an optional second argument, the CLOSE inhibit
bits. These are described in the UUO manual (Stanford System). These
are defaulted to zero when not specified so that old programs which
did not specify them will work as before.
The CLOSE inhibit feature only works at SU-AI.
9.11 - TTYUP
oldval←TTYUP(newval)
This routine casuse conversion of lower case characters (a-z) to
their upper case equivalents for strings read by any of the SAIL
teletype routines that do not use break tables. If newval is TRUE,
then conversion will take place on all subsequent inputs until TTYUP
is called with newval FALSE. Oldval will always get set to the value
of newval used in the previous call. (If TTYUP has never been called,
then no conversions will take place, and the first call to TTYUP will
return FALSE).
In TENEX, TTYUP sets the system parameter using the STPAR jsys to
convert to upper case.
9.12 - BREAKSET MODES "K" AND "F"
A "K" specification as a BREAKSET mode will cause lower to upper case
conversion when that break table is used. Conversion takes place
before each character is checked for breaking or omission. An "F"
specification turns off the conversion -- i.e. it undoes the effects
of "K".
36
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.13 - INOUT
INOUT(inchan,outchan,howmany)
INOUT reads howmany words from channel inchan and writes them out on
channel outchan. Each channel must be open in a mode between 8 and
12. on return, the EOF variables for the two channels will be the
same as if ARRYIN & ARRYOUT had been used. If howmany is less than
zero, then transfer of data will cease only upon end of file or a
device error.
(note: INOUT uses BLTs to transfer data directly from one set of
buffers to the other)
INOUT is not available in TENEX SAIL.
9.14 - GETSTS & SETSTS
SETSTS(chan,newstatus)
issues a SETSTS uuo on channel chan with the status value newstatus.
status←GETSTS(chan)
returns the results of a GETSTS uuo on channel chan.
These functions do not exist in TENEX SAIL. Instead, see GTSTS,
GDSTS, STSTS, and SDSTS for analogous features.
9.15 - CHANGES TO "OPEN" ERROR HANDLING
If the EOF variable supplied to OPEN is non-zero and the device name
is invalid, then OPEN will fail without giving the error message
"INVALID DEVICE NAME FOR OPEN", and the EOF value will be unchanged.
If a device is unavailable, and EOF=0, then the user is now given the
options of trying again or going on without opening the device, in
which case EOF will be set to non-zero as usual.
37
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.16 - ASH
ASH has been added as an arithmetic operator. Its syntax is just
like that of LSH, and it generates similar code (except for putting
out a PDP-10 ASH instruction instead of a LSH).
9.17 - ARG!LIST
ARG!LIST(<arg1>,...,<argn>)
where each <arg> may be any valid argument to the REF!ITEM construct,
assembles a list of "temporary" reference items that will be deleted
by APPLY after the applied procedure returns. Thus
APPLY(proc,ARG!LIST(foo,bar,VALUE baz))
is roughly equivalent to
tmplst←{{REF!ITEM(foo),REF!ITEM(bar),REF!ITEM(VALUE baz)⎇⎇;
APPLY(proc,tmplst);
WHILE LENGTH(tmplst) DO DELETE(LOP(tmplst));
but is somewhat easier to type. Note that the reference items
created by ARG!LIST are just like those created by REF!ITEM, except
that they are marked so that APPLY will know to kill them.
9.18 - CLOSE
The CLOSE function now has an additional optional argument that
allows the CLOSE inhibit bits to be turned on. The second argument
is the bit pattern for the inhibition, and it is defaulted 0. See
the UUO manual for details.
This feature is available only at SU-AI, and is not available in the
TENEX version of SAIL.
38
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.19 - TYPEIT
The number returned by the TYPEIT procedure (which identifies the
type of the datum of its item expression argument) is now changed for
arrays. Now it is '24 plus the scalar value of the type (e.g.,
INTEGER), whereas before it was '15 plus the scalar value.
Additional types added to TYPEIT are: '16 for labels, '17 for record
classes.
9.20 - COMPARISON OF .REL FILES
Starting with version 18, the compiler emits information into each
.REL file containing the version of the compiler used. Then, during
the SAIL initialization sequence, these versions are compared, and a
warning message is issued if necessary. Thus, the problem of
converting from one version of the compiler to a new version is
lessened. This feature may not work as well in the current
changeover as it will in the future.
9.21 - SCAN Optimizations
The SCAN function has been modified to return true substrings instead
of copies in those cases that the break table in question was not
omitting any characters. This should be an improvement in the
efficiency of those routines.
9.22 - BREAK TABLES
There are now 54 user-setable break tables available to the SCAN,
INPUT, TTYINL functions, as well as SETBREAK and BREAKSET. These
tables are allocated and deallocated dynamically.
In addition, GETBREAK now returns the value of the smallest
unallocated breaktable, and RELBREAK releases its table argument.
The implicit declarations of these new runtime routines are:
INTEGER PROCEDURE GETBREAK
39
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
PROCEDURE RELBREAK(INTEGER TABLE)
NOTE: a breaktable is allocated by either GETBREAK, SETBREAK,
BREAKSET or STDBRK. A breaktable is de-allocated (and thereby made
available to GETBREAK) by RELBREAK. Breaktables are stored in groups
of 18, so it is more efficient to use all the tables in a given group
before going to another group. The use of GETBREAK is particularly
recommended for load-modules and the like, so that conflicts will be
minimzed. Breaktable zero is special. It is predeclared to produce
the same results as SETBREAK(0,NULL,NULL,"I"). This results in
break-on-count for calls to INPUT, and always returns the whole
string for SCAN. Breaktable zero is stored along with breaktables 1
to 18, and thus takes up no additional space.
HACKERS: Actually there are 17 additional system breaktables which
are reserved for use by the SAIL runtime system. These tables are
numbers -17 through -1, and are ordinarily not available to the user.
They will be used by the debugger and by additional SAIL system
software.
The user can obtain access to breaktables -17 through -1 by setting
BRKPRV(USER) to -1, for example by the USERCON function which
accesses the SAIL user table. WARNING: absolutely no guarantees are
made to the user who accesses these breaktables. Thipεinformation is
intended for completeness only; the use of these special breaktables
by the user is not recommended.
9.23 - CV6STR
CV6STR does what you always wished CVXSTR did. I.e., it stops
converting as soon as it sees a blank rather than always returning a
six-character string. Example:
CV6STR(CVSIX("XYZ"))="XYZ", not "XYZ ".
Beware, however, since
CV6STR(CVSIX("X Y Z")) ="X", not "X Y Z" or "XYZ".
40
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.24 - TENEX RUNTIMES
The TENEX version of SAIL now has these additional teletype-oriented
routines: STTYP, GTTYP, STPAR, STI, and DELNF, all named after
jsyses. See TENEX-specific documentation.
9.25 - CVASTR
CVASTR is the "correct" inverse function to CVASC. I.e., it stops on
a null character. For instance,
CVASTR(CVASC("ABC")) is "ABC"
whereas
CVSTR(CVASC("ABC")) is "ABC"&0&0
9.26 - NEW SWITCHES
/V forces loader link blocks and constant string texts into the low
segment; intended for overlay systems in which code is overlaid but
data is not.
/X controls compiler save/continue; see the section on
save/continue.
/W generates additional (suppressed) DDT symbols. These symbols are
designed to serve as comments to a programmer or processor rummaging
though the generated code. Symbols generated by this switch all
begin with a percent sign (%), and many come in pairs. A %$ symbol
points to the first word of an area and a %. symbol points to the
first word beyond the area. Thus the length of an area is the
difference of its %. and %$ symbols. The symbols are:
%$ADCN %.ADCN address constant area
%$LIT %.LIT literal area
%$RLIT %.RLIT reference literal area
%$SCOD %.SCOD START!CODE or QUICK!CODE area
%$STRC %$STRC string variable area
%$VARS %.VARS simple variable area
%ALSTO registers are about to be cleared
%$ARRY first data word of a fixed array
%$FORE FOREACH satisfier block
41
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
%$SUCC SUCCEED/FAIL return block
/W tends to increase the number of DDT symbols by a factor of 2 or 3.
/F Two new values, /40F and /100F, have been added. Characters are
temporarily inhibited from going to the listing file if the 40 bit is
on (see COMPILER!SWITCHES below for what good this will do you). If
the 100 bit is on then the two-line banner normally put at the top of
each page of the listing is suppressed. Using the 100 bit is a way
to have SAIL "permanently" expand macros; a /110F listing can be used
as a SAIL source file.
/D, /P, /Q, /R now accept values. If a non-zero value appears, it is
interpreted as decimal and the stack is set to that size. If the
value is zero or absent, then the stack size is doubled as before.
Thus /35P/P first sets the P stack to 35 and then doubles it to 70.
9.27 - COMPILER!SWITCHES
The statement REQUIRE "chars" COMPILER!SWITCHES; can be used to
change the settings of the compiler switches. "chars" must be a
string constant which is a legitimate switch string, containing none
of the characters "(/)"; e.g.,
REQUIRE "20F" COMPILER!SWITCHES;
The string of characters is merely passed to the switch processor,
and it may be possible to cause all sorts of problems depending on
the switches you try to modify. The switches which set stack sizes
(D, P, Q, R) or string space (S) should be avoided. Switches which
control the format of files (B, F) should only be used if you have
such a file open.
9.28 - COMPILER!BANNER
This is a predefined macro which expands to a string constant
containing the text of the two-line banner which would appear at the
top of the current page if a listing file were being made. This
string contains the date, time, name and page of the source file, the
value of all compiler switches, the name of the outer block, and the
name of the current block. Thus you can automatically include the
date of compilation in a program by using COMPILER!BANNER[n TO m] for
42
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
appropriate n and m. Try REQUIRE COMPILER!BANNER MESSAGE; or look at
a listing for the exact format.
9.29 - EDFILE
EDFILE("filename",line,page,bits[0])
Exits to an editor. Which editor is determined by the bits which are
on in the second parameter, line . If bit 0 or bit 1 (600000,,0 bits)
is on, then line is assumed to be ASCID and SOS is called. If
neither of these bits is on, then line is assumed to be of the form
attach count,,sequential line number and E is called. Page is the
binary page number. Bits defaults to zero and controls the editing
mode:
0 edit
1 no directory (as in /N)
2 readonly (as in /R)
4 create
In addition, the accumulators are set up from INIACS (see below) so
that the E command αX RUN will run the dump file from which the
current program was gotten. [Accumulators 0 (file name), 1
(extention), and 6 (device) are loaded from the corresponding values
in INIACS.]
9.30 - INIACS
The contents of locations 0-'17 are saved in block INIACS when the
core image is started for the first time. Declare INIACS as an
external integer and use START!CODE or MEMORY[LOCATION( INIACS)+n] to
reference this block.
9.31 - GOGTAB
Direct access to the user table can be gained by declaring EXTERNAL
INTEGER ARRAY GOGTAB[0:n]; The clumsy USERCON linkage is obsolete.
The symbolic names of all GOGTAB entries can be obtained by requiring
GOGTAB.DEF[S,AIL] (<SAIL>GOGTAB.DEF on TENEX) as a source file. This
file contains DEFINEs for all of the user table entries.
43
SAIL Addendum 1 MISCELLANEOUS NEW FEATURES
9.32 - ARERR
The effective address of an ARERR UUO (op code 007) may be either
word 1 or word 2 of a string descriptor. This allows ARERR 1,["array
name"] from START!CODE.
44
SAIL Addendum 1 MINOR CORRECTIONS TO AIM-204
SECTION 10
MINOR CORRECTIONS TO AIM-204
This is a file of known SAIL manual defects (mainly typos) that are
not already noted in the preface or covered by the "incremental" SAIL
manual. It is primarily an internal document for the SAIL hackers,
put is being provided here as a stopgap measure pending a full new
edition for the manual. This list is, however, not complete in that
it does not include a number of typos that do not change the meaning.
If, however, you discover any defects in the manual or in the update,
please notify your friendly local SAIL representative.
99R KVL The synonym for "SUCH THAT" is "|" and not "
"
32R KVL APPENDIX 5 has nothing to do with the
bits for IO errors or mode enablings
43L RHT FILEINFO documentation is a lie. You usually get:
FILENAME
EXT,,DATE
prot(9)Mode(4)time(11)date(12)
negative swapped word count (if did a lookup).
0 (unless you opened device in magic mode)
0
The whole point is that what you get is the six words
from the last lookup or enter. For details see the
monitor manual.
58R JRL if a designated bracketed triple is not found
then bindit is returned and no error message is given
33L JRL release now takes a second defaultable value integer
argument, the close inhibit bits (see RELEAS in UUO
manual). These are defaulted to zero when
unspecified.
72R KVL TELLALL does not do an implicit RESCHEDULE as the
description implies -- it just sets the status of
the concerned processes to "ready".
102R RFS "33 through 36" S/B "33 through 35"
45
SAIL Addendum 1 MINOR CORRECTIONS TO AIM-204
105R RFS ". her are several" s/b " . There are several"
79R,L KVL JOBTPC should be loaded with the location of a CALL
to a non-simple procedure.
92R JRL 20F will in future surround macro expansions with
"<>" not "⊂⊃".
38R RHT The description of INCHWL is wrong. Actually, the
activation character is never included in the string
and is always put into !SKIP!. (<crlf> puts a <cr>
into !SKIP! & throws away the <lf>).
24L RHT The compiler will not in fact turn division by a
power of two into an ASH.
90L REG "... See section 19 about these [compilation errors]"
should be section 20.
90L REG 19.1.3 "boundary" is misspelled.
41R RHT CVSIX left-justifies the sixbit value it builds.
43L RHT In POINT, it is "a PDP-10 byte pointer".
45R RHT FORC syntax should be "FORC <identifier> ← ... "
57R RHT " ... methods of searching the associative store ..."
had "store" missing before.
105L RHT "omaname" should be "the symbolic name"
110L RHT added reference:
Harvey, Brian "Monitor Command Manual" SAILON 54.3
(Dec 1973)
Also, there is a more current SOS manual: SAILON 50.3
76L RHT Should be "REF!ITEM(VALUE <expression>)"
43L RFS For FILEINFO, also should have a note to export users
like "FILEINFO fills the array with the results of
the last LOOKUP or ENTER (DEC 10-50 systems).
Consult your local monitor manual for the format of
these entries."
28L JRL CALLING PROCEDURES FROM INSIDE CODE BLOCKS
"... procedure is typed, it will return is value in
AC 1 (a pointer to the second word if the procedure
46
SAIL Addendum 1 MINOR CORRECTIONS TO AIM-204
is a string procedure)." should be " procedure is
typed and not a string procedure it will return
its value in AC 1. String procedures push the two
word string descriptor corresponding to the result
on the SP stack."
23L RHT The table of precedence for AND & OR is misleading.
AND has higher precedence than OR.
26R JRL ARRYIN. No indication of how many words were actually
read is given if EOF is encountered while reading a
file in DUMP mode.
25L RHT The description of the MEMORY[x,<type>] construct is
very misleading. There is no restriction on the use
of this construct as the left hand side of an
assignment statement. In fact, MEMORY[x,<type>] may
be used anywhere a simple variable of type <type> may
be used.
92R JFR The compiler is initialized with /7F.
47