REF SECTIONS John Gibson Oct 1992 COPYRIGHT University of Sussex 1992. All Rights Reserved. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< SECTIONS >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< This REF file provides the why and the how behind the use of sections. i.e. creating and manipulating sections, importing/exporting identifiers, miscellaneous procedures etc. The mechanics of sections are illustrated by some examples at the end. CONTENTS - (Use <ENTER> g to access required sections) 1 Introduction 2 Pathnames 3 The section Construct 4 Global Identifiers 5 Section Procedures 6 Predicates on Sections 7 Creating/Manipulating Sections 8 Standard Sections 9 Importing/Exporting Identifiers 10 Miscellaneous 11 Examples --------------- 1 Introduction --------------- As described in REF * IDENT, a declaration of a permanent program identifier (i.e. a variable or a constant) results in the attachment of a identifier record to the corresponding word, this record maintaining the idval (or valof) and identprops of the program identifier. Program sections provide a means whereby this attachment can be made on a localised basis, i.e. the same word can be associated with different permanent identifiers in different sections of a program. (Note that the section mechanism does NOT apply to lexically-scoped identifiers, i.e. those declared with lvars or lconstant. From here on 'identifier' will always mean 'permanent identifier'.) The motivation for sections is that in writing a part of a large program (or in writing a library program or system which other people are going to use), it may be convenient to use particular words to name private identifiers on the basis of mnemonic significance. But at the same time these private identifiers should not conflict or interfere with identifiers of the same name either in other parts of the program, or that users of the library program/system will employ. (This applies particularly to frequently used variable names, e.g. "x".) For example, the mere use of a variable name in a library routine will prevent a warning message being issued for that variable when employed by a user who has forgotten to declare it as local to a procedure (assuming he has the library routine loaded). Another useful aspect of sections is that they can be cancelled. Cancelling a section simultaneously cancels all the permanent identifiers local to that section, implying that the words used to reference them (if not used elsewhere) will be garbage collected. Pop-11 sections are analagous to directories in a tree-structured file system, where the identifiers play the role of files. Just as files in different directories may have the same name, so identifiers in different sections may also; just as directories may have sub-directories, so sections may have sub-sections. Just as there is the concept of 'current directory', so there is the concept of 'current section', and the user may make any node in the section tree the current section at any time -- changing sections in this way involves the system in manipulating the identifier fields in all word records currently in the dictionary. The ability to import and export identifiers provides a facility not (usually) found in file systems. Importing an identifier named X into a sub-section B of a section A means that references to X in B refer to the identifier associated with X in A; similarily, exporting an identifier Y from B upto A means that references to Y in A refer to the identifier as declared in B. Thus the former allows references to identifiers already declared in sections above the current one, while the latter allows mew identifiers to be declared in such sections from within the current. The construction of the section tree is in terms of section records, each section record containing information about the identifiers local to that section, as well as a list of section records for sub-sections of that section. The root node of this tree is the section record in the constant pop_section, which represents the 'top-level' of the POP system, and all other sections can be reached by working downwards from this. Procedures are provided to enable the user to effect this and other manipulations on sections and identifiers at run-time (see below), as well as syntactic constructs for use at compile-time. ------------ 2 Pathnames ------------ As with directories, sections are identified by name; a 'pathname' syntax is provided to enable reference to identifiers within sections (in a manner similar to UNIX file pathnames). The word "$-" is used to separate parts of the pathname (rather than "/" as in UNIX), so that for example $-tom$-dick$-harry refers to the identifier harry in subsection dick of section tom (tom being a subsection of pop_section), while $-foo refers to the top-level identifier foo. Again analagously to UNIX, a pathname not beginning with '$-' is taken to be relative to the current section, e.g. bill$-ben means the identifier ben in the subsection bill of the current section. ------------------------ 3 The section Construct ------------------------ The section construct is the principal way of using sections when compiling programs. It has the form section <pathname> <imports> => <exports> ; <statement sequence> endsection where both <imports> and <exports> are optional sequences of words, the "=>" being omitted if there are no exports. <pathname> is a pathname as described above, but in THIS context it refers to a section, not an identifier. So section $-tom$-dick$-harry; ... endsection specifies subsection harry of subsection dick of subsection tom of pop_section, etc. In addition, the name of pop_section is <blank> (it is!), so that omitting the pathname references the top-level, thus section; ... endsection (there must be no imports or exports in this case because they don't make sense at top-level). The effect of section is to save the current section, make the named section the current, and then continue compiling until endsection is encountered, at which point the previous current section is restored. After entering the named section, section_import is called on each word specified by <imports>, and section_export on each specified by <exports> -- see under 'Section Procedures' below. (In fact, section_import and section_export are also called in each intermediate section in the specified path. This implies, e.g, that section $-tom$-dick$-harry xxx => yyy; ... endsection will import xxx from top-level down through tom and dick into harry, and export yyy from harry up through them to top-level.) --------------------- 4 Global Identifiers --------------------- Most permanent identifiers are normally required to be accessible in all sub-sections of the section in which they are declared, and thus to be imported into sub-sections without any explicit declaration to that effect. To this end, an identifier can be declared as global, meaning that it should be considered an automatic import into any sub-section of a section where it is accessible. This can be done either at run-time with sysGLOBAL (see REF * VMCODE), or at compile-time with a vars or constant statement prefixed by global, e.g. global vars x, y, z; global constant a, b, c; The keyword global can also appear in a define statement after the word "define" (but before any "vars" or "constant"). E.g. define global x(); ... enddefine; define global constant y(); ... enddefine; However, to make the continual use of global unnecessary in Pop-11, the compile_mode option :pop11 +global may be used; this automatically defaults all permanent identifiers to global. Moreover (since in practice non-global identifiers are rarely needed), this option is included in the 'macro' option :pop11 +strict used by most system and library code. If required, the :pop11 +global option can be overridden with nonglobal, which may appear anywhere that global can, e.g. nonglobal vars x, y, z; define nonglobal x(); ... enddefine; --------------------- 5 Section Procedures --------------------- These procedures allow the manipulation of sections by the user (the syntactic constructs described above being implemented in terms of these). At system startup time the current (and only) section is pop_section, which represents the 'normal' top-level of POP. New sections are then created by use of section_subsect as described below. On entering a section (by assigning to current_section), all non-imported words have their identifiers set to "undef", with the following exceptions: ¤ All system words. ¤ All words having system identifiers associated with them. ¤ All words having associated with them identifiers marked as global (this actually subsumes (2), since all system identifiers are so marked). After this, words having section-local identifiers are set appropriately. The process of entering a section actually involves 'unwinding' all sections up to the lowest common ancestor of that section and the current one, and then recursively entering all sections from there down to the given one (although the user need not be aware of this). Whenever a new identifier is declared (i.e. with vars, constant etc), this identifier is made local to the current section, unless the identifier name has been declared as an export (see below). By use of word_identifier (described below), new identifiers can be created in any section regardless of the current section context. Redeclarations of existing identifiers merely alter the information in the existing identifier record, and so do not change their section status in any way. ------------------------- 6 Predicates on Sections ------------------------- issection(item) -> bool [procedure] Returns <true> if item is a section, <false> otherwise. --------------------------------- 7 Creating/Manipulating Sections --------------------------------- section_subsect(name, sect, create) -> sub_sect [procedure] section_subsect(sect) -> sub_sect_list In the first form of the call, given a section sect, returns the subsection called name of sect (name is a word). If no such subsection currently exists, then (a) If create is true, a new subsection of sect called name is created and returned; (b) If create is <false>, the mishap NONEXISTENT SECTION occurs. In the second form, given a section sect, returns a list of all subsections of sect. section_supersect(sect) -> super_sect [procedure] Given a section sect, returns the section super_sect of which sect is a subsection, or <false> if sect is the top-level section pop_section. section_cancel(sect) [procedure] section_cancel(sect, zap_pdprops) Cancels the section sect, i.e. breaks the link to sect from its supersection (sect must not be top-level, although it's quite OK for sect to be the CURRENT section). If the optional boolean argument zap_pdprops is true, the pdprops of all procedures held in local identifiers of sect are set to <false> (providing that they are user procedures whose current pdprops is the word with which the identifier is associated -- if not the pdprops are left untouched). section_cancel also recursively applies itself (with the same value for zap_pdprops) to any subsections of sect, cancelling them too. section_name(sect) -> word [procedure] This procedure returns the name of sect, or <false> if sect is pop_section (note that the name does not include the full pathname of sect). section_pathname(sect) -> string [procedure] Returns the full pathname of sect, as a string (blank if sect is pop_section). -------------------- 8 Standard Sections -------------------- pop_section -> sect [constant] The value of this constant is the top-level section record, the root node of the section tree. pop_default_section -> sect [variable] sect -> pop_default_section This variable holds the default section to return to on doing a setpop (or when vederror is called inside VED). In other words, they both do the assignment pop_default_section -> current_section; The initial value of this variable is pop_section. current_section -> sect [variable] sect -> current_section This (active) variable holds the current section; its initial value is pop_section. ---------------------------------- 9 Importing/Exporting Identifiers ---------------------------------- section_export(word) [procedure] Declares the word word to be an export of the current section (which must not be top-level), meaning that whenever word is subsequently declared, the identifier attached to it is made local to the section above (or the section above that if it is exported from there , etc). At the same time, word is made an import to the current section; thus the identifier actually 'rises' to the highest level section it is NOT exported from, while at the same time 'sinking' down from there to the current section through all intermediate sections. If word currently has a local identifier associated with it, this 'rises' as described above and ceases to be local; if it has an associated imported identifier, then exporting has no effect unless word is cancelled and redeclared, in which case the redeclaration is exported. section_import(word) [procedure] Declares the word word to be an import of the current section (which must not be top-level), thus making available the identifier associated with word in the super-section of SECT. If word already has a local identifier associated with it, this is CANCELLED. word is automatically declared in the super-section if it is undefined there. ----------------- 10 Miscellaneous ----------------- sys_read_path(first_item, use_itemread, needsect) -> result [procedure] Reads a section/identifier pathname from the current input stream (i.e. from proglist). If needsect is <false>, the pathname is interpreted as referring to an identifier, and the appropriate word_identifier (called with CONTEXT argument "undef" -- see below) is the result. If needsect has a true value, the pathname is interpreted as a section name (all sections referenced being created if they don't exist). For any true value of needsect other than [] (nil), the section record for the target section is simply returned; however, for needsect = [] the result is instead a list of all section records in the pathname, starting with pop_section if the pathname is absolute (i.e. begins with "$-"). It is assumed that the pathname begins with (the word) first_item, which has already been read from proglist; successive items of the pathname are then read with itemread if use_itemread is true, or readitem otherwise. (If the first item has not been read then the first_item argument should be readitem() or itemread(), etc.) word_identifier(word, sect, context) -> word_id [procedure] This procedure enables sectioned identifiers to be represented by unique word records. Given a dictionary word word and a section sect, it returns a unique word word_id which has associated with it the identifier associated with word in the section sect. The word word_id is not entered in the dictionary, and so does not participate in the section mechanism; thus the identifier associated with it is always guaranteed to be that associated with word in sect (in other words word_id is a 'symbolic' representation of that particular identifier record). What is meant by 'the identifier associated with word in sect' further depends on the value of the context argument, which can take the following values: false Only identifiers strictly local to sect are considered (i.e. not including imports, either explicit ones or implicit "global" ones); <false> is returned if there is no currently associated identifier. the word "undef" Same as false, but if there is currently no local identifier associated with word, an 'undeclared' word identifier is returned (see below). anything else Imported identifiers are taken into account, i.e. the state of word as it would be if sect were the current section is considered; false is returned if there is no currently associated identifier. In all cases, the characters of the word word_id are the full section pathname of its identifier, except that top-level identifiers are not prefixed by '$-'. The case of the "undef" context argument is different from the other two in that it returns an 'undeclared' word identifier when there is no current local identifier. This word identifier will act as a vehicle for declaring word in sect, in the sense that any later attachment of an identifier to word_id (e.g. with ident_declare or sysSYNTAX, or by a direct assignment with identof, etc), will simultaneously attach that identifier to word in section sect. Conversely, a later declaration of word in sect will cause the new identifier to become attached to word_id also. [Note that in all cases, cancelling word_id with syscancel will cancel word in sect. It does not, however, actually remove the identifier from word_id, since word_id is supposed to represent that identifier uniquely. What it does do is to remove the link between word_id and word in sect, so that from the point of view of any further operations it becomes a 'stand-alone' identifier.] If the word argument to word_identifier is not a dictionary word (i.e. it is itself a word identifier, or a copied word), then word is just returned unchanged. Note that in Pop-11, any ident expression for a permanent identifier may be surrounded by word quotes to get the corresponding quoted word identifier, e.g. "ident $-mysect$-xxxx" -> word_id; In addition, "nonactive" may be used in place of "ident": "nonactive $-ved_current_file" -> pair; This returns the word identifier inside a 'nonactive pair' suitable for giving to (e.g.) sys_current_val. Either "ident" or "nonactive" may be followed by "weakref" to return the word in a 'weakref pair': "ident weakref $-mysect$-xxxx" -> pair; See REF * VMCODE fast_app_sect_idents(sect, p) [procedure] Applies the procedure p to all identifiers local to the section sect. That is, for each word having a local identifier associated with it in sect, p is called with the word and identifier record as arguments, i.e. p(WORD, IDENT) If sect is pop_section, then p is called for all words having an associated top-level identifier. If the procedure p create new words in the dictionary, or deletes existing ones, or declares or cancels identifiers in sect, exactly what p is applied to is undefined; in this case it is advisable to use a 'non-fast' version such as the following: define app_sect_idents(sect, p); lvars sect, procedure p, n, v; {% fast_app_sect_idents(sect, identfn) %} -> v; for n from 1 by 2 to datalength(v) do p(subscrv(n,v), subscrv(n+1,v)) endfor enddefine; etc. section_key -> key [constant] This constant holds the key structure for sections (see REF * KEYS). ------------ 11 Examples ------------ We will now illustrate the mechanics of sections by some examples. Suppose we declare list as a constant: constant list = [this is a list of words]; Normally, the following procedure definition will produce a mishap, because list has already been declared as a constant (and so cannot be a procedure local): define count(list); if list == [] then 0 else hd(list) + count(tl(list)) endif; enddefine; However, if we put this definition inside a section called various (if we want to make sure it's a subsection of top-level we should call it $-various) section various; define count(list); if list == [] then 0 else hd(list) + count(tl(list)) endif; enddefine; endsection; this is OK, because the local variable list used in count now has nothing whatever to do with the previous definition of list as a constant -- the word "list" is associated with different identifiers inside and outside of section various. Outside of this section, the identifier which is the local of count is inaccessible by the name 'list' (but could be accessed as 'various$-list'). On the other hand, this applies also the identifier count, i.e. it cannot be accessed outside of various, and this is probably not what we want. So if count is required to be used outside of various, we can make it an export of the section: section various => count; define count(list); ... enddefine; endsection; Thus the definition of count is treated as if it were made outside of various, while at the same time list remains internal to the section. Now on entering a section, it is NOT the case that any identifiers defined outside are automatically accessible inside. This is generally what we want, i.e that these external identifiers should not conflict with ones which are internal to the section. So in the example above, the constant list is not available inside various, and so does not conflict with the local of count. If we have another constant, vector say, and we try to access it inside section various, it will be undefined: constant vector = {1 2 3 4 5 6 7 8 9}; section various; vector=> ;;; DECLARING VARIABLE vector ** <undef vector> endsection; However, we can either make vector an explicit import of section various section various vector; vector=> ** {1 2 3 4 5 6 7 8 9} endsection; or, if we know that we are going to want to import it into any section, we could have declared it as global in the first place: global constant vector = {1 2 3 4 5 6 7 8 9}; section various; vector=> ** {1 2 3 4 5 6 7 8 9} endsection; (Note that, in the definition of count above, the system procedures +, ==, hd and tl were accessible inside various by virtue of being declared global, as all system identifiers are.) +-+ C.all/ref/sections +-+ Copyright University of Sussex 1992. All rights reserved.