REF PROGLIST                                        John Gibson Oct 1992

       COPYRIGHT University of Sussex 1993. All Rights Reserved.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<    THE PROGLIST VARIABLE    >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Poplog provides the global  permanent variable proglist  for use as  the
input item stream by many system modules, including the Pop-11 compiler.
This  file  describes  the  procedures  and  variables  associated  with
proglist.

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

  1   Introduction

  2   Reading Items from Proglist

  3   Reading Items with Macro Expansion

  4   Proglist-Related Permanent Macros

  5   Including a File in the Current Compilation Stream

  6   Proglist State Variables



---------------
1  Introduction
---------------

A standard requirement for  compilers and other  utilities in Poplog  is
the ability to read source text in itemised (or 'tokenised') form,  that
is, to have  an input  character stream lexically  analysed into  words,
numbers, strings, etc. This  process can be  performed, for example,  by
the item repeater procedures constructed by * incharitem from  character
repeaters (see REF * CHARIO and REF * ITEMISE).

    For programs which wish to process such an input item stream, it  is
particularly convenient to do so via a dynamic list constructed from the
item repeater (see REF * LISTS for  a description of dynamic lists).  An
item can then be  obtained simply by  taking the head  of the list,  and
saved there until the next item is required (at which point the list can
be tailed). Another advantage of this method is that extra items can  be
inserted into the stream when necessary, by concatenation onto the front
of the list (e.g. for macro expansion, see below).

    Because many parts of programs may require access to the item stream
currently in use, it is also useful to define a standard location  where
the input list can be found; for this reason, Poplog provides the global
permanent variable proglist.  The list  (dynamic or  otherwise) in  this
variable is  used as  the  input item  stream  by many  system  modules,
including the Pop-11 compiler (see REF * POPCOMPILE).

    Although proglist can be processed directly, it is conventional (and
usually  more  convenient)  to  take  input  items  from  it  using  the
item-reading procedures described below.  Of these procedures,  itemread
and nextitem also provide a macro expansion facility.




------------------------------
2  Reading Items from Proglist
------------------------------

poplastitem -> item                                           [variable]
item -> poplastitem
        Contains the  last  item read  from  proglist with  readitem  or
        itemread.


readitem() -> item                                           [procedure]
        Removes the next item from proglist and returns it. If  proglist
        is null, then <termin> is  returned. The item returned is  saved
        in poplastitem.


nextreaditem() -> item                                       [procedure]
        Returns the next item from proglist, but without removing it (so
        that another  call of  nextreaditem will  return the  same  item
        again). <termin> is returned if proglist is null.


readtill(end_item) -> (item_1, item_2, ..., end_item)        [procedure]
readtill(end_list) -> (item_1, item_2, ..., end_item)
        Reads items with readitem until an item either equal to end_item
        (first  form)  or  a  member   of  end_list  (second  form)   is
        encountered. All items read, including the last, are returned.


readline() -> list                                  [procedure variable]
        The  standard  procedure  in  this  variable  reads  items  from
        proglist (using readitem) until a newline is encountered.  (This
        is done by setting popnewline true, so that newline is  returned
        as a word.) The result is a list containing all the items  read,
        excluding the newline.


pop_readline_prompt -> string                                 [variable]
string -> pop_readline_prompt
        The item in this variable (default '?\s') is locally assigned to
        popprompt during readline. See  REF * SYSIO for possible  values
        of popprompt.


requestline(prompt) -> list                                  [procedure]
        Same as readline,  but with pop_readline_prompt  locally set  to
        prompt.


rdstringto(end_item) -> string                               [procedure]
rdstringto(end_list) -> string
        Reads items with readitem until an item either equal to end_item
        (first  form)  or  a  member   of  end_list  (second  form)   is
        encountered.

        The result is  the string formed  by concatenating together  the
        printed representations  of all  the items  read, EXCLUDING  the
        last (the items are concatenated with sys_><, see REF * PRINT).


