perm filename SAIL.UPD[NEW,AIL] blob sn#410588 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.  This 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