REF DATA                                            John Gibson Dec 1995

       COPYRIGHT University of Sussex 1995. All Rights Reserved.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<   GENERIC DATA PROCEDURES   >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

This file  describes  data  representation  in  Poplog,  and  provides a
comprehensive list of all Poplog data types (together with the REF files
containing further information on each). Generic functions applicable to
most structures (including  user defined ones)  are then described.  The
final sections deal with the internal format of Poplog data structures.

         CONTENTS - (Use <ENTER> g to access required sections)

  1   Representation of Data in Poplog
      1.1   Overview
      1.2   List of Data Types
      1.3   Notes

  2   Predicates on Objects

  3   Information About Objects

  4   Comparison Procedures

  5   Structure Concatenation

  6   Generic Data Structure Procedures

  7   Generic Vector/Byte Structure Procedures

  8   Miscellaneous Procedures

  9   Format of Poplog Data Structures
      9.1   Byte-Accessible Structures



-----------------------------------
1  Representation of Data in Poplog
-----------------------------------

1.1  Overview
-------------
In many programming language systems, the types of data objects are  not
encoded explicitly within the  objects, but are  merely implicit in  the
way in which they are processed;  that is, objects are not  identifiable
at run-time.

In Poplog, however (as in most AI programming environments), data  items
carry around with  them an  explicit representation of  type, which  all
procedures in the  system can  use in deciding  how to  process a  given
object. This is achieved by representing all items to be manipulated  as
encoded bit patterns (of  the size of the  'natural' word length of  the
underlying machine) which identify themselves as either:

    (a)  directly containing the actual data (simple objects), or

    (b)  as pointers to data structures (compound objects)

The latter pointer  types are  then further distinguished  by a  special
field in the  data structures  to which  they point,  which contains  an
identifying key structure for the class of object (keys are described in
REF * KEYS.) See the section Format of Poplog Data Structures below  for
further details on the layout of Poplog structures.

(Note that  the above  encoding  scheme does  not  apply to  integer  or
floating-point data  held  in 'packed'  record  or vector  fields  (e.g.
strings.) These values  are implicitly  typed by  the fields  containing
them, and  so  can be  represented  'normally'. However,  extraction  or
insertion of  these field  values necessitates  conversion to  and  from
Poplog  representation,  this  being  performed  automatically  by   the
corresponding access and update procedures.)


1.2  List of Data Types
-----------------------
Below is  a complete  list  of the  data  types currently  available  in
Poplog, together with their identifying names as given by the  procedure
* dataword. Note that only integers and decimals are simple objects: all
others are compound.

    "biginteger"
        Arbitrarily-large integer               (REF * NUMBERS)

    "boolean"
        The unique items * true and * false     (REF * RECORDS)

    "complex"
        Complex number                          (REF * NUMBERS)

    "ddecimal"
        Double-length floating-point            (REF * NUMBERS)

    "decimal"
        Floating-point (simple)                 (REF * NUMBERS)

    "device"
        Input/Output device                     (REF * SYSIO)

    "dstring"
        String of display characters            (REF * STRINGS)

    "external_ptr"
        Pointer to external data                (REF * EXTERNAL_DATA)

    "ident"
        Identifier (constant or variable)       (REF * IDENT)

    "integer"
        Integer (simple)                        (REF * NUMBERS)

    "intvec"
        Signed packed-integer vector            (REF * INTVEC)

    "shortvec"
        Signed short packed-integer vector      (REF * INTVEC)

    "key"
        Class key                               (REF * KEYS)

    "matchvar"
        Used for matching items with =          (REF * RECORDS)

    "nil"
        The unique item [] in * nil             (REF * LISTS)

    "pair"
        Pair (and lists)                        (REF * LISTS)

    "procedure"
        Procedures in general and closures      (REF * PROCEDURE)
        Property procedures                     (REF * PROPS)
        Array procedures                        (REF * ARRAYS)

    "process"
        Process                                 (REF * PROCESS)

    "prologterm"
        Prolog term                             (REF * PROLOG)

    "prologvar"
        Prolog variable                         (REF * PROLOG)

    "ratio"
        Ratio of two integers (i.e. fraction)   (REF * NUMBERS)

    "ref"
        Single-element reference                (REF * RECORDS)

    "section"
        Permanent identifier section            (REF * SECTIONS)

    "stackmark"
        The item * popstackmark                 (REF * STACK)

    "termin"
        The unique item <termin> in * termin    (REF * CHARIO)

    "undef"
        Undef record (initial values of idents) (REF * IDENT)

    "vector"
        Standard full vector                    (REF * VECTORS)

    "word"
        Word                                    (REF * WORDS)

    "XptDescriptor"
        X toolkit Interface Descriptor          (REF * XptDescriptor)