readstringline() -> string                                   [procedure]
        Reads a string of characters string up to (but not  including) a
        newline or <termin>, in the following way:

        If   proglist   is    an   unexpanded    dynamic   list,    then
        nextchar(readitem) is used to  get the characters until  newline
        or <termin> is encountered  (see REF * ITEMISE). Leading  spaces
        are ignored; a  backslash \  character may be  used to  escape a
        following newline, backslash, or leading  space when this is  to
        be included in the string. Trailing spaces are also ignored.

        Otherwise, if proglist actually contains some items already, the
        result is

                rdstringto([^newline ^termin])

        (with popnewline set true).


yesno(item) -> bool                                          [procedure]
        Prints item (using  =>) then  uses readline  to read  a line  of
        input; if the input is [yes] or [y] it returns true, if [no]  or
        [n] it returns false, otherwise it prompts for input again.


proglist_read_by(read_p) -> list                             [procedure]
        Given any  procedure read_p  which  reads items  from  proglist,
        executes read_p and returns a separate list of the items it read
        (which are removed from proglist).

        pop_syntax_only is locally set  true while read_p is  executing.
        Thus if read_p is a procedure that compiles (e.g.) Pop-11  code,
        the only effect  will be to  return the list  of items it  read,
        without actually planting any Poplog VM code.


exprread() -> list                                           [procedure]
        Returns a list of Pop-11 items constituting an expression,  read
        from proglist, for use  with LIB * FORM. See HELP * FORM.  (This
        procedure is just proglist_read_by(%pop11_comp_expr%).)


impread() -> list                                            [procedure]
        Returns a  list  of  Pop-11  items  constituting  an  imperative
        sequence separated by commas, read  from proglist, for use  with
        the form macro. See HELP * FORMS.


impseqread() -> list                                         [procedure]
        Returns a  list  of Pop-11  items  constituting an  sequence  of
        imperatives, separated  by  ",",";","=>", or  "==>",  read  from
        proglist, for use with the form macro. See HELP * FORMS.


listread() -> item                                           [procedure]
        Reads either  a  single  item from  proglist,  or  a  bracketted
        sequence of them. The outer (and nested) brackets may be  either
        [ ... ] or { ... }. (Note that this is not the same as a  Pop-11
        list or vector  constructor expression, in  that the  'evaluate'
        keywords %, ^, and ^^ are not recognised.) See HELP * LISTREAD.


numberread() -> number                                       [procedure]
        Reads and returns the next  item from proglist, which must  be a
        number.


readimp(bool) -> list                                        [procedure]
        Returns a list  of Pop-11 items  constituting an imperative  (if
        bool is true), or a sequence of imperatives (if bool is  false),
        read from proglist.


varread() -> word                                            [procedure]
        Returns a word read from proglist, for use with LIB * FORMS.




-------------------------------------
3  Reading Items with Macro Expansion
-------------------------------------

A macro is a word which is currently declared as a lexical or  permanent
identifier with identprops "macro" (see REF * WORDS, * IDENT). When such
a word is read from proglist using the procedures itemread and nextitem,
it undergoes macro expansion, that is, the word is replaced in  proglist
by a sequence  of items derived  from the value  of the identifier.  The
item actually returned by the call  of itemread or nextitem is then  the
first of these (unless  this is again a  macro, in which case  expansion
proceeds recursively until the first item is not a macro). Thus a  macro
can substitute itself in the input stream with any desired items.

    The sequence of items into which a macro is expanded depends on  its
