MAINSAIL Language Manual, Chapter 11

previous   next   top   complete contents   complete index   framed top   this page unframed


11. MODULEs and Data Sections

A MODULE is the smallest separately compilable unit of MAINSAIL code. A MAINSAIL program is composed of one or more MODULEs, some of which may be contributed by the programmer and some by the MAINSAIL runtime system.

MODULEs communicate at runtime through interface fields, which are the variables and PROCEDUREs of each MODULE declared by the programmer to be accessible from other MODULEs.

A MODULE is written in the general form shown in Figure 11–1. The outer declarations sections may be empty; see Chapter 6. modNam is the name of the MODULE, enclosed in double quotes, and must be a valid MAINSAIL identifier. The name is used in the declaration of the MODULE, if the MODULE is explicitly declared (see Section 11.2). Since the runtime system uses a MODULE's name to identify it, every MODULE in a program must have a unique name. The programmer's choice of MODULE names must not conflict with the names of standard runtime MODULEs (see Appendix K).

Figure 11–1. A MAINSAIL MODULE
BEGIN "modNam"
outer declarations 1
PROCEDURE 1
outer declarations 2
PROCEDURE 2
. . .
outer declarations n
PROCEDURE n
outer declarations n + 1
END "modNam"

Since the compiler forms the output file intmod and objmod name from the MODULE name, a long MODULE name could result in a file name which is too long to be legal on some operating systems. This problem does not arise if the intmod and objmod are put into a library. It is the programmer's responsibility to deal with this situation if it arises.

The outer declarations declare all identifiers (except those predefined by MAINSAIL and those obtained from intmods; see Chapter 13) that are to be accessible from the point of declaration to the end of the MODULE, but not from any other MODULEs. The outer declarations of a MODULE m must include declarations of all MODULEs referenced by m. In addition, m must declare itself if it has any interface fields. MODULE declarations are described in Section 11.2.

A MODULE cannot contain another MODULE; i.e., MODULEs cannot be nested. All MODULEs are on equal footing; there is no explicitly declared “main” or “controlling” MODULE, although the MODULE first given control during a particular execution might be considered the “main” MODULE for that execution.

The division of a program into MODULEs is entirely up to the programmer. MAINSAIL has no portable rule by which to determine when a MODULE is too large, but each machine on which MAINSAIL is implemented may place an upper limit on the size of a MODULE it can execute. If such a limit exists, it may be found in the relevant part of the MAINSAIL System-Specific User's Guides.

Unlike many programming languages, MAINSAIL does not use a “link” step before execution. Instead, the MODULEs are brought into memory as needed during execution. The MAINSAIL runtime system provides all the facilities for intermodule communication. The programmer need never specify beforehand what MODULEs make up a program; a program is an open-ended collection of MODULEs whose identity is not determined until execution time. The dynamic binding of MODULEs provides a degree of flexibility lacking in statically linked systems.

The MAINSAIL runtime system automatically verifies that MODULE interfaces are consistent with one another when linkage between MODULEs is established; see Section 11.10.

11.1. Bound and Nonbound Data Sections

OWN variables (including outer and interface variables) of a MODULE are stored in a data structure called a data section. After an object module (the compiled form of a MODULE) has been brought into memory for execution, it is referred to as a control section. Each control section may be associated with at most one bound data section and zero or more nonbound data sections. Bound data sections are created by means of the system PROCEDURE bind; nonbound data sections are created by several forms of the system PROCEDURE new. Bound and nonbound data sections are identical in format, but the interface fields of a bound MODULE can be accessed indirectly (i.e., without using an explicit POINTER) as described below.

Data sections differ from dynamic records in that each data section is associated with a control section. A PROCEDURE field may be accessed by means of a POINTER to a data section, but not by means of a POINTER to a record; MODULEs may contain PROCEDUREs, but records may not.

Interface fields associated with bound data sections may be accessed by means of implicit MODULE pointers; such access is called indirect access. Interface fields associated with either bound or nonbound data sections may be accessed by means of explicitly declared POINTERs to the data sections; such access is called direct access.

11.2. MODULE Declaration