1.3  Notes
----------
(The type "descriptor" is also present in VMS Poplog; this is  described
in REF * EXTERNAL.)

There is no special data type for characters, as these are simply  8-bit
integers.  Character  strings   are  merely   "packed"  vectors   with a
field-size of 8.

For each built-in data-type there is a global permanent constant  whose
name starts with the * dataword and ends with _key, and whose value  is
the   key   for   that   class,   e.g.   * integer_key,    * ratio_key,
* biginteger_key, * device_key etc.

* conskey (described in REF * KEYS)  can be used  to create new  record
classes or vector classes (e.g. bit-vectors.) REF * DEFSTRUCT describes
the syntax construct * defclass,  which packages these facilities  in a
more convenient form for programming use.

The procedures given below provide various functions applicable to  many
structures (including user defined ones) although (with the exception of
= etc)  not  to  numbers.  See also  REF * PRINT  for  generic  printing
procedures.




------------------------
2  Predicates on Objects
------------------------

issimple(item) -> bool                                       [procedure]
        Returns true if item is a  simple object (i.e. a simple  integer
        or a simple decimal), false otherwise.


iscompound(item) -> bool                                     [procedure]
        Returns true if item is a pointer to a data structure, false  if
        item is simple.


isrecordclass(item) -> key                                   [procedure]
isvectorclass(item) -> key                                   [procedure]
        These  two   procedures   return  datakey(item)   if   item   is
        respectively a  record-type  data  structure  (reference,  pair,
        record type constructed  with * conskey  etc), or a  vector-type
        data  structure  (string,  intvec,  full  vector,  vector   type
        constructed with conskey etc.) Otherwise they return false.

        (Note that  compound  items  for which  both  isrecordclass  and
        isvectorclass are false are  'special' objects, e.g  procedures,
        keys, etc.)


isinheap(struct) -> bool                                     [procedure]
        For a compound object struct, returns  true if struct is in  the
        working heap, i.e. is not an object in in the system area, false
        otherwise. (Note that structures  locked by * sys_lock_heap  are
        still counted as part  of the heap,  so that * isinheap  remains
        true for  these,  whereas those  locked  with  * sys_lock_system
        become part of the system, and isinheap becomes false. See  also
        * is_fixed in REF * EXTERNAL_DATA.)


is_poplog_item(item) -> key                                  [procedure]
        Returns datakey(item)  if  item  is recognisable  as  a  genuine
        Poplog item (i.e.  a simple  or compound  data item),  otherwise
        false. (This procedure is included for system checking;  users
        should not normally need it.)




----------------------------
3  Information About Objects
----------------------------

datakey(item) -> key                                         [procedure]
        Returns the  key  structure of  the  class of  which  item  is a
        representative. For example:

            datakey(3) =>
            ** <key integer>
            datakey([a b c]) =>
            ** <key pair>
            datakey("fred") =>
            ** <key word>
            datakey(hd) =>
            ** <key procedure>

        For more information on keys see REF * KEYS, HELP * CLASSES.


dataword(item) -> word                                       [procedure]
        Returns the name of the class of which item is a representative.
        For example:

            dataword(3) =>
            ** integer
            dataword([a b c]) =>
            ** pair
            dataword("fred") =>
            ** word
            dataword(hd) =>
            ** procedure

        Note that (unlike the datakey of  an item), the dataword is  not
        necessarily unique (i.e. two different classes can have the same
        dataword). For more information see REF * KEYS.


key_of_dataword(word) -> key                                 [procedure]
        Given a word which is a dataword, return the corresponding  key.
        (This is a library property, initialised for built in keys,  and
        updated by defclass, but not  currently by conskey itself.)  For
        more information on keys see REF * KEYS.


datasize(item) -> Nwords                                     [procedure]
        Returns the number of Poplog words occupied by the item item  in
        memory. (A Poplog word is the  native word size of the  machine,
        64  bits   on  Alpha   OSF,  and   32  on   all  other   current
        implementations.)  If  item  is  simple  (i.e.  an  integer   or
        decimal), 0 is returned.




