previous next top contents index framed top this page unframed
A compiler directive may occur wherever a declaration or statement may occur (except that BEGINSCAN must be the first thing on a page), and must be terminated with a semicolon.
16.1. MESSAGE
MESSAGE is a compiler directive that writes a
STRING at compiletime
to a new line of logFile.
The form of a MESSAGE directive is MESSAGE c; where c is a STRING constant expression, or MESSAGE c,c2;, where c is an arbitrary STRING constant expression and c2 is one of "error" or "warning" (case is ignored). c is written to logFile when the MESSAGE directive is encountered during compilation; if c2 is present, then c is included in a warning message if c2 is "warning" or an error message if c2 is "error". For example, to give a compiletime error message if the character set is unknown:
IFC $charSet = $ascii THENC ...
$EFC $charSet = $ebcdic THENC ...
ELSEC MESSAGE "Unknown char set","error"; ENDC
The form of a SOURCEFILE directive is SOURCEFILE c; where c is a STRING constant expression that specifies a file name. SOURCEFILE causes the compiler to save the state of the current source file (that is, the one it is currently compiling) and then begin compiling the file named by c, as if its text had appeared in place of the directive. When compilation of the file c is complete, compilation resumes immediately following the SOURCEFILE directive.
A file that was itself obtained with SOURCEFILE may also use SOURCEFILE to get additional files; i.e., SOURCEFILEs may be nested.
A SOURCEFILE name may be read from cmdFile by means of an interactive define (see Section 15.4):
DEFINE defFile "Name of file with definitions: ";
SOURCEFILE defFile;
The SOURCEFILE directive may
be used to maintain a set of declarations
common to a number of MODULEs in a single file that is sourcefiled
by all of them.
An alternative (and often more flexible) way to maintain such
declarations is by using intmods; see Chapter 13.
16.3. CHECK, NOCHECK, and CHECKING
CHECK, NOCHECK, and
CHECKING govern the generation of code to
check certain
conditions at runtime that cannot be determined at compiletime.
They are described in detail in Chapter 17.
16.4. $DIRECTIVE
The directive $DIRECTIVE permits certain compiler subcommands
and other directives to
be specified inside the source text for a MODULE. Its format is:
$DIRECTIVE s1,...,sn;
where the si are STRING constants that are the names of compiler subcommands (followed by arguments, if applicable). The case of the the compiler subcommands in si does not matter. The subcommands currently accepted by $DIRECTIVE are:
The $DIRECTIVE directives that are not compiler subcommands are:
HIDEPROC is described in Section 16.4.1. DATETIMECHECK and NODATETIMECHECK are described in Section 16.4.2. MAKEMODULENOTVISIBLE, MAKEMODULEVISIBLE, MAKENOTVISIBLE, MAKEVISIBLE, and OPENMODULE are described in Chapter 13. PUSHACHECK, POPACHECK, PUSHCHECK and POPCHECK are described in Chapter 17.
$DIRECTIVE directives apply only to the current MODULE, i.e., are not sticky.
The directives:
$DIRECTIVE "CHECK";
and:
$DIRECTIVE "NOCHECK";
are equivalent to:
CHECK;
and:
NOCHECK;
respectively.
The current setting of many $DIRECTIVE directives can be examined with the system PROCEDURE $compileTimeValue; see Section 32.48.
16.4.1. HIDEPROC Directive
The directive:
$DIRECTIVE "HIDEPROC";
can be given inside a PROCEDURE, in which case the PROCEDURE is not compiled debuggable, does not take part in disassemblies or statement count listings, and does not have timing code inserted.
This same directive can be put outside of a PROCEDURE, in which case it applies to all subsequent PROCEDUREs for that compilation. The companion directive NOHIDEPROC turns HIDEPROC off.
This directive is useful for well-debugged PROCEDUREs that are compiled into an intmod (or compiled as FORWARD PROCEDUREs from a source file) for which the source file is not available at a site where programmers are using the debugger to step through code that calls the PROCEDUREs. The debugger will not attempt to step into HIDEPROC PROCEDUREs, and therefore will not issue any error messages for missing source files.
You may find this directive useful, e.g., if you ship a library of
PROCEDUREs as an intmod
(without the source code) to customers who are
developing MAINSAIL programs.
16.4.2. DATETIMECHECK/NODATETIMECHECK Compiler Directives
By default, when MAINSAIL opens a supporting intmod (because it is
used by another intmod), it issues a warning message if a different
revision of the supporting intmod (as indicated by the date and time
of compilation of the supporting intmod) was used when the requesting
intmod was created.
A compiler directive can be used to suppress this warning in
cases where you know that no incompatible changes have been made to
the supporting intmod.
The $DIRECTIVE directives DATETIMECHECK and NODATETIMECHECK, when appearing in a supporting intmod, control whether a warning message is given for that intmod. DATETIMECHECK is the default; when it is in effect for an intmod and the intmod is used as a supporting intmod, MAINSAIL performs date/time checking. NODATETIMECHECK turns off DATETIMECHECK, causing MAINSAIL to suppress the date/time check when the intmod is opened as a supporting intmod.
NODATETIMECHECK should not be specified for a MODULE if any
changes have been made to it that are incompatible with existing
intmods that use it as a supporting intmod (see Section 13.9.1).
16.5. SAVEON and RESTOREFROM
SAVEON and RESTOREFROM allow symbols from an intmod
to be used during a compilation; see Chapter 13.
16.6. ENCODE
The ENCODE directive is used with the Foreign Language Interface
(FLI, described in Chapter 7 of the MAINSAIL Compiler User's Guide)
to supply target-dependent names to be written to the
generated assembly language file in place of the MAINSAIL
PROCEDURE identifiers.
The FLI ordinarily uses some transformation (as specified in the
appropriate operating-system-specific MAINSAIL user's guide)
of a MAINSAIL PROCEDURE name as the foreign PROCEDURE name.
In some cases the foreign name cannot be derived from the default
transformation.
The ENCODE directive allows the
programmer to supply an arbitrary
STRING as the foreign PROCEDURE name.
The form of the ENCODE directive is:
ENCODE p1 s1, ..., pn sn;
where the pi are interface PROCEDURE identifiers and the si are STRING constants. The STRING si is used as the foreign PROCEDURE name corresponding to pi when pi is compiled with the FLI compiler.
This directive:
ENCODE streamPutRec "stream_Put$Rec";
makes streamPutRec is the MAINSAIL PROCEDURE identifier used for the foreign PROCEDURE stream_Put$Rec. The FLI code generator outputs stream_Put$Rec to the assembly file as the name (label) of the foreign PROCEDURE.
The FLI is further described in the
Chapter 7 of the MAINSAIL Compiler User's Guide.
16.7. $GLOBALREDEFINE
Sometimes it is useful to carry over information from one
compilation to the next (within the same compiler session).
This can be accomplished with the keyword
$GLOBALREDEFINE, which introduces
a global macro definition.
The syntax and semantics of
$GLOBALREDEFINE are just like those
of REDEFINE, except that the defined identifiers
are entered into a global symbol table that persists from one
compilation to the next in the same invocation of the compiler.
A macro defined in one MODULE can be accessed in a
subsequently compiled MODULE.
If an identifier has been defined in a global definition, then a DEFINE or REDEFINE of the identifier defines or redefines a non-global (local to the current MODULE or PROCEDURE) occurrence of the identifier. Subsequent references to the identifier (within the scope of the non-global definition) reference the non-global definition. If the non-global definition is local to a PROCEDURE, then after the body of that PROCEDURE the global definition is once more visible.
Compiler subcommands are available for doing global redefinitions and also removing identifiers from the global symbol table.
Compiling the following file compiles into an indefinite number of empty MODULEs named FOO1, FOO2, FOO3, etc:
IFC NOT DCL(modNum) THENC
$GLOBALREDEFINE modNum = 1;
ELSEC
$GLOBALREDEFINE modNum = modNum + 1;
ENDC
$GLOBALREDEFINE modName = "foo" & cvs(modNum);
BEGIN modName
END modName
SOURCEFILE $thisFileName;
The argument to DSP or $LDSP is a field reference, where a field reference is:
For example, given the declarations:
MODULE m (INTEGER i);
CLASS c (STRING s);
CLASS d ($RECORD(c) r);
the following calls to DSP are legal (the same arguments would be permitted to $LDSP):
DSP(i) # assuming no other identifier i in top-level scope
DSP(m.i) # same as DSP(i)
DSP(c.s)
DSP(d.r)
DSP(d.r.s)
XIDAK reserves the right to change the layout of record
and data section fields in memory, so always use DSP or $LDSP
if you need to determine the offset of a field, rather than
hardwiring the offset.
16.9. $sizeOfField
$sizeOfField(field reference) returns a LONG INTEGER
for the size of its
field reference
argument;
the field reference argument may have the same format as arguments
to DSP (see Section 16.8).
If the field reference specifies a dynamic ARRAY, the size of a POINTER is returned (since a dynamic ARRAY field is implemented as a POINTER). If the specified field is an inplace record or inplace ARRAY, the size of the entire record or ARRAY is returned.
For example, given the declaration:
CLASS cls (
INTEGER $INPLACEARRAY(1 TO 10) ipAry;
LONG INTEGER(2) ARRAY(1 TO 10) dyAry;
$RECORD(c) rec;
LONG INTEGER(-2) i;
LONG INTEGER(-4) j;
);
then:
$sizeOfField(cls.ipAry) = cvli(10 * size(integerCode))
# assuming no extra padding
$sizeOfField(cls.dyAry) = $lSize(pointerCode)
$sizeOfField(cls.rec) = $lSize(c)
$sizeOfField(cls.i) = 2
For example, given the declarations:
CLASS cls (
INTEGER $INPLACEARRAY(1 TO 10) ipAry;
LONG INTEGER(2) ARRAY(1 TO 10) dyAry;
$RECORD(c) rec;
LONG INTEGER(-2) i;
LONG INTEGER(-4) j;
);
ADDRESS(cls) a;
then:
$sizeOfValue(a.ipAry) = $sizeOfField(cls.ipAry)
$sizeOfValue(a.dyAry) = $sizeOfField(cls.dyAry)
$sizeOfValue(a.rec) = $sizeOfField(cls.rec)
$sizeOfValue(a.i) = $sizeOfField(cls.i)
$sizeOfValue(a.i + a.j) = $lSize(longIntegerCode)
$LEGALNOTICE s;
where s is any STRING constant expression,
is used to specify a legal notice.
Only the first $LEGALNOTICE text encountered in
a MODULE's source text
is put into the output file(s).
$LEGALNOTICE texts from referenced intmods are not put into the
object file; it must appear in the source file when it is compiled.
A semicolon is required after s.
16.12. Conditional Compilation: IFC, THENC, $EFC,
ELSEC, and ENDC
Conditional compilation allows the programmer to specify under what
conditions indicated parts of the source file are to be compiled or
ignored.
The conditional:
IFC c THENC text1 ENDC
causes the compiler to compile text1 if c (a constant expression evaluable at compiletime; see Section 2.5) is non-Zero, and to ignore text1 otherwise. text1 is any source text that is valid (e.g., statement(s), declaration(s), macro definition(s)) where the conditional appears. THENC separates the condition c from the text to be conditionally compiled, and ENDC marks the end of that text.
A sample conditional is:
IFC doDebug THENC ttyWrite("current value is ",val); ENDC
The ttyWrite ... is compiled if doDebug is non-Zero; otherwise, it is ignored.
The general conditional form is:
IFC c1 THENC text1
{$EFC c2 THENC text2
{$EFC c3 THENC text3
...
{$EFC cm THENC textm}}}
{ELSEC textn}
ENDC
The ci are constant expressions evaluable at compiletime. If c1 is non-Zero, then text1 is compiled; otherwise, if c2 is present and non-Zero, then text2 is compiled; otherwise, if c3 is present and non-Zero, then text3 is compiled, etc. If none of the ci is non-Zero, and ELSEC is present, then textn is compiled. The texti that are not compiled are ignored.
“Ignored” text is really scanned (except that macros are not expanded, and compiler directives are ignored) but not parsed, which means that basic constructs such as constants must be properly constructed, and IFCs, $EFCs, ELSECs, and ENDCs must be properly matched. Otherwise, the text need not be syntactically correct.
IFCs may be nested to any depth. That is, constructs such as the following are allowed:
IFC c1 THENC
...
IFC c2 THENC text1 ELSEC text2 ENDC
...
ELSEC text3 ENDC
If c1 is Zero, then text3 is compiled (the rest of the conditional is scanned, but not parsed). If c1 and c2 are both non-Zero, then text1 is compiled. If c1 is non-Zero but c2 is Zero, then text2 is compiled.
The C in IFC, $EFC, THENC, ELSEC,
and ENDC stands for “conditional”.
16.13. $CASEC: Compiletime Case
$CASEC provides for compiletime case selection,
and is useful as a shorthand for some forms of IFC directives.
The syntax is similar to that of the CASE statement:
$CASEC x OF
[x1] text1
[x2 TO x3] text2
[x4][x5] $BEGINC text3 ENDC
[ ] text4
ENDC
OFB may be used in place of OF (it does not take a matching END); OFB and OF are therefore exactly equivalent in this context.
16.13.1. Selectors
The case selection expression x
is a constant expression of any data
type; it need not be an INTEGER as it would for a
CASE statement.
All the expressions
used in the case selectors
(x1 through x5) must be of the same data type
as x.
The bracketed selectors are evaluated in the order encountered, and as soon as one occurs that matches (see Section 16.13.2) the selection expression, the corresponding text is gathered into a STRING, the remainder of the $CASEC directive (down to the terminating ENDC) is discarded, and then the gathered text is compiled. The selected text is terminated by a “bare” left bracket (see Section 16.13.3) or ENDC.
The catchall selector [] matches any selection expression. All
selections after it are ignored, so it should come last (this
differs from the treatment of the catchall selector in the
CASE statement).
A selector of the form [a TO b]
matches x depending on the data type of x, a,
and b (all must be the same type) according to the following
rules:
The above computations are carried out using the host
machine characteristics; avoid $CASEC if cross-compiling
with non-portable values for the case selection expression or
any case selector expression.
This causes the compiler not to treat the left bracket as the start of
the next selector. If the
$BEGINC-ENDC pair had been left out of the
above example, the compiler would have gathered
b := bAry as the text
corresponding to [bitsCode], and considered [k] to be the next selector
(with just ; as its selected text),
which would probably have caused a syntax error.
The gathering of the selected text applies to the text after
any macro parameters have been replaced with their arguments. If any of
the text contains macro parameters which could possibly be passed an
argument with a bare left bracket, the text (or at least each such macro
parameter) must be enclosed in a $BEGINC-ENDC pair
(it never hurts to enclose the text in a $BEGINC-ENDC pair).
$DONEC may be used in a
$DOC body to terminate the iterations. The
compiler discards the remainder of the loop body and resumes compilation
beyond the ENDC matching the terminated $DOC.
$CONTINUEC may be used in a $DOC body to continue with the next
iteration. The compiler resumes compilation at the top of the loop
body (immediately after the $DOC).
By default, $DONEC and $CONTINUEC apply to the innermost
$DOC loop. A
STRING constant name may be associated with a $DOC and used by
$DONEC or $CONTINUEC within the $DOC
body to terminate or continue the named loop. For example:
The name must be enclosed in
parentheses, and the left parenthesis must immediately follow the
keyword (with no intervening text, not even white space;
otherwise, the parenthesized name is considered part of the
iterated text).
Unlike ENDs associated with
named DOs, a name cannot be
associated with a matching ENDC.
Specifying the null STRING is equivalent to
not specifying a name, so if used with a $DONEC or
$CONTINUEC, it
specifies the innermost loop.
Examples:
var is an iteration identifier that
is redefined as described below,
start
is a (LONG) INTEGER constant expression,
and stop is a constant
expression of the same type as start.
The UPTO form:
is expanded by the compiler to the equivalent form:
and the DOWNTO form:
to:
If start and stop
are LONG INTEGERs, the compiler uses 1L in place of 1.
The expanded form is compiled in place of the original text. Any errors
in the expanded form show the expanded text as if it were in the
source file. The comments are included to help the user recall that the
text has been created by the compiler, should the text be shown in an
error message.
The first example of the previous section can be rewritten as follows:
An example using $FORC, $CONTINUEC, $DONEC and nested loops:
16.13.2. Selector Matching Rules
A selector of the form [a] matches x if x = a,
i.e., if x and a evaluate to the same value.
Type of x, a, b
[a TO b] matches x if BOOLEAN
(IF a THEN 1 EL 0) LEQ (IF x THEN 1 EL 0)
LEQ (IF b THEN 1 EL 0) (LONG) INTEGER, (LONG) REAL, STRING
a LEQ x LEQ b (LONG) BITS
cvli(a) LEQ cvli(x) LEQ cvli(b) POINTER, ADDRESS, CHARADR
Always matches since the only constant for
these types is Zero. $CASECs of these types
are not very useful.
16.13.3. Delimiters of Selected Text
The selected text (text1, text2, etc. above)
is arbitrary text to be compiled. If
it contains a “bare” left bracket ([ or
{), i.e., not inside of a
STRING constant ("...[..."),
character constant ('['), or comment
(#...[...<eol>),
the left bracket (and optionally surrounding text) must be enclosed
in a $BEGINC-ENDC pair. For example:
$CASEC i OF
[...] ...
[bitsCode] $BEGINC b := bAry[k]; ENDC
[...] ...
ENDC
16.14. $BEGINC
Matched $BEGINC-ENDC pairs are useful within the selected
text governed by $CASEC.
In other places, matched $BEGINC-ENDC pairs are permitted,
but have no effect.
16.15. $DOC, $DONEC, $CONTINUEC, $FORC:
Compiletime Iteration
16.15.1. $DOC iteratedText ENDC
Text between $DOC and its terminating ENDC is
repeatedly compiled until the loop is terminated,
e.g., by $DONEC. The compiler gathers
the iterated text into a
single STRING.
You must take care to avoid putting the compiler into an infinite loop.
16.15.2. $DONEC and $CONTINUEC
$DONEC and $CONTINUEC are the compiletime analogues of the
DONE and CONTINUE statements.
$DOC("outer") ...
$DONEC("outer") ...
$CONTINUEC("outer") ...
ENDC
DEFINE i = 1;
$DOC write(f,i); REDEFINE i = i + 1;
IFC i > 5 THENC $DONEC ENDC ENDC
DEFINE i = 1;
$DOC("outer")
...
$DOC write(f,i); REDEFINE i = i + 1;
IFC i > 5 THENC $DONEC("outer") ENDC ENDC
... ENDC
16.15.3. $FORC
In the form:
$FORC var = start UPTO/DOWNTO stop $DOC ... ENDC
$FORC var = start UPTO stop $DOC ... ENDC
REDEFINE var = (start) - 1; # ($FORC expansion)
$DOC REDEFINE var = var + 1; # ($FORC expansion)
IFC var > stop THENC $DONEC ENDC # ($FORC expansion)
... ENDC
$FORC var = start DOWNTO stop $DOC ... ENDC
REDEFINE var = (start) + 1; # ($FORC expansion)
$DOC REDEFINE var = var - 1; # ($FORC expansion)
IFC var < stop THENC $DONEC ENDC # ($FORC expansion)
... ENDC
$FORC i = 1 UPTO 5 $DOC write(f,i); ENDC
$FORC i = 1 UPTO 2 $DOC("outer")
$FORC j = 1 UPTO 5 $DOC
IFC j DIV 2 THENC $CONTINUEC; ENDC
...
IFC ... THENC $DONEC("outer") ENDC
... ENDC
ENDC
16.16. Conditional Compilation and End-of-File
DONESCAN, SKIPSCAN, and end-of-file currently cause
IFC and $BEGINC
compilation constructs for the current source file to be closed.
If such a construct is closed due to end-of-file, an error
message is generated; otherwise, it is assumed that the closing
syntax is in the skipped text, but the compiler currently
does not examine
the skipped text to check this.
($DOC, $FORC, and
$CASEC behave differently; they always gather
up all text to the matching ENDC before processing any text.)
This behavior may change in future releases; you should always include a terminating ENDC for any of the conditional compilation constructs (even if the rule above implies that the ENDC will not be seen), and the ENDC should appear in the same file as the start of the construct. That means you should not do the following:
$BEGINC SOURCEFILE "file that contains an ENDC";
expecting that the ENDC in the sourcefiled file will terminate
the $BEGINC.
16.17. DCL
DCL is a compiletime pseudoprocedure.
DCL(identifier) is TRUE
if identifier has been declared or defined
(by the programmer, or as a standard MAINSAIL identifier),
and FALSE otherwise. DCL is
useful in conjunction with conditional compilation.
For example:
IFC NOT DCL(switch) THENC DEFINE switch = FALSE; ENDC
If switch has been declared or defined then
DEFINE switch = FALSE; is
ignored; otherwise, it is compiled.
16.18. $TYPEOF
$TYPEOF(x) returns the INTEGER constant type code
of the expression,
CLASS name, or MODULE name x.
The compiler parses x,
determines the type of the result, then discards the
resulting parse information (x is not actually evaluated).
The type codes that can be returned are the following:
booleanCode integerCode longIntegerCode realCode
longRealCode bitsCode longBitsCode stringCode
addressCode charadrCode pointerCode $recordCode
$procvarCode $classCode $moduleCode
| Temporary feature: subject to change |
$typeOf currently returns the type code of the base type of its argument expression, not an extended type code; e.g., $typeOf(i1), where i1 is an INTEGER(1), is integerCode, not $integer1Code.
This behavior is subject to change; future versions of $typeOf may return the extended type code for explicitly sized data types.
If x is an ARRAY (inplace or dynamic), $TYPEOF(x) is the base type of the ARRAY, i.e., the type of the elements (0 if untyped). If x is an inplace record, $TYPEOF returns $recordCode. If x is a CLASS or MODULE name, $TYPEOF returns $classCode or $moduleCode, respectively.
Given the declarations:
CLASS cls (STRING s; POINTER(c) link);
MODULE m;
INTEGER t,u;
POINTER(cls) p;
$TYPEOF returns the type codes shown for the following expressions:
| Expression | Result |
|---|---|
| $TYPEOF(t) | integerCode |
| $TYPEOF(t + u) | integerCode |
| $TYPEOF(p) | pointerCode |
| $TYPEOF(p.s) | stringCode |
| $TYPEOF(p.link) | pointerCode |
| $TYPEOF(sin(1.)) | realCode |
| $TYPEOF(cls) | $classCode |
| $TYPEOF(m) | $moduleCode |
An example of a macro that can increment either an INTEGER or LONG INTEGER:
DEFINE inc(a) =
[a .+ IFC $TYPEOF(a) = integerCode THENC 1
ELSEC 1L ENDC];
For example, given the declarations:
CLASS cls (STRING s; POINTER(c) link);
MODULE m;
INTEGER t,u;
POINTER(cls) p;
$CLASSOF returns the values shown for the following expressions:
| Expression | Result |
|---|---|
| $CLASSOF(t) | "" (null STRING) |
| $CLASSOF(t + u) | "" |
| $CLASSOF(p) | "CLS" |
| $CLASSOF(p.s) | "" |
| $CLASSOF(p.link) | "C" |
| $CLASSOF(sin(1.)) | "" |
Given the declarations:
CLASS rec1 (...; POINTER(rec1) nextRec1);
CLASS rec2 (...; POINTER(rec2) nextRec2);
you can define a macro that depends on the class of its POINTER argument:
DEFINE nextRec(p) = # make it work for rec1 and rec2
[p := IFC $CLASSOF(p) = "REC1" THENC p.nextRec1
ELSEC p.nextRec2 ENDC];
For example, suppose calls to the local PROCEDURE fooProc, which takes one argument, are desired to be inline if the argument is a constant. Define foo as below, then use foo instead of fooProc:
DEFINE foo(x) =
[IFC $ISCONSTANT(x) THENC INLINE ENDC
fooProc(x) ENDC];
SKIPSCAN allows the compiler to skip quickly over pages in the source file. The form of a SKIPSCAN directive is:
SKIPSCAN c;
where c is a STRING constant scan name. This directive causes the compiler to begin skipping pages until it finds one that starts with the keyword BEGINSCAN followed by the same scan name. Compilation then resumes on that page. Pages are delimited by eop characters (see Section 2.1). Upper and lower case are not distinguished in examining the scan name.
If c is Zero, i.e., if:
SKIPSCAN "";
is encountered, the compiler stops at the next BEGINSCAN c, regardless of the value of c.
Macros are not expanded within text skipped over by SKIPSCAN, and compiler directives (other than a matching BEGINSCAN) are ignored.
BEGINSCAN serves as a stopping point for a SKIPSCAN search.
The form of a BEGINSCAN directive is:
BEGINSCAN c;
where c is a STRING constant scan name. It is used by the SKIPSCAN search to determine whether or not the search should stop at this BEGINSCAN.
BEGINSCAN must appear as the very first text on a page, not even preceded by blank or tab; this allows the SKIPSCAN search to be fast since it need examine only the first line of each page. The compiler ignores the BEGINSCAN directive except during a SKIPSCAN search.
If c is Zero, the BEGINSCAN directive stops any SKIPSCAN search; i.e.:
BEGINSCAN "";
stops any SKIPSCAN search.
DONESCAN terminates compilation of the current file as if the end of the file were reached. It may be used to return from a sourcefile of a file that is being used as a repository for several sources.
The form of a DONESCAN directive is:
DONESCAN;
The scanning directives may be used to compile
MODULEs selectively in a file that contains more than one
MODULE.
That is, proper
use of the scanning directives can direct the compiler to compile just
some of the MODULEs in the file,
depending on which ones are specified
by the user.
16.22. NEEDBODY and NEEDANYBODIES
The compiletime pseudoprocedures NEEDBODY and NEEDANYBODIES
are used in conjunction with the
FORWARD qualifier
(see Section 7.13) to determine whether a FORWARD
PROCEDURE needs a body,
i.e., has been called but has not yet been given a
declaration containing the PROCEDURE body.
NEEDBODY may also be used to determine whether
an interface PROCEDURE (whether called or not) needs a body.
The form:
NEEDBODY(id)
is TRUE if and only if id is the name of a PROCEDURE that either has been declared FORWARD and has appeared in a PROCEDURE call or is an interface PROCEDURE, but has not been declared with a body.
NEEDANYBODIES has two forms, one followed by a parenthesized file name, and one not. The form:
NEEDANYBODIES(c)
where c is a STRING constant expression for a file name, is TRUE if and only if some PROCEDURE p was declared with the qualifier FORWARD(c), and NEEDBODY(p) is currently TRUE. In other words, NEEDANYBODIES(c) tells whether there are any PROCEDURE bodies in the file c that need to be compiled.
The form:
NEEDANYBODIES
is equivalent to:
NEEDANYBODIES(c)
where c is the name of the file that caused the current automatic SOURCEFILE as explained in Section 7.13. The implied c is the “top-level” file that was sourcefiled, not necessarily the current file (additional SOURCEFILE directives may occur in the top-level file).
The $compileTimeValue argument HASBODY may be used to determine
whether a PROCEDURE has been given a body, regardless of how the
PROCEDURE was declared.
16.23. $compileTimeValue
$compileTimeValue is a compiletime PROCEDURE that provides a
number of miscellaneous compiletime facilities.
It is described in detail in Section 32.48.
16.24. $def
The macro $def is an aid to defining a consecutive sequence of
(LONG) INTEGERs, or a sequence of
(LONG) BITS each shifted one more bit to the
left than the previous value.
$def(a,v) redefines a to be v, and then:
The user must define v's starting value before using $def.
Example:
# define a = 1, b = 2, c = 3, d = 4
DEFINE v = 1;
$def(a,v)
$def(b,v)
$def(c,v)
$def(d,v)
The second argument, v, may be omitted, in which case the identifier $defVal is used in place of v. $defVal is an identifier which has been set aside for this purpose. In this case, the user must initialize $defVal with REDEFINE since it may already be defined at the start of compilation. It is expected that most uses of $def will omit the second argument and use $defVal; the second argument would be useful, however, if multiple sequences need to be defined in parallel.
Example:
# define a = '1, b = '2, c = '4, d = '10
REDEFINE $defVal = '1;
$def(a)
$def(b)
$def(c)
$def(d)
REDEFINE allows the type of a macro to be changed; for example, if $defVal is defined to be an INTEGER constant, then:
REDEFINE $defVal = '1L;
changes it to be a LONG BITS constant.
There is nothing “magic” about $def; i.e., it could just as easily be provided by the user. $def is defined as follows:
DEFINE
$def(a,v) =
[IFC [v] THENC
REDEFINE
a = v,
v = IFC $TYPEOF(v) = integerCode THENC v + 1
$EFC $TYPEOF(v) = longIntegerCode THENC
v + 1L
ELSEC v SHL 1 ENDC;
ELSEC
REDEFINE
a = $defVal,
$defVal =
IFC $TYPEOF($defVal) = integerCode THENC
$defVal + 1
$EFC $TYPEOF($defVal) = longIntegerCode
THENC $defVal + 1L
ELSEC $defVal SHL 1 ENDC;
ENDC];
The exact definition of $def is subject to change; the above is presented only as an example.