MODULEs communicate by means of interface fields, i.e., those variables and PROCEDUREs specified by the programmer (in MODULE declarations) as accessible by other MODULEs. Interface data fields are called interface variables and are OWN variables (see Section 6.4); i.e., they reside in the data section of the MODULE (see Section 11.6).

Unless a variable or PROCEDURE in a MODULE is explicitly declared as an interface field, it is not accessible from other MODULEs.

The outer declarations of a MODULE m must include, in any order (except that interface variables must be declared before use, and interface PROCEDUREs must be declared as interface PROCEDUREs before their bodies appear), declarations for all MODULEs of which interface fields are indirectly accessed by m (such declarations may, of course, be obtained from an intmod used by m instead of explicitly appearing in the text of m). In addition, m itself must be declared if it has any interface fields, even if they are not referenced within m, because the compiler must know the interface fields of the MODULE it is compiling. If m has no interface fields, its declaration may be omitted, in which case the compiler declares it automatically as a MODULE with no interface fields. That is:

BEGIN "m"
outer declarations        # not including one for m
...
END "m"

is equivalent to:

BEGIN "m"
outer declarations
...
MODULE m;  # default interfaceno interface variables
           # 
or PROCEDUREs
END "m"

The most common form of a MODULE declaration is:

MODULE v (declarations of interface fields)

where v is the MODULE's name. Interface fields may be variables and/or PROCEDUREs, in any order. The declaration of an interface PROCEDURE gives only its header. It serves as a FORWARD declaration (see Sections 7.13 and 16.22) for the PROCEDURE; i.e., the PROCEDURE may be called within v before its body has been seen. The PROCEDURE body must be given within the MODULE v, where the PROCEDURE is declared as usual. Interface variables of v are declared only in v's MODULE declaration; they are not redeclared in v after the MODULE declaration has been seen.

A sample MODULE declaration is shown in Example 11–2. The sample declares a MODULE named parse with several interface fields.

Example 11–2. Sample MODULE Declaration
MODULE parse (
    
INTEGER                 val,lineNum,index;
    
STRING                  token,line;
    
INTEGER ARRAY(1 TO 10)  order;
    
PROCEDURE               getToken;
    
STRING PROCEDURE        msgTxt (INTEGER page,msgNum);
    )

A MODULE m that accesses fields of a MODULE n need declare only a prefix of n's interface if it does not access all of n's fields. No error occurs (see Section 11.10), provided that m's view of n matches a prefix of n's view of itself. For example, if the MODULE n has two fields, and is declared in n as:

MODULE n (INTEGER field1PROCEDURE field2);

and the MODULE m uses only the first field (field1) of n, then n may be declared in m as:

MODULE n (INTEGER field1);

11.3. Indirect Access to Interface Fields

An interface field f of a MODULE m may be indirectly accessed with the field variable m.f (which may also be written with m in parentheses, i.e., (m).f). As described below, the simpler form f may often be used. The interface field is associated with the MODULE's bound data section. Because of the syntactic simplicity of indirect access, a MODULE's bound data section may be thought of as its “default” data section (the one used when no explicit POINTER is used).

The term “field variable” is used for both interface PROCEDUREs and interface variables.

For every MODULE m declared by means of the keyword MODULE in a MODULE n (and actually used in n), n maintains a hidden implicit MODULE pointer to m's bound data section. It is this implicit MODULE pointer that is used in indirect access to interface fields of m.

For example, if m1 is declared as:

MODULE m1 (STRING name,questINTEGER valPROCEDURE findVal)

then the interface fields of m1 can be indirectly accessed as the field variables m1.name, m1.quest, m1.val, and m1.findVal. The interface variables of m1 may be altered by other MODULEs; i.e., there are no “protected” or “read-only” fields.

m.f can be written as f if m is the current MODULE or if m is the only MODULE declared in the current MODULE with a field named f. In either case, the compiler effectively provides the m. prefix. The compiler generates the same code regardless of whether or not the abbreviated form is used (i.e., there is no efficiency penalty or advantage for including the m.).