------------------------
4  Comparison Procedures
------------------------

item1 ==  item2 -> bool                                     [operator 7]
item1 /== item2 -> bool                                     [operator 7]
        The operator == returns true  if item1 and item2 are  absolutely
        identical (i.e.  pointers to  the  same structure  or  identical
        simple numbers), otherwise false.

        /== is the same as not(item1 == item2).


item1 =  item2 -> bool                                      [operator 7]
item1 /= item2 -> bool                                      [operator 7]
        The operator = compares item1 and item2 by running the * class_=
        procedure from the key of item2, i.e.

            class_=(datakey(item2))(item1, item2)

        The  default  value  of  any  key's  class_=  is  the   standard
        comparison procedure run by * sys_=.  (In other words, = is  the
        same as sys_= unless the class_= procedure has been changed.)

        /= is the same as not(item1 = item2).


item1 =-> item2                                            [operator 10]
        The 'equals assign' operator =-> is  the same as =, but  instead
        of returning a boolean result, mishaps with 'NON-EQUAL ARGUMENTS
        FOR =->' if item1 and item2 are not equal.

        The principal use of this operator (and the reason for the  name
        'equals assign') is with an item2 containing matchvars, e.g.

                list =-> [=?x =?y =?z];

        is a way of decomposing a structure and assigning its components
        to variables.


sys_=(item1, item2) -> bool                                  [procedure]
        Does a  standard  comparison  of item1  and  item2,  recursively
        element by element if they  are structures, and returns true  if
        they are the same, false otherwise.

        The sub-elements of two structures of the same class and  length
        are compared  by calling  the class_=  procedure of  the  second
        sub-element (i.e. same as calling = on them).

        If item1 and item2 are numbers of any kind then the result  will
        depend on  their  mathematical equality/inequality  --  see  the
        description of = and /= in REF * NUMBERS.

        item2 may  also  be,  or  contain,  matchvar  records  to  match
        arbitrary   items.   See   HELP * EQUAL,   and   Matchvars    in
        REF * RECORDS.


item1 equals item2 -> bool                                  [operator 7]
item1 equals (item2, accept_match_p) -> bool
        This operator is an alternative version of = that guarantees  to
        find  any   possible  match   involving  repeated   list-segment
        matchvars, i.e. =??  variables that  occur more  than once  in a
        pattern. (It is, however, significantly slower than =.)

        It can take  as an optional  third argument a  procedure of  the
        form

                accept_match_p() -> bool

        which is called when a match is found. If accept_match_p returns
        true, equals returns true; if accept_match_p returns false,  the
        next match is  tried, or equals  returns false if  there are  no
        further matches.

        See the section Pattern Matching With = in HELP * EQUAL.


sys_nonlocal_equals(item1, item2) -> bool                    [procedure]
sys_nonlocal_equals(item1, item2, accept_match_p) -> bool
        This procedure is the same as the equals operator, but does  not
        localise or initialise the value of * pop_matchvars_bound.




--------------------------
5  Structure Concatenation
--------------------------

See also * >< and * sys_>< in REF * PRINT for concatenating the printed
representation of items.


struct1 <> struct2 -> struct3                               [operator 5]
        Concatenates struct_1 and  struct_2, which must  be of the  same
        type, the result also being of that type; permissible types  are
        strings, any kind of vector, lists and words. E.g.

                [1 2 3] <> [4 5 6] is [1 2 3 4 5 6]
                {a b c} <> {d e f} is {a b c d e f}
                'a ' <> 'string' is 'a string'
                "word1" <> "word2" is "word1word2"

        This operator also composes two procedures, so that

                p1 <> p2

        is a new procedure  which first runs p1  and then runs p2  (see
        the    section    Generic    Datastructure    Procedures     on
        Procedures/Closures   in   REF * PROCEDURE    for   a    fuller
        description.)

        Note that if one of the arguments  to <> is empty the result  is
        simply the non-empty argument. (Compare with * ><.)


struct1 nc_<> struct2 -> struct3                           [operator -5]
        This operator is identical to  <>, except that when struct1  and
        struct2 are lists, the  second list struct2  is joined onto  the
        end of the struct1, without  copying struct1 (which is then  the
        result.) E.g.

                vars list = [1 2 3];
                list nc_<> [4 5 6] =>
                ** [1 2 3 4 5 6]
                list =>
                ** [1 2 3 4 5 6]


