Updated July 2019; see History
++PRAGMA GLOBAL_BEGIN
<map and dimx statements>
++PRAGMA GLOBAL_END
These are similar in concept to the pragmas PRIVATE_BEGIN and PRIVATE_END, except that they declare a block of variables—and possibly some instructions related to initializing those variables—intended to be visible to any other module in the program.
Although non-PRIVATE variables defined outside of functions and procedures are already global, the difference here is that the section of variables and code gets effectively moved to the start of the program (see clarification below) so that the variables are all defined and initialized before any other code that may reference them. This feature is intended to help programmers modernize old-style ++INCLUDE modules which suffer from the use of un-mapped variables, and/or which are sensitive to the order in which they are included in the main program.
Clarification: by default, the GLOBAL_BEGIN/END code is moved to the start of the program. But in some cases that may not be quite ideal, for example where the MAP statements or code require definitions from, say, SOSLIB:ashell.def. To give you that flexibility, you can specify the location where you want the global code to be inserted via a special ++INCLUDE statement:
++include $GLOBALS ! insert GLOBAL_BEGIN/END blocks here
This acts like a normal ++INCLUDE except that instead of referencing a static file, it collects up all the code in the GLOBAL_BEGIN / END blocks and creates a virtual include file on the fly. Technical note: the global blocks will actually be copied to a temporary file cmpglobals.tmp, which you can examine for debugging purposes.
For include modules with unmapped variables, the recommendation would be to add a GLOBAL_BEGIN/END block to explicitly map the variables used in the module. For example, to take an extremely simple case, imagine an include module containing a routine to close a file:
CLOSE'FILE: ! caller sets CH
CLOSE #CH
RETURN
The problem with this module is that it references a variables, CH, which is not mapped or initialized here, thus requiring the calling programs to compile without the /M switch, or to figure out how and where to map/init it. It probably should be converted to a function, passing the channel explicitly, but that would definitely require changing all of the code that uses this function, which we're trying to avoid. Without the new pragmas, to fix the unmapped variable problem, could insert a map statement into the module, but unless the module was included at the top of the program, it is likely that code that calls the module would not yet have seen the MAP statement, and thus would still get an unmapped variable reference. And if you did include it at the top of the program, you would also have to insert a GOTO statement and label to jump over the CLOSE'FILE routine, lest it get executed during the program startup. And even then, if the routine was referenced by other included modules, you could easily get into "include sequence hell", where you endlessly shuffle the sequence of ++INCLUDEs trying to come up with an order that manages to have all the variable definitions occur before they are referenced.
Another approach to solving that problem would be to split the module into two parts - a .map to be included at the top of the program, and a .bsi to be included at the bottom. That works, but introduces module clutter, which tends to encourage combining the .MAP modules, but that leads to variable definition bloat and general confusion.
With the new pragma, we can insert the following at the top of the module:
++PRAGMA GLOBAL_BEGIN
MAP1 CH,B,2
++PRAGMA GLOBAL_END
Now, when we compile it, the definition of CH will get moved to the top of the program (or to a specified location - see below) eliminating the forward-reference problem. Existing programs can just be recompiled without any other changes, unless they actually did map the CH variable, in which case that map would have to be removed. But it is likely that any such map statement would be in a common include, so you can probably just add a ++IFNMAP CH conditional to that to fix it in all cases.
Of course this is an extremely simplistic example. In a more realistic case, you may have many variables used within a BSI, some of which are truly local and should be declared PRIVATE, and others which may require some explicit initialization code. But the principle remains the same - whatever you put between the GLOBAL_BEGIN and GLOBAL_END pragmas will be made globally available to the rest of the program without you having to make any other adjustments to external code, other than recompiling the programs that use this module.
Note: the feature requires the /P (or -p) compile switch, but does not require any particular run-time version. The RUN files can even be AMOS compatible, if you stick with the /RC option.
History
2019 July, A-Shell 6.5.1664, compiler edit 911: The temporary file used to hold a GLOBAL_BEGIN/END block now uses a source-file-specific name <source>.glbi instead of the fixed name cmpglobals.inc. This resolves a conflict with running multiple simultaneous compilations in the same directory.
2014 October, A-Shell 6.1.1392: Add to A-Shell