As an example, many of the MAINSAIL system PROCEDUREs are interface fields of various system MODULEs. The programmer need not know the names of the runtime MODULEs. To call a system PROCEDURE, the programmer specifies only the PROCEDURE name. All the system PROCEDUREs have been given unique names, and hence the compiler can figure out the MODULE name. If the programmer declares an interface variable with the same name as a system PROCEDURE, the name of the system PROCEDURE alone may no longer suffice to produce an unambiguous reference. System PROCEDURE names must not be explicitly prefixed with their MODULE names, since XIDAK reserves the right to change the MODULE in which a system PROCEDURE resides.

11.4. CLASSes with PROCEDUREs and CLASSes as Prefixes of MODULEs

The fields of a MODULE can be supplied using a CLASS, with a declaration such as:

MODULE(cm

where c is a CLASS name. The MODULE declaration may declare the MODULE to be of a prefixed CLASS by adding extra fields to an existing CLASS, in the form:

MODULE(cm (declarations of additional fields)

The declaration of the MODULE PARSE of Example 11–3 is equivalent to the declaration of Example 11–2.

Example 11–3. Sample MODULE Declaration Using a CLASS
CLASS parseCls (
    
INTEGER                 val,lineNum,index;
    
STRING                  token,line;
    
INTEGER ARRAY(1 TO 10)  order;
    
PROCEDURE               getToken;
    
STRING PROCEDURE        msgTxt (INTEGER page,msgNum);
    );

MODULE(parseClsparse;

11.5. Direct Access to Interface Fields

An explicit POINTER to a MODULE's data section may be declared if the interface of the MODULE is declared as a CLASS. Access by means of an explicit POINTER to fields associated with a data section is referred to as direct access to the data section. The MODULE must have the interface specified by the CLASS of the POINTER used to access its data section; otherwise, the effects of accessing fields with the POINTER is undefined.

Both bound and nonbound data sections may be directly accessed.

The system PROCEDURE bind and some forms of the system PROCEDURE new allocate a data section instead of a dynamic record and return a POINTER to the allocated data section. These forms specify the name of the MODULE for which a data section is to be created.

Figure 11–4 shows examples of data section allocations and field variables.

Figure 11–4. Accessing Data Section Fields with a POINTER
CLASS parseCls (
    
INTEGER                 val,lineNum,index;
    
STRING                  token,line;
    
INTEGER ARRAY(1 TO 10)  order;
    
PROCEDURE               getToken;
    
STRING PROCEDURE        msgTxt (INTEGER page,msgNum);
    );

POINTER(parseClsp;

If there exists a MODULE PARSE of parseCls, p may be made to point to the bound data section of PARSE by means of:

p := bind("PARSE");

In addition, if PARSE is declared in a MODULE declaration such as:

MODULE(parseClsparse;

then PARSE can also be bound using:

p := bind(parse);

The call to bind allocates the bound data section if it has not already been allocated.

p may be made to point to a nonbound data section of PARSE by means of:

p := new("PARSE");

or, if PARSE is declared in a MODULE declaration:

p := new(parse);

The call to new always allocates a new nonbound data section.

If p is made to point to a data section of the CLASS parseCls, the following directly accessed field variables are valid:

p.val
p.lineNum
p.index
p.token
p.line
p.order
p.getToken
p.msgTxt(...)

11.6. MODULE Allocation and Disposal

The allocation of a MODULE is the allocation and clearing of its data section and the invocation of its INITIAL PROCEDURE, if it has an INITIAL PROCEDURE (see Section 11.11). A MODULE may be allocated by a call to bind or new, as shown in Figure 11–4. An indirectly accessed MODULE may be automatically allocated, as described in Section 11.9.

When a data section is disposed (see Section 33.30), MAINSAIL automatically invokes the MODULE's FINAL PROCEDURE, if there is one (see Section 11.12). When a MODULE is disposed, MAINSAIL disposes all the data sections for that MODULE, then releases the control section for the MODULE (so that if a new data section is allocated for the MODULE, the search for the MODULE's control section proceeds from scratch as described in Section 14.2). At the end of a MAINSAIL execution, MAINSAIL normally executes the FINAL PROCEDUREs associated with all data sections and then closes any open files.

The exception $disposedDataSecExcpt is raised when an attempt is made to return to a PROCEDURE invocation associated with a disposed data section.

When a MODULE is unbound (see Section 49.1), the bound data section is disposed, but the control section is not released.

11.7. Allocation of a Dynamic Record of a CLASS with PROCEDURE Fields

Allocation of a dynamic record of a CLASS c by means of new(c), where c contains PROCEDURE fields, results in a record in which the PROCEDURE fields are not valid; the compiler issues a warning message if such an allocation is performed. The effect of calling a PROCEDURE in c using such a record is undefined. PROCEDURE fields may be accessed with the POINTER only if a data section of the CLASS is allocated instead of a record.

11.8. Garbage Collection of Data Sections

Nonbound data sections are subject to garbage collection, like dynamic records and ARRAYs. Bound data sections are not garbage collected; once created, they continue to exist until explicitly unbound or until the MAINSAIL execution finishes.

11.9. Establishing MODULE Linkage

A MODULE m may at any time indirectly call an interface PROCEDURE in another MODULE n. However, m can indirectly access an interface variable in n only if a bound data section already exists for n. When a bound data section for n is created, implicit MODULE pointers to n in all MODULEs that use n are initialized. If a MODULE m is allocated and a bound data section for n exists, m's implicit MODULE pointer to n is initialized. When the implicit MODULE pointer from m to n is initialized, m is said to have linkage to n.

If checking is in effect, MAINSAIL raises the exception $unboundModuleExcpt if an attempt is made to access an interface variable of a MODULE to which linkage is not yet established (i.e., for which no bound data section exists).

In the future, MAINSAIL may support automatic establishment of linkage upon interface data access; this has not been done so far because of execution overhead considerations.

11.10. Intermodule Consistency Checking

If a MODULE A indirectly accesses a MODULE B, the compiler requires that A include a MODULE declaration for B and that B include a MODULE declaration for itself. When A gets linkage to B, MAINSAIL checks these MODULE declarations for consistency. A MODULE inconsistency is detected if A's view of B is not a prefix of B's view of itself. If the interfaces are inconsistent, an error occurs.

The consistency check verifies that the declarations of corresponding interface variables and PROCEDUREs are compatible. Corresponding interface variables must have the same data type; if the variables are ARRAYs, they must have the same bounds. Corresponding interface PROCEDUREs must have equivalent declarations; corresponding parameters must be of the same data type, and must be both USES, both MODIFIES, both PRODUCES, or both $REFERENCE. It is not checked that corresponding identifiers have the same name. Currently, it is also not checked that corresponding POINTERs have the same CLASS. Such checks may be added in future versions of MAINSAIL.

11.10.1. Detailed Intermodule Consistency Checking Rules, with an Example

The complete rules for interface inconsistency are these, given a MODULE P (the producer) that provides an interface, and a MODULE U (the user) that accesses PROCEDUREs or variables in P:

  1. P must provide at least the interface that U expects to see. That is, the declaration of P within P must provide every field that is in the declaration of P within U.

  2. The fields of P that U knows about must be declared exactly the same in both P and U. For data fields, data types, ARRAY sizes, POINTER CLASSes, etc., should be the same. For PROCEDURE fields, the same parameter names must appear in the same order and have the same data types and qualifiers (although parameter names need not match).

  3. The fields of P that U knows about must be declared in the same order in both P and U.

  4. P may provide additional fields that U does not know about, but those fields must appear at the end of P's declaration, after all the fields that U knows about.

For example, assume the MODULE U contains (or sourcefiles, or restores from an intmod that includes):

MODULE p (
    
INTEGER i;
    
STRING s;
    
PROCEDURE proc (REAL rMODIFIES BITS b);
);

Then if P contains a declaration like:

MODULE p (
    
INTEGER i;
    
STRING s;
);

that violates rule #1 above (P does not provide everything U knows about; specifically, it does not provide proc).

If P contains a declaration like:

MODULE p (
    
LONG INTEGER i;
    
STRING s;
    
PROCEDURE proc (REAL rMODIFIES BITS b);
);

rule #2 is violated (the data type of i does not match in P and U).

If P contains a declaration like:

MODULE p (
    
INTEGER i;
    
STRING s;
    
PROCEDURE proc (REAL rBITS b);
);

that also violates rule #2 (the second parameter of proc is declared as a MODIFIES in U but not in P).

If P contains a declaration like:

MODULE p (
    
STRING s;
    
INTEGER i;
    
PROCEDURE proc (REAL rMODIFIES BITS b);
);

that violates rule #3 (s and i are in a different order in P's and U's declarations).

However, it is permissible under rule #4 for P to contain a declaration like:

MODULE p (
    
INTEGER i;
    
STRING s;
    
PROCEDURE proc (REAL rMODIFIES BITS b);
    
POINTER(xyzptr;
);

The field ptr is not declared in U's view of P, but it appears in the interface after every field that U knows about, so there is no problem.

11.11. INITIAL PROCEDURE

Each MODULE may contain a single typeless and parameterless PROCEDURE that is to be called whenever a data section for the MODULE is allocated. This PROCEDURE is qualified with INITIAL, in accordance with the syntax described in Section 7.11. The INITIAL PROCEDURE may also be called explicitly.

The “main” or “top-level” MODULE of a program (the one specified to the MAINSAIL executive as the MODULE to gain control first) must have an INITIAL PROCEDURE, or it returns immediately without performing any action. The execution of the top-level MODULE's INITIAL PROCEDURE leads to execution of the entire program.

A MODULE need not have an INITIAL PROCEDURE. When a MODULE not intended to be used as a top-level MODULE has an INITIAL PROCEDURE, it usually performs initialization of the MODULE's outer and interface variables.

The programmer does not have to give the INITIAL PROCEDURE a name, in which case the compiler supplies the name initialProc. That is:

INITIAL PROCEDURE;
BEGIN ... END

is equivalent to:

INITIAL PROCEDURE initialProc;
BEGIN ... END

The INITIAL qualifier need be specified only in a PROCEDURE declaration that includes a PROCEDURE body; i.e., it does not have to be given in FORWARD or interface field declarations. However, if it is given in a FORWARD or a field declaration, it must also be given in the body declaration.

11.12. FINAL PROCEDURE

Each MODULE may contain a single typeless and parameterless PROCEDURE that is automatically invoked when the MODULE is disposed. This PROCEDURE is qualified with FINAL, in accordance with the syntax described in Section 7.11. The FINAL PROCEDURE may also be called explicitly.

FINAL PROCEDUREs are often used to dispose of dynamic ARRAYs and data sections that are no longer needed, to release scan bits, or to close files that should not be left open. A FINAL PROCEDURE often “undoes” the work of the INITIAL PROCEDURE.

The programmer does not have to give the FINAL PROCEDURE a name, in which case the compiler supplies the name finalProc. That is:

FINAL PROCEDURE;
BEGIN ... END

is equivalent to

FINAL PROCEDURE finalProc;
BEGIN ... END

The FINAL qualifier need be specified only in a PROCEDURE declaration that includes a PROCEDURE body; i.e., it does not have to be given in FORWARD or interface field declarations. However, if it is given in a FORWARD or a field declaration, it must also be given in the body declaration.

When a MAINSAIL execution terminates, all data sections are disposed, and all open files are closed. The order in which data sections are disposed is unspecified. The programmer must not access a data field of another MODULE in a FINAL PROCEDURE without first ensuring that the other MODULE is bound. The programmer must not perform I/O to a file in a FINAL PROCEDURE without ensuring that the file is open. Bugs that are difficult to track may occur because of dependencies on the order of execution of FINAL PROCEDUREs.

Currently, when a data section is collected by the garbage collector, the MODULE's FINAL PROCEDURE is not executed. This behavior is subject to change.

11.12.1. FINAL PROCEDUREs and $exitingMainsail

MAINSAIL FINAL PROCEDUREs are called when a data section for the MODULE containing the FINAL PROCEDURE is disposed, and also when a MAINSAIL execution finishes.

It is sometimes useful in a FINAL PROCEDURE to determine why the FINAL PROCEDURE is being called. FINAL PROCEDUREs that are called because MAINSAIL is exiting do not need to do certain kinds of cleanup, particularly disposal of data structures, since these data structures will go away as soon as MAINSAIL exits anyway. Disposal of a large, complicated data structure can sometimes take a noticeable amount of time and serves no purpose if its only effect is to delay MAINSAIL's exit. On the other hand, FINAL PROCEDUREs called when MAINSAIL is not exiting should clean up any data structures they have allocated, since MAINSAIL execution will continue and the presence of the data structures may impair subsequent performance.

FINAL PROCEDUREs that need to determine whether they are being called because MAINSAIL is exiting can call the BOOLEAN macro $exitingMainsail, which becomes set on entry to the system PROCEDURE exit. If $exitingMainsail returns TRUE, the FINAL PROCEDURE is being called because MAINSAIL is exiting. For example:

FINAL PROCEDURE;
IF NOT $exitingMainsail THEN
    
disposeMyComplicatedDataStructure;

11.12.2. How to Avoid Problems During a Call to exit

In general, it is unwise to call an interface PROCEDURE of a MODULE after the MODULE's FINAL PROCEDURE has been called. MODULEs are typically written so that FINAL PROCEDUREs deallocate outer data that is expected to be initialized during a call to any interface procedure of the MODULE.

Except during a call to exit, it is not possible to call a MODULE's interface PROCEDUREs after the MODULE's FINAL PROCEDURE has finished executing, because the MODULE's data section is then immediately deallocated by the runtime system. However, during a call to exit, the FINAL PROCEDUREs of all data sections currently in memory are called in an unspecified order, and the data sections are not deallocated after the FINAL PROCEDURE is called. Thus, interface PROCEDUREs corresponding to data sections that have been deinitialized are still available to be called, even though it may no longer make sense to do so.

Consequently, when $exitingMainsail is set, FINAL PROCEDUREs should be very cautious about making intermodule calls (except to the MAINSAIL runtime system MODULEs, which have been carefully written so that calls to them during a call to exit are not a problem). You should not call an interface PROCEDURE in any MODULE for which the FINAL PROCEDURE has been called, unless you know that that MODULE has been written to handle the situation. Any MODULE that might be called during a call to exit, and which has outer data that should be initialized during a call to any interface PROCEDURE, should include in its interface a flag variable to tell potential callers that its FINAL PROCEDURE has already been called. When $exitingMainsail is set, do not make calls to the MODULE if its flag is set.

In addition, any PROCEDUREs called by the FINAL PROCEDURE while $exitingMainsail is set must also check whether the target of an intermodule call has already had its FINAL PROCEDURE called.

A MODULE CALLEE might set a flag so that a MODULE CALLER can avoid calling it when $exitingMainsail is TRUE as follows:

BEGIN "calleeHdr"

$DIRECTIVE "NOOUTPUT"; SAVEON;

MODULE callee (
    
BOOLEAN finalProcCalled;
    
PROCEDURE interfaceProc;
);

END "calleeHdr"
##########################################################
BEGIN "caller"

RESTOREFROM "calleeHdr";

...

FINAL PROCEDURE;
IF NOT $exitingMainsail THENB
    ... 
normal cleanup... END
EB  # Cleanup that must be doneeven during exit
    ...
    
IF NOT callee.finalProcCalled THEN
        
callee.interfaceProc END;

END "caller"
##########################################################
BEGIN "callee"

RESTOREFROM "calleeHdr";

...

FINAL PROCEDURE;
BEGIN
...
finalProcCalled := TRUE;
END;

END "callee"

11.13. GENERIC PROCEDUREs as Field Variables

GENERIC PROCEDUREs may be used as field variables; i.e., in p.f or m.f (p is a POINTER and m a MODULE), f may be a GENERIC PROCEDURE name. The GENERIC name is substituted according to the usual rules (see Section 7.16) for f. For example, given the declarations:

CLASS c1 (PROCEDURE p1 (INTEGER i));

PROCEDURE p2 (REAL r);

CLASS c3 (PROCEDURE p3 (STRING s));

GENERIC PROCEDURE p "p1,p2,p3";

POINTER(c1ptr1;
POINTER(c3ptr3;

the code:

ptr1.p(2);
p(2.0);
ptr3.p("2")

would be equivalent to:

ptr1.p1(2);
p2(2.0);
ptr3.p3("2")

Note that behavior is undefined if a GENERIC PROCEDURE p has a field of a CLASS c as an instance and c also has a field named p; i.e., the behavior of the following is undefined:

CLASS c (PROCEDURE p1PROCEDURE p);
GENERIC PROCEDURE p "p1";
...
POINTER(ccp;
cp.p; # undefined

11.14. Control Sections and MODULE Swapping

Whenever a data section is allocated for a MODULE, the corresponding objmod is brought into memory if necessary; an objmod brought into memory for execution is called a control section. Only the currently executing MODULE's control section need be in memory; MAINSAIL automatically swaps out control sections for which there is not enough memory. This may be thought of as an “automatic overlay” facility. MAINSAIL attempts to keep the most recently used control sections in memory. MAINSAIL does not swap out any data structures other than control sections; thus, MAINSAIL supports “virtual code space” but not “virtual data space”.

When a control section that was obtained from an individual objmod file is first removed from memory, it is written to a swap file. When a control section obtained from a currently open objmod library is removed from memory, it is not written to the swap file, since it may be read back in from the objmod library.

The name of the swap file on most systems is of the form swpxxx.tmp, where xxx is an integer. This file name format is subject to change and may be different on some systems.

11.14.1. Deletion of Swap Files

If MAINSAIL opens a swap file during execution, it is deleted when MAINSAIL returns normally back to the operating system. The swap file is opened with the delete bit set so that when it is closed, it is deleted.

If MAINSAIL does not exit normally, e.g., if the process is killed because the user typed a terminal interrupt character, then the logic that closes all open files is not executed, and hence the swap file is not deleted. This also happens if the process exits to the operating system while in foreign code.

11.15. Compilation of Several MODULEs in One File

More than one source MODULE can appear in the same file. If no text (other than blank, tab, end-of-page, and end-of-line characters) appears between the final END of one MODULE and the BEGIN of the following MODULE, the MODULEs are compiled just as if they were separated into different files and each file compiled separately.

Symbols that are defined between the END of one MODULE and the BEGIN of the next (with DEFINE or REDEFINE) normally belong to the preceding MODULE, not the following. The compilation of a new MODULE does not begin until its BEGIN is seen (if something other than BEGIN or a macro definition or compiler directive is seen, it is treated as end-of-file). Compiling a file with the following contents therefore gets an error:

REDEFINE moduleName = "firstM";

BEGIN moduleName
END moduleName

REDEFINE moduleName = "second";

BEGIN moduleName
END moduleName

since the second definition of moduleName belongs to the first MODULE; when the second BEGIN is seen, the compilation of the second MODULE is begun, and the previous definition of moduleName is forgotten. The use of moduleName therefore results in a compiler error message.

Symbols may be defined after the initial BEGIN of a MODULE. The above could be rewritten as:

REDEFINE moduleName = "firstM";

BEGIN moduleName
END moduleName

BEGIN REDEFINE moduleName = "second";
    
moduleName
END moduleName

This would produce two MODULEs, FIRSTM and SECOND, without error. The $GLOBALREDEFINE directive could also be used in place of REDEFINE in the original example to make it compile correctly.

11.16. Nonbound-Invocation MODULEs

Temporary feature: subject to change

A MODULE may be a nonbound-invocation MODULE, meaning that when $invokeModule (see Section 38.14) is called it creates a nonbound data section rather than a bound data section (if the MODULE's data section is allocated with bind or by indirect access of an interface PROCEDURE, a bound data section is created, as usual). This allows several invocations of a MODULE to coexist, provided that they are created by $invokeModule.

A MODULE is specified to be nonbound-invocation MODULE with the compiler subcommand UNBOUND. This subcommand may be used in a $DIRECTIVE directive; i.e., a MODULE containing:

$DIRECTIVE "UNBOUND";

is specified to be a nonbound-invocation MODULE.

In the MAINSAIL compiler, the MODULE COMPIL is a nonbound-invocation MODULE (all the other compiler MODULEs are also allocated as nonbound data sections, created with new). If, during a compilation, the compiler is invoked (e.g., with a call to $invokeModule, or at an Error response: prompt, or from MAINEX or MAINEDIT, all of which use $invokeModule), a new instance of the compiler is created that does not interfere with any other instance. If a bound data section of COMPIL were used, then a second invocation of the compiler would destroy the first, since both would be using the bound instance of COMPIL.

XIDAK is considering other, more flexible, approaches to allowing simultaneous invocations of the same program.


previous   next   top   complete contents   complete index   framed top   this page unframed

MAINSAIL Language Manual, Chapter 11