packitem(list) -> item                                       [procedure]
        If list  is  a  list  of  integers,  returns  a  single  integer
        constructed by considering  list as  a list  of base-10  digits,
        e.g.

            packitem([1 3 5]) =>
            ** 135

        Otherwise, the  characters  from  all  the  items  in  list  are
        concatenated into a single word (using * dest_characters to  get
        the characters):

            packitem([cat er 'pillar']) =>
            ** caterpillar

            packitem([w a r t h o g]) =>
            ** warthog


unpackitem(item) -> list                                     [procedure]
        If item is an integer, returns a list containing all the base-10
        digits in item, as integers, e.g.

            unpackitem(135) =>
            ** [1 3 5]

        Otherwise, item should be a character object to which  * appdata
        can be applied: in  this case, the result  is a list  containing
        all the letters in item, as words of length 1:

            unpackitem("cat") =>
            ** [c a t]




------------------------------------
6  Generic Data Structure Procedures
------------------------------------

These procedures can be applied to most kinds of data structures,  that
is,  compound  items  which  can  be  considered  to  have  independent
components or  elements (which essentially includes  everything  except
numbers, ordinary procedures, and special objects like * true, * false,
* termin, * nil, etc.)

Note that each REF file on an individual data type has a section  called
Generic Data  Structure  Procedures  on datatype,  which  describes  the
action of these procedures on that particular type (for example, Generic
Data Structure Procedures on Lists in REF * LISTS).


datalength(struct) -> N                                      [procedure]
length(struct) -> N                                          [procedure]
        Returns the length of the  structure struct, i.e. the number  of
        elements it  contains. The  only difference  between length  and
        datalength is in how they treat lists: length applied to a  list
        returns the  length of  the  list (like  * listlength),  whereas
        datalength returns  2 for  the  length of  the first  pair.  For
        example:

            length("abcd") =>
            ** 4
            length({a b c d}) =>
            ** 4
            length('abcd') =>
            ** 4
            length([a b c d]) =>
            ** 4
            datalength([a b c d]) =>
            ** 2

        Other examples: the datalength  of a property  is its number  of
        entries, while  the datalength  of a  closure is  its number  of
        frozvals, etc.  If struct  is the  key of  a record  class  then
        datalength gives  the  number  of  fields  in  the  record  (see
        REF * KEYS).

        (Since length  has to  determine  what sort  of argument  it  is
        given, it is slightly more efficient to use listlength when  the
        argument is known to be a list, and datalength when known not to
        be one.)


appdata(struct, p)                                           [procedure]
        Applies the procedure p in turn to each element of the structure
        struct. (Treats lists as their first pair.)


mapdata(struct1, p) -> struct2                               [procedure]
        Applies the procedure p in turn to each element of the structure
        struct1, and uses fill  to fill a copy  struct2 of struct1  with
        the resultant values. Could be defined as:

            define mapdata(struct1, p) -> struct2;
                lvars struct1, p;
                appdata(struct1, p);   ;;; get result values
                if isword(struct1) then
                    ;;; can't use fill with words
                    consword(datalength(struct1)) -> struct2
                else
                    fill(copy(struct1)) -> struct2
                endif
            enddefine;

        Compare with * ncmapdata.


ncmapdata(struct, p) -> struct                               [procedure]
        Same as * mapdata, but does not copy its argument (and therefore
        cannot work on words.) Defined as

                fill(appdata(struct, p), struct)


copy(struct1) -> struct2                                     [procedure]
        Returns a  copy  struct2  of the  structure  struct1,  in  which
        sub-structures  are  not  copied  except  where  they  form   an
        'essential' part of the outer structure -- see the REF files  on
        individual data types. (Note in particular that copy applied  to
        a list will only copy the initial pair: use * copylist to copy a
        complete list non-recursively -- see REF * LISTS.)


copydata(struct1) -> struct2                                 [procedure]
        Copies its  argument,  and  recursively  copies  its  components
        (unlike * copy  which  only  copies  the top  level  of  a  data
        structure.) There is an error check for one-level circularity.


