More Pre-Scheme packages
========================

Along with the prescheme structure, there are several other structures built-in to Pre-Scheme.

Floating point operation
------------------------

Since Pre-Scheme's strict static type system would not permit overloading of the arithmetic operators for integers & floats, it provides a different set of operators for floats.  These names are all exported by the ps-flonums structure.

 -- procedure: fl+ augend addend ... returns float
 -- procedure: fl- float returns float
 -- procedure: fl- minuend subtrahend returns float
 -- procedure: fl* multiplier multiplicand ... returns float
 -- procedure: fl/ divisor dividend returns float
 -- procedure: fl= floata floatb returns boolean
 -- procedure: fl< floata floatb returns boolean
 -- procedure: fl> floata floatb returns boolean
 -- procedure: fl<= floata floatb returns boolean
 -- procedure: fl>= floata floatb returns boolean
     All of these operations flOP correspond as floating point variations of their OP integer equivalents.

Record types
------------

The ps-record-types structure defines the following special form for introducing record types.  Pre-Scheme record types are translated to C as structs.

 -- syntax: define-record-type

          (define-record-type TYPE TYPE-DESCRIPTOR
            (CONSTRUCTOR ARGUMENT-FIELD-TAG ...)
            (FIELD-TAG1 FIELD-TYPE-SPEC1
              FIELD-ACCESSOR1 [FIELD-MODIFIER1])
            (FIELD-TAG2 FIELD-TYPE-SPEC2
              FIELD-ACCESSOR2 [FIELD-MODIFIER2])
            ...
            (FIELD-TAGN FIELD-TYPE-SPECN
              FIELD-ACCESSORN [FIELD-MODIFIERN]) lisp
          Defines a record type.  TYPE is mangled to the C struct type name
          (TYPE-DESCRIPTOR-NAME is unused unless running Pre-Scheme as
          Scheme).  CONSTRUCTOR is defined to construct a record of the new
          type and initialize the fields ARGUMENT-TYPE-FIELD ... with
          its arguments, respectively.  If it cannot allocate a sufficient
          quantity of memory, CONSTRUCTOR returns a null pointer.  The
          initial values of fields that are not passed to the constructor are
          undefined.  For each field FIELDI specified,

            * FIELDI is specified to have the type
               FIELD-TYPE-SPECI;

            * FIELD-ACCESSORI is defined to be a procedure of one
               argument, a record of type TYPE-NAME, that returns the value of
               the field FIELDI of that record --- its type is defined to
               be (=> (TYPE-NAME) FIELD-TYPE-SPECI); and

            * if present, FIELD-MODIFIERI is defined to be a
               procedure of two arguments, a record of type TYPE-NAME and a
               value of type FIELD-TYPE-SPEC, that assigns the value of the
               field FIELDI in its first argument to be the value of its
               second argument; its type is (=> (TYPE-NAME
               FIELD-TYPE-SPEC) unit).

          Records must be deallocated explicitly when their lifetime has expired
          with deallocate.

Multiple return values
----------------------

Pre-Scheme support multiple return values, like in Scheme.  The only difference is that one cannot operate on multiple return values as lists, since Pre-Scheme does not have lists.  Multiple return values are implemented in C as returning in C the first value and passing pointers to the remaining values, which the function returning multiple values assigns.  The prescheme structure exports the two multiple return value primitives, call-with-values and values, but the ps-receive structure exports this macro for more conveniently binding multiple return values.

 -- syntax: receive formals producer body
     Binds the lambda parameter list FORMALS to the multiple values that PRODUCER returns, and evaluates BODY with the new variables bound.

          (receive FORMALS
                   PRODUCER
            BODY)
              ==
          (call-with-values
              (lambda () PRODUCER)
            (lambda FORMALS
              BODY)) lisp

Low-level memory manipulation
-----------------------------

Pre-Scheme is a low-level language.  It provides very low-level, direct memory manipulation.  `Addresses' index a flat store of sequences of bytes.  While Pre-Scheme `pointers' are statically checked for data coherency, allow no arbitrary arithmetic, and in general are high-level abstract data to some extent, addresses are much lower-level, have no statically checked coherency --- the values an address represents are selected by what operation used to read or write from it ---, permit arbitrary address arithmetic, and are a much more concrete interface into direct memory.  The ps-memory structure exports these direct memory manipulation primitives.

 -- procedure: allocate-memory size returns address
 -- procedure: deallocate-memory address returns unit
     Allocate-memory reserves a sequence of SIZE bytes in the store and returns an address to the first byte in the sequence. Deallocate-memory releases the memory at ADDRESS, which should have been the initial address of a contiguous byte sequence, as allocate-memory would return, not an offset address from such an initial address.

 -- procedure: unsigned-byte-ref address returns unsigned-byte
 -- procedure: unsigned-byte-set! address unsigned-byte returns unit
 -- procedure: word-ref address returns word
 -- procedure: word-set! address word returns unit
 -- procedure: flonum-ref address returns float
 -- procedure: flonum-set! address float returns unit
     Procedures for reading from & storing to memory. Unsigned-byte-ref & unsigned-byte-set! access & store the first unsigned byte at ADDRESS.  Word-ref & word-set! access & store the first word --- Pre-Scheme integer --- beginning at ADDRESS.  Flonum-ref & flonum-set! access & store 64-bit floats beginning at ADDRESS..

     Bug: Flonum-ref & flonum-set! are unimplemented in the Pre-Scheme-as-Scheme layer (see Running Pre-Scheme as Scheme).

 -- procedure: address? value returns boolean
     Disjoint type predicate for addresses.

     Note: Address? is available only at the top level, where code is evaluated at compile-time.  Do not use this in any place where it may be called at run-time.

 -- constant: null-address returns address
     The null address.  This is somewhat similar to the null pointer, except that it is an address.

     Note: One acquires the null pointer by calling the procedure null-pointer, whereas the constant value of the binding named null-address is the null address.

 -- procedure: null-address? address returns boolean
     Null-address? returns true if ADDRESS is the null address and false if not.

 -- procedure: address+ address increment returns address
 -- procedure: address- address decrement returns address
 -- procedure: address-difference addressa addressb returns integer
     Address arithmetic operators.  Address+ adds INCREMENT to ADDRESS; address- subtracts DECREMENT from ADDRESS; and address-difference returns the integer difference between ADDRESSA and ADDRESSB. For any ADDRESSP & ADDRESSQ, (address+ ADDRESSP (address-difference ADDRESSP ADDRESSQ)) is equal to ADDRESSQ.

 -- procedure: address= addressa addressb returns boolean
 -- procedure: address< addressa addressb returns boolean
 -- procedure: address> addressa addressb returns boolean
 -- procedure: address<= addressa addressb returns boolean
 -- procedure: address>= addressa addressb returns boolean
     Address comparators.

 -- procedure: integer->address integer returns address
 -- procedure: address->integer address returns integer
     Integers and addresses, although not the same type, may be converted to and from each other; integer->address & address->integer perform this conversion.  Note that Pre-Scheme pointers may not be converted to addresses or integers, and the converse is also true.

 -- procedure: copy-memory! source-address target-address count returns unit
     Copies COUNT bytes starting at SOURCE-ADDRESS to TARGET-ADDRESS.  This is similar to C's memcpy.

 -- procedure: memory-equal? addressa addressb count returns boolean
     Compares the two sequences of COUNT bytes starting at addresses ADDRESSA & ADDRESSB.  It returns true if every byte is equal and false if not.

 -- procedure: char-pointer->string address size returns string
 -- procedure: char-pointer->nul-terminated-string address returns string
     Char-pointer->string returns a string with SIZE bytes from the contiguous sequence of bytes starting at ADDRESS. Char-pointer->nul-terminated-string does similarly, but it returns a string whose contents include every byte starting at ADDRESS until, but not including, the first 0 byte, ie ASCII nul character, following ADDRESS.

 -- procedure: read-block port address count returns [count-read eof? status]
 -- procedure: write-block port address count returns status
     Read-block attempts to read COUNT bytes from PORT into memory starting at ADDRESS.  Write-block attempts to write COUNT bytes to PORT from the contiguous sequence in memory starting at ADDRESS.  Read-block returns three values: the number of bytes read, whether or not the read went to the end of the file, and the error status (see Pre-Scheme error handling).  Write-block returns the error status.