identifier value, which may be either a procedure, a list, or any  other
item (except an undef record):

    # For a procedure, the expansion is  all the items left on the  user
      stack by calling  it (i.e. the  topmost item on  the stack is  the
      last in the  sequence). The  procedure is called  with the  next N
      items from proglist (read with itemread) as its arguments, where N
      is its * pdnargs.

    # For a  list,  the  expansion  is all  the  elements  of  the  list
      (possibly none).

    # For any other  item, the  expansion is  that item.  A mishap  will
      result if the item is an undef record (on the assumption that this
      means the macro's value is undefined).

Expansion is actually performed by collecting the items in a list  list,
and then adding them to proglist with

        list <> proglist -> proglist;

after removal of  the macro  word itself  and any  arguments. (Thus  the
original list pairs constituting proglist are not updated, which can  be
important in some contexts -- see proglist_macro_pair below.)

    Note that before checking  for a macro,  nextitem and itemread  will
attempt to  autoload any  word which  is not  currently declared  as  an
identifier (by  calling  * sys_autoload). This  permits  autoloading  of
(permanent) macros, and is also the mechanism by which autoloading takes
place in  Pop-11. (When  unwanted, this  can be  turned off  by  locally
assigning false to * pop_autoload.)

    If a macro word is required  to be read from proglist without  macro
expansion, it must be preceded by the word "nonmac" (see below).


itemread() -> item                                           [procedure]
        After  expanding  macros  (and  possibly  autoloading  undefined
        words),  returns  and  removes  the  next  non-macro  item  from
        proglist. <termin> is  returned if  proglist is  null. The  item
        returned is saved in poplastitem.


nextitem() -> item                                           [procedure]
        As for  itemread, but  does not  remove the  returned item  from
        proglist (so that another call of nextitem will return the  same
        item again).


proglist_macro_pair -> list                                   [variable]
list -> proglist_macro_pair
        As described  above, macro  expansion  always creates  new  list
        pairs to add to proglist, and does not update the original ones.
        This variable provides a means for macro procedures to  actually
        update the original proglist if they wish to.

        When a macro procedure is applied, proglist_macro_pair holds the
        list pair on proglist that actually contained the macro word (if
        the macro has no  arguments, the next pair  on proglist will  be
        the tl  of this  one).  Thus for  example, a  macro  producing a
        single item  can, as  well as  returning it  as a  result,  also
        assign it directly to

            hd(proglist_macro_pair)

        (alternatively,  it   can  do   the  latter   and  then   assign
        proglist_macro_pair to proglist, returning no result).

        Of particularly relevance in this  context are macros that  read
        characters from  the input  stream using  * nextchar, which  can
        fail to work properly with certain compilers (e.g. Pop-11)  that
        expect to be able to read  sections of proglist more than  once.
        The reason for this  is that on a  second or subsequent  reading
        the original  proglist still  contains the  macro word,  but  no
        longer has available the characters required by the macro (since
        it has been itemised ahead of  that point). Macros of this  type
        should therefore use  proglist_macro_pair to replace  themselves
        directly, so that  re-reading of the  item stream will  function
        correctly.




------------------------------------
4  Proglist-Related Permanent Macros
------------------------------------

nonmac                                                           [macro]
        Escapes the next word on proglist as a macro, so that when  read
        with nextitem or itemread the word will not be expanded. E.g. if
        proglist is

                    [nonmac foo ...]

        where "foo" is a macro, then itemread() will produce "foo".  (On
        the other hand, note that readitem() would produce "nonmac".)


#_<                                                              [macro]
>_#                                                              [macro]
        #_< implements on-the-fly macros by allowing the evaluation of a
        sequence of Pop-11 statements in the input stream. Its usage is

                    #_< statement-sequence >_#

        The statement sequence up to >_# is compiled and evaluated,  and
        any items left on  the stack in so  doing are spliced back  onto
        proglist in  place  of  the whole  construct.  For  example,  if
        proglist is

                    [ #_< 3 + 4 * 5 >_# ...]

        then itemread() will return 23. Note that >_# is simply a  macro
        that produces <termin>,  so that #_<  can compile the  statement
        sequence to <termin>; in fact, this macro is just defined as

           pop11_exec_compile(termin, pop11_comp_stmnt_seq_to, true) ->


#_IF                                                             [macro]
#_ELSEIF                                                         [macro]
#_ELSE                                                           [macro]
#_ELSE_ERROR                                                     [macro]
#_ENDIF                                                          [macro]
        These macros enable the conditional reading or skipping of items
        in proglist. Their usage is

                #_IF expression
                    item-sequence
                #_ELSEIF expression
                    item-sequence
                #_ELSEIF expression
                    item-sequence
                    ...
                #_ELSE (or #_ELSE_ERROR)
                    item-sequence
                #_ENDIF

        where the #_ELSEIF  and #_ELSE clauses  are optional, and  where
        each Pop-11  expression  is  terminated  by  a  newline  as  for
        readline (qv). The item-sequence may be empty.

        Starting from the #_IF, each  expression occurring after a  #_IF
        or #_ELSEIF is evaluated until one is found that returns a  true
        result, item sequences  following a false  result being  skipped
        without macro expansion. The sequence following the true result,
        or that following a #_ELSE  if no expression evaluated to  true,
        is then 'allowed through' in the sense that the current call  of
        itemread etc and  subsequent calls will  return these items  (if
        there is no true clause or #_ELSE then whatever item follows the
        #_ENDIF will result).

        #_ELSE_ERROR may be used instead of  a #_ELSE: in this case,  if
        no expression  in the  corresponding  #_IF or  #_ELSEIF  clauses
        evaluates to  true, the  mishap

            NO CLAUSE SATISFIED IN #_IF

        results.

        These macros may be  nested to any depth,  i.e. any of the  item
        sequences can contain further #_IF constructs.


#_TERMIN_IF                                                      [macro]
        This macro is followed by an expression like #_IF, i.e.

                #_TERMIN_IF expression

        If expression evaluates to true,  [] is assigned to proglist  to
        terminate the current item stream.

        It also clears  the internal stack  associated with #_IF,  which
        means that  no  #_IF-associated  errors  will  result  from  the
        premature end-of-file (but note  that this is NOT so for  Pop-11
        closing brackets, e.g.

            section;
            #_TERMIN_IF true
            endsection;

        would produce an error).


DEF                                                              [macro]
DEFV                                                             [macro]
        These macros enable  the status  of an identifier  to be  tested
        with (for example) #_IF.

        DEF takes an  identifier name  (either as  a word  or a  section
        pathname) and  returns  true  if  the  identifier  is  currently
        declared and has a non-false value. Otherwise it returns  false.
        E.g.

            #_IF DEF UNIX

        will satisfy the #_IF if UNIX  is declared as an identifier  and
        has  a  non-false  value.  The  test  for  being  declared  uses
        * sys_current_ident, and so works for both lexical and permanent
        identifiers.

        DEFV is similar,  but combines the  test for declaration  with a
        comparison of the identifier's value against a given number.  It
        takes three  arguments:  the first  is  an identifier  name  (as
        before), the second is one of the comparison operator names

                =   /=   <   <=   >   >=

        and the third is a (non-complex) number. It returns true if  the
        same conditions as for  DEF hold, and in  addition the value  of
        the identifier (which must be numeric) satisfies the  comparison
        with the number. E.g.

            #_IF DEFV VMS >= 5.3

        will satisfy the #_IF if VMS is declared and has a numeric value
        >= 5.3.

        (Note, however, that before doing the comparison both values are
        multiplied by 1000  and then rounded  to integers. This  enables
        floating-point values -- which may  not be quite accurate --  to
        be compared  sensibly. The  principal use  of this  macro is  in
        comparing floating-point version numbers.)

        INCLUDE * SYSDEFS defines a set of system-specific macros  (such
        as UNIX, VMS, etc) which can be used in conjunction with DEF and
        DEFV    for    controlling    conditional    compilation.    See
        HELP * SYSDEFS.




-----------------------------------------------------
5  Including a File in the Current Compilation Stream
-----------------------------------------------------

#_INCLUDE                                                        [macro]
        This macro enables the stream of  items from a given file to  be
        spliced into proglist at its current point.

        It takes  one  argument,  a  string  or  a  word  representing a
        filename, which is passed to discin to open a character repeater
        CHAR_REP for the file, e.g.

            #_INCLUDE 'foo.ph'
            #_INCLUDE baz

        Note that discin  appends pop_default_type to  a word  argument;
        #_INCLUDE locally adds an 'h' to  its current value, so that  if
        e.g. pop_default_type  is  '.p', then  the  default for  a  word
        argument to #_INCLUDE will be '.ph'.

        The  current  values  of  proglist,  cucharin,  popfilename  and
        poplinenum are then saved on a stack (-pop_#_include_stack-, see
        below), and the latter 3  variables are set to have  appropriate
        values for the new character repeater CHAR_REP. proglist is then
        set with

            pdtolist(incharitem(CHAR_REP)) -> proglist

        so that the  item returned  by the itemread,  etc which  invoked
        this macro  will  be the  first  item  of the  file.  When  this
        proglist is  exhausted, the  previously  saved values  of  the 4
        variables are unstacked  and restored,  and the  next item  read
        will be the item following the #_INCLUDE argument.

        Note that if isincharitem(itemread)  is true before proglist  is
        set, i.e.  the existing  proglist was  producing items  from  an
        incharitem repeater (see REF * ITEMISE), then the item  repeater
        constructed from CHAR_REP is  given the same itemiser  character
        types as the existing  one. Moreover, any  local changes to  the
        character types of the new one are copied back when the original
        proglist is restored. This makes #_INCLUDEing files  transparent
        to local character type changes.

        The macro include allows a search list of directories to be used
        in connection with #_INCLUDE. See HELP * INCLUDE.


include                                                          [macro]
        This macro takes one argument, i.e.

            include FILENAME

        It searches through the directories named in popincludelist  for
        an occurrence of a file with the given name, after appending, if
        necessary, an appropriate file-type  such as '.ph' as  explained
        in connection with * #_INCLUDE. include compiles the first  such
        file found, as part  of the current  compilation stream so  that
        top level lexically  scoped declarations are  accessible in  the
        file containing the include  command. This makes it  unnecessary
        to specify the full  path name of the  file to be included.  See
        HELP * INCLUDE and REF * LIBRARY for further detail.


popincludelist -> list                                        [variable]
list -> popincludelist
        This user-assignable variable is used  by the macro include.  It
        holds a list  of directories  in which to  search for  "include"
        files. See * #_INCLUDE, * include, LIB * INCLUDE.


loadinclude                                                      [macro]
        This macro behaves  exactly as  include, except  that the  given
        file is compiled in  a separate compilation  stream (as if  with
        compile), rather than being included in the current one.




---------------------------
6  Proglist State Variables
---------------------------

proglist has a number of associated global variables, some of which  are
accessible to the user, some of which are not. The complete state of the
input stream represented by proglist is returned by the active  variable
proglist_state.  A  complete  state  for  a  new  input  source  can  be
constructed with the procedure proglist_new_state, and then assigned  to
proglist_state.


proglist -> list                                              [variable]
list -> proglist
        The input list  of items  (possibly dynamic)  used by  readitem,
        nextread, itemread and nextitem, etc.


cucharin() -> char                                  [procedure variable]
        Contains the character  repeater procedure currently  associated
        with proglist. That is, if proglist  is a dynamic list which  is
        producing items from a character repeater, then cucharin is that
        repeater. When  proglist  is  not dynamic,  cucharin  will  be a
        procedure that just returns <termin> when called.

        Compilers set up  this variable when  setting up proglist  for a
        new input  stream,  e.g. with  proglist_new_state  (see  below).
        Changing this variable afterwards generally has no effect, since
        compiler procedures do not reference it again.


popfilename -> false_or_string                                [variable]
        If cucharin is a  character repeater taking  input from a  named
        file or  device,  then  this variable  contains  the  associated
        filename. Otherwise, it contains false.

        Compilers set up  this variable when  setting up proglist  for a
        new input stream, e.g. with proglist_new_state (see below).

        It is  used  in particular  by  sysprmessage, which  assumes  it
        contains the name of the file currently being compiled, and  (if
        not false), includes the line

                FILE: popfilename LINE NUMBER: poplinenum

        in mishap messages.


poplinenum -> int                                             [variable]
        If cucharin is a character repeater taking input from a file  or
        device, then  this variable  contains  the current  line  number
        within the file. It is incremented by discin character repeaters
        and charin each time a newline is read (see REF * CHARIO).

        Compilers set  this  variable  to 1  (or  as  appropriate)  when
        setting  up  proglist  for  a   new  input  stream,  e.g.   with
        proglist_new_state (see below).

        Assumed by sysprmessage  to contain the  line number within  the
        current file being compiled (cf popfilename above).


pop_#_include_stack -> stack                        [protected variable]
        This variable holds  the stack used  by #_INCLUDE, as  described
        above.

        false represents an  empty stack;  when the  stack is  non-empty
        (i.e. when the current proglist  comes from a #_INCLUDEd  file),
        its value  is  a  vector  containing the  saved  values  of  the
        proglist-related global variables, i.e.

            { ^proglist_state }

        (which includes the stack variable itself).

        Compiler startup procedures locally  set this variable to  false
        by assigning  a  proglist_new_state  for an  input  source  to a
        localised proglist_state, i.e.

            dlocal proglist_state = proglist_new_state(source);

        The  test  for  pop_#_include_stack  having  a  true  value  can
        therefore be used to determine whether the current file is being
        #_INCLUDEd or directly compiled.


proglist_state -> (item1, ..., itemN)                  [active variable]
(item1, ..., itemN) -> proglist_state
        This active variable produces all the variables associated  with
        proglist,  including  proglist  itself,  cucharin,  popfilename,
        poplinenum, pop_#_include_stack, as well  as the internal  stack
        associated with #_IF.

        NOTE that the number and  disposition of the values produced  by
        this variable are intended  to be opaque to  the user (i.e.  you
        should not assume there  are any particular  number of them,  or
        anything about  what the  values are).  The number,  meaning  or
        ordering of  the values  may change  in future  versions of  the
        system.

        proglist_state is intended to be used only in two ways,  neither
        of which conflicts with  the above: (1) to  save the state  in a
        vector, as in

                { ^proglist_state } -> save;

        (after which

                explode(save) -> proglist_state;

        will restore the state), or (2) locally to a procedure, with  or
        without an assignment from proglist_new_state, e.g.

            dlocal proglist_state = proglist_new_state(list);

        The above  is  the correct  way  to  locally assign  a  list  to
        proglist; just localising and assigning proglist itself, i.e.

                dlocal proglist = list;

        MAY work  some  of  the  time, but  will  not  necessarily  work
        correctly in  all  contexts (e.g  where  the #_INCLUDE  or  #_IF
        stacks are non-empty).


proglist_new_state(source) -> (item1, ..., itemN)            [procedure]
        For a new  input source source,  returns a set  of values to  be
        assigned to proglist_state.

        In this set, pop_#_include_stack is false and the internal stack
        associated with #_IF  is empty. The  state values for  proglist,
        cucharin, popfilename and poplinenum are derived from the source
        argument, as follows:

        If source is a list (i.e. of items), then proglist is that list.
        In this  case,  cucharin  is  a  procedure  that  just  produces
        <termin> when called, and popfilename and poplinenum have  their
        current values.

        Otherwise, source may be  either a character repeater  procedure
        directly, or an argument to be  given to discin to produce  one.
        (I.e.  filename   string,  word,   or  device   record  --   see
        REF * discin. Note that  when given a  word, discin will  append
        pop_default_type to it for the resultant filename.)

        In either  case, the  character repeater  char_rep is  then  the
        value for cucharin, and the proglist value is the dynamic list

                pdtolist(incharitem(char_rep))

        The values for popfilename and  poplinenum are derived from  the
        pdprops of  char_rep as  follows: if  the props  are a  filename
        string (as will be the case  for a discin result), then this  is
        popfilename and poplinenum is 1; if  the props are a pair,  then
        the front is taken  as popfilename and  the back as  poplinenum;
        otherwise, popfilename is false and poplinenum is 0.

        As with proglist_state, the actual number and disposition of the
        values produced by this  procedure are opaque  to the user.  The
        state produced  should only  be assigned  to proglist_state  (or
        saved in a vector, etc).



--- C.all/ref/proglist
--- Copyright University of Sussex 1993. All rights reserved.