matchvar_instantiate(struct1)        -> struct2              [procedure]
matchvar_instantiate(struct1, flags) -> struct2
        Given a structure struct1, returns a structure struct2 in  which
        any matchvars in struct1 or  its components are replaced by  the
        values of  their corresponding  identifiers. (See  HELP * EQUAL,
        and Matchvars in REF * RECORDS for a description of matchvars).
        For example:

              vars x = "mary", y = [tom dick harry];
              matchvar_instantiate([the children of =?x are =??y]) =>
              ** [the children of mary are tom dick harry]

        This procedure only copies as  much of struct1 as necessary;  if
        struct1 or  any  of  its components  contain  no  matchvars  (or
        contain only matchvars  which are  not replaced),  that part  of
        struct2 will share structure with the original struct1.

        The optional integer  flags argument can  specify the  following
        bits (note that bits 1 and 2 are mutually exclusive):

            Bit     Meaning
            ---     -------
             0      If set,  then  only  matchvars  whose  corresponding
                    identifier is in * pop_matchvars_bound are  replaced
                    by   their   value.   Other   matchvars   are   left
                    uninstantiated.

             1      Mishap if any uninstantiated matchvar remains in the
                    structure. This includes both 'anonymous'  matchvars
                    with no corresponding  identifier (which by  default
                    are   left   alone),   as   well   as   those   left
                    by virtue of bit 0 being set.

             2      Replace any uninstantiated matchvars with  pop_undef
                    for single item (=? and  =*) or [] for  list-segment
                    (=?? and =**).

        (With the flags argument omitted, all bits default to 0.)


explode(struct) -> (item1, item2, ...,  itemN)               [procedure]
(item1, item2, ..., itemN) -> explode(struct)
        Puts the N elements of the structure struct on the stack. Except
        when struct is a list, this is the same as:

                appdata(struct, identfn)

        When struct is  a list, explode  puts the elements  of the  list
        struct on the stack, i.e. the same as

                dl(struct)

        In both  cases,  the updater  does  the opposite,  i.e.  given a
        structure struct,  fills  its N  elements  with items  from  the
        stack.


datalist(struct) -> list                                     [procedure]
        Produces a list of the elements of the structure struct. This is
        equivalent to

                [% explode(struct) %]


fill(item1, item2, ..., itemN, struct) -> struct             [procedure]
        Given an N-element structure struct, fills it with N items  from
        the stack (and also returns struct as result.) For example:

                fill(1, 2, 3, 4, initv(4)) =>
                ** {1 2 3 4}

        The only difference  between this procedure  and the updater  of
        * explode is  that the  latter treats  a list  pair as  a  list,
        whereas fill  would  treat  it  as  a  pair,  i.e.  a  2-element
        structure.


allbutfirst(N, struct) -> sub_struct                         [procedure]
allbutlast(N, struct)  -> sub_struct                         [procedure]
        These procedures both take a (simple) integer N and a  structure
        struct, which  may  be  a  list, a  word,  or  any  vector-class
        structure (such as  a string  or a vector).  They both  return a
        structure of  the same  kind with  either the  first N  elements
        (allbutfirst) or  last  N  elements  (allbutlast)  removed.  The
        structure struct must therefore have at least N elements.

        For example:

            allbutfirst(3, [cat dog mouse elephant pig horse]) =>
            ** [elephant pig horse]
            allbutlast(3, [cat dog mouse elephant pig horse]) =>
            ** [cat dog mouse]
            allbutfirst(2, "abcdefgh") =>
            ** cdefgh
            allbutlast(2, "abcdefgh") =>
            ** abcdef


last(struct) -> item                                         [procedure]
item -> last(struct)
        Where struct is a  list, a vector-class  object (e.g. string  or
        vector), or  a word,  returns  or updates  the last  element  of
        struct (which must have at least one element). For example:

            last([1 2 3 4]) =>
            ** 4
            last('abcde') =>
            ** 101

        The updater of  last can be  used to change  the last item  of a
        data structure, e.g.

            vars v = {what is the time};
            v =>
            ** {what is the time}
            "date" -> last(v);
            v =>
            ** {what is the date}

        (Note that you CANNOT update the last character in a word.)


check_item(item, check, string)                              [procedure]
        Checks item conforms  to the test(s)  specified by check.  check
        can be a procedure, or  a list of procedures. Procedures  should
        take one  argument  and return  a  boolean result  (for  example
        * isinteger and * isstring.)

        item conforms to  the tests  specified by  check if  one of  the
        procedures returns a  non-false value when  applied to item.  If
        item does  not conform  to any  of the  supplied test  a  mishap
        occurs with the message string string.

        If string is  false a mishap  message of the  following form  is
        displayed:

            ;;; MISHAP - EXPECTING types - FOUND dataword

        Where dataword is the * dataword of item, and types is a list of
        the * pdprops of the procedure(s) in check. If the pdprops  of a
        procedure starts with the substring "is" then that substring  is
        removed before the pdprops are printed.

        For example, compiling this

            vars foo = 10;
            check_item(foo, [% isstring, isword %], false);

        produces the following mishap

            ;;; MISHAP - EXPECTING STRING OR WORD - FOUND INTEGER

        check_string could have been implemented as:

            check_item(%isstring, false%)

        Also see * checkinteger and * check_string.




-------------------------------------------
7  Generic Vector/Byte Structure Procedures
-------------------------------------------

initvectorclass(n, init_item, vec_key) -> vec                [procedure]
        The purpose of  this procedure is  to enable new  vectors to  be
        initialised  with  a  given  item  (the  normal  vector   'init'
        procedures initialise each element to a fixed value.) It creates
        and returns  a new  vector of  the class  specified by  the  key
        structure vec_key (using its * class_init.) The vector will have
        n elements, each of which is initialised to the value  init_item
        (which must of course be suitable  for the kind of vector  being
        constructed.) For example, to construct a string (which is  just
        a special sort of vector) consisting of five 'a' characters do:

                initvectorclass(5, `a`, string_key)

        To construct a five element  full vector using * nil (the  empty
        list) you could do:

                initvectorclass(5, nil, vector_key)

        See REF * VECTORS for more information on vectors.


sysanyvecons(item1, item2, ..., itemN, L, cons_p) -> vec     [procedure]
sysanyvecons(cons_p, item1, item2, ..., itemN, L) -> vec
        Given  a   vector-class  constructor   procedure  cons_p   (like
        * consvector,  * consstring,  etc),  constructs  and   returns a
        vector vec of that class containing  all the items on the  stack
        EXCEPT the last L.

        The procedure cons_p may  be the last  argument (first form)  or
        the first argument (second form): in both cases, L is the length
        of the stack  before pushing  any of the  arguments. This  means
        that the first  form removes L  and cons_p from  the stack,  and
        then performs

            stacklength() - L -> N;
            cons_p(N) -> vec;

        whereas the second removes L from the stack and then performs

            stacklength() - (L+1) -> N;
            subscr_stack(N+1) -> cons_p;
            cons_p(N) -> (, vec);       ;;; erase cons_p from the stack
                                        ;;; after constructing vec

        The items item1,  ..., itemN must  be suitable for  the kind  of
        vector being constructed.

        (sysanyvecons is  used e.g.  by  the Pop-11  * cons_with  vector
        constructor,  which  saves  the   stacklength  L,  compiles   an
        expression to push  the constructor procedure  cons_p, and  then
        compiles a constructor expression {...}. It then calls

                sysanyvecons(cons_p, item1, item2, ..., itemN, L)

        to produce a vector of all the items in the {...} expression.)


move_subvector(s_sub, s_vec, d_sub, d_vec, N)                [procedure]
        Where s_vec and d_vec are any two vector-type structures, copies
        the N components  of s_vec  starting at subscript  s_sub to  the
        components of d_vec starting at subscript d_sub.

        The values  coming  out  of  the source  vector  s_vec  must  be
        appropriate for the  type of the  destination vector d_vec,  and
        d_vec must be large enough to hold them.


set_subvector(item, sub, vec, N)                             [procedure]
        Where vec is any vector-type structure, sets the N components of
        vec starting at subscript sub to have the value item (which must
        be an appropriate value for the type of vector.)


move_bytes(s_bsub, s_bytestruct, d_bsub, d_bytestruct, N)    [procedure]
        Where  s_bytestruct   and  d_bytestruct   are  any   two   'byte
        accessible' structures (as defined below), copies the N bytes of
        s_bytestruct  starting   at  byte   s_bsub  to   the  bytes   of
        d_bytestruct starting at byte d_bsub.

        In addition,  either  s_bytestruct  or d_bytestruct  may  be  an
        external pointer-class structure. In this  case the N bytes  are
        copied from/to the byte addresses contained by the pointer(s).


set_bytes(char, bsub, bytestruct, N)                         [procedure]
        Sets the N  bytes of  the byte  accessible structure  bytestruct
        starting at byte number bsub to have the value char, which  must
        be an integer from 0 to 255 inclusive.

        In  addition,  bytestruct  may  be  an  external   pointer-class
        structure. In this case the N bytes addressed by the pointer are
        set to char.




---------------------------
8  Miscellaneous Procedures
---------------------------

datafile(filename) -> structure                              [procedure]
structure -> datafile(filename)
        A facility for saving (certain kinds of) Poplog data  structures
        on disk,  and  subsequently reading  them  back in.  To  write a
        structure to disk, use;

            structure -> datafile(filename)

        Similarly, to read a structure back from disk, use:

            datafile(filename) -> structure

        The permitted  data types  are:  words, numbers,  lists,  vector
        types, record types, arrays, ordinary properties, and booleans.




-----------------------------------
9  Format of Poplog Data Structures
-----------------------------------

For most programming  purposes in  Poplog it  is not  necessary to  know
anything about the layout of data structures in the system; however,  in
certain contexts  this becomes  important  (in particular,  when  Poplog
structure are to be processed by external agents.) This section outlines
the relevant details.

As mentioned  above in  Representation  of Data  in Poplog,  a  compound
object is a pointer to a data structure, and different structure classes
are distinguished  by an  extra  field containing  a  pointer to  a  key
structure. For fixed-length structures like records the key by itself is
sufficient to describe the  structure. For variable-length objects  like
vectors, however,  the  number of  elements  must also  be  known:  this
necessitates another field to contain a vector length.

To meet these  requirements, Poplog  structures have  a 2-word  'header'
which contains the key, and, in the case of a vector, its length;  for a
record, the length word is not needed,  and so may be allocated to  hold
one  or  more  ordinary  fields.  On  the  other  hand,  data  processed
externally  will  not  normally  be  expected  to  contain  such  header
information (since  it is  concerned with  the run-time  description  of
objects, for which external programming languages don't make allowance.)

To keep both sides happy therefore, the header is effectively  'hidden',
by making it occupy not the  first two words addressed by the  structure
pointer, but the two immediately behind. Pictorially, the situation  for
records and vectors is

              -- --------------          -------------- --
              |  |  field(s)  |          |   length   |  |
        header|  |------------|          |------------|  |header
              |  |    key     |          |    key     |  |
              -- |------------|          |------------| --
             >-> |            |      >-> |            |
                 |  remaining |          |   vector   |
                 |  field(s)  |          |  elements  |

where >-> marks the location actually addressed by the pointer (i.e. the
third word of a structure.)

Thus an  external program  processing  a vector  pointer just  sees  the
elements; in the case of a record, it sees the fields that begin at  the
pointer -- but NOT  any allocated in the  spare header word. The  latter
point is important  when using  * defclass or * conskey  to specify  the
layout of a record to be processed externally, because field(s) will  be
allocated in the header word unless you prevent it. (This is done simply
by including the symbol >-> as a  dummy field in the record; >->  forces
the following fields to begin at  the pointer, and appearing first  will
therefore prevent any use of the header word.)


9.1  Byte-Accessible Structures
-------------------------------
Certain  procedures  (* move_bytes  and   * set_bytes  in  this   file,
* sysread, * syswrite, and * sys_io_control, in REF * SYSIO etc)  allow
uncontrolled 'bulk'  operations  on the  data  in structures  from  the
pointer position  onwards  (see  previous  section.)  To  prevent  such
operations using Poplog-encoded  data in  "full" fields  in a  spurious
way, or (worse still) creating spurious encoded data, these  procedures
operate only on structures which have  no such fields from the  pointer
position onwards.  A structure  satisfying this  requirement is  called
byte-accessible.

For vectors, this excludes only  "full" ones; for records, it  prohibits
anything with a "full" field except in the spare header word (i.e.  if a
"full" field is present it must come first in the record and be the only
one).

Note that in byte-subscripted operations  on these structures, the  byte
at subscript 1 is the first byte  at the pointer (as, for example,  in a
string.)



--- C.all/ref/data
--- Copyright University of Sussex 1995. All rights reserved.
