Pragmas

CM Modula-3 recognizes the following pragmas:

<*EXTERNAL*>

The pragma <*EXTERNAL N:L*> may precede an interface or a procedure or variable declaration in an interface. It asserts that the following entity is named ``N'' and implemented in language ``L'' (or uses calling convention ``L''). If ``N'' is omitted, the external name is the Modula-3 name. The default and only recognized value for ``L'' are platform dependent. The ``:'' is only required when specifying ``L''. ``N'' and ``L'' may be Modula-3 identifiers or string literals.

On Unix platforms, the default and only recognized language is C.

On Windows/NT, two calling standards are supported, __cdecl and __stdcall. They are treated as languages by the <*EXTERNAL*> pragma. C and WINAPIV are aliases for __cdecl. WINAPI, CALLBACK, APIENTRY, APIPRIVATE, and PASCAL are aliases for __stdcall. The default is C.

The names of external procedures and variables are passed through the back end unchanged. The types of external variables, the types of formal parameters, the types of results, and the raises clauses of external procedures are all assumed to be correct and are not checked against their external implementation.

Beginning an interface with <*EXTERNAL*> declares all of the procedures and variables in that interface external.

For example:

    <*EXTERNAL*> INTERFACE OS;
    VAR errno: INTEGER;
    PROCEDURE exit (i: INTEGER);
    END OS.
allows importers of OS to access the standard Unix symbols errno and exit through the names OS.errno and OS.exit respectively.

Alternatively, the following interface provides access to the same two symbols, but uses a more conventional Modula-3 name for the procedure:

    INTERFACE OS;
    <*EXTERNAL errno:C *> VAR errno: INTEGER;
    <*EXTERNAL exit:C  *> PROCEDURE Exit (i: INTEGER);
    END OS.

If several variables are declared within a single <*EXTERNAL*> VAR declaration, they are all assumed to be external.

The external pragma may optionally specify a name different from the Modula-3 name. For example:

    INTERFACE Xt;
      <*EXTERNAL "_XtCheckSubclassFlag" *>
      PROCEDURE CheckSubclassFlag (...);
      ...
defines a procedure named Xt.CheckSubclassFlag in Modula-3 and named _XtCheckSubclassFlag in the generated C.

<*INLINE*>

The pragma <*INLINE*> may precede a procedure declaration. The pragma is allowed in interfaces and modules. CM Modula-3 parses but ignores this pragma.

For example:

    INTERFACE X;
    <*INLINE*> PROCEDURE P (i: INTEGER);
    <*INLINE*> PROCEDURE Q ();
    END X.
declares X.P and X.Q to be inlined procedures.

<*ASSERT*>

The pragma <*ASSERT expr*> may appear anywhere a statement may appear. It is a static error if ``expr'' is not of type BOOLEAN. At runtime ``expr'' is evaluated. It is a checked runtime error if the result is FALSE.

Assertion checking can be disabled with the -a compiler switch.

<*TRACE*>

The pragma <*TRACE expr*> may appear at the end of any variable or formal declaration. This pragma will generate tracing calls whenever the declared variable is modified.

The ``expr'' must evaluate to a procedure of two arguments. The first argument is the name of the traced variable, a TEXT. The second argument is the traced variable. Note that any of the formal passing modes may be used with the second argument.

For example:

    MODULE M;
    VAR x: Foo <*TRACE MyTrace.FooChanged*>;
will cause
    MyTrace.FooChanged ("M.x", x)
to be generated after each statement that modifies x. Variable aliasing is not tracked, so
    WITH  alias = x DO  INC(alias) END
will not generate any tracing.

The pieces of Modula-3 grammar affected by <*TRACE expr*> are:

    VariableDecl = IdList (":" Type & ":=" Expr) V_TRACE.
    Formal       = [Mode] IdList (":" Type & ":=" ConstExpr) V_TRACE.
    ForSt        = FOR Id V_TRACE ":=" Expr TO Expr [BY Expr] DO S END.
    Handler      = QualId {"," QualId} ["(" Id V_TRACE ")"] "=>" S.
    TCase        = Type {"," Type} ["(" Id V_TRACE ")"] "=>" S.
    Binding      = Id V_TRACE "=" Expr.
    V_TRACE      = [ "<*" TRACE  Expr "*>" ].

The pragma <*TRACE stmt-list*> may appear immediately after any BEGIN. The specified ``stmt-list'' will be inserted after each statement of the block started by the BEGIN. For example:

    BEGIN <* TRACE  INC(cnt); MyTrace(cnt) *>
      i := j;
      j := i;
    END;
will generate INC(cnt); MyTrace(cnt) after each of the assignment statements.

<*FATAL*>

The pragma <*FATAL id-list*> may appear anywhere a declaration may appear. It asserts that the exceptions named in ``id-list'' may be raised, but unhandled in the containing scope. If they are, it's fatal and the program should crash. Effectively, the <*FATAL*> pragma disables a specific set of ``potentially unhandled exception'' warnings. If ``id-list'' is ANY, the pragma applies to all exceptions. The effects of the <*FATAL*> pragma are limited to its containing scope --- they cannot be imported from interfaces.

For example:

    EXCEPTION InternalError;
    <*FATAL InternalError*>
at the top-level of a module M means that no warnings will be generated for procedures in M that raise but don't list InternalError in their RAISES clauses.

Similarly,

    PROCEDURE X() RAISES {} =
    BEGIN
      ...
      <*FATAL ANY*> BEGIN
         List.Walk (list, proc);
      END;
      ...
    END X;
specifies that although X raises no exceptions and List.Walk may, no warnings should be generated.

<*UNUSED*>

The pragma <*UNUSED*> may precede any declaration. It asserts that the entity in the following declaration is not used and no warnings should be generated.

For example, the procedures that implement the default methods for an object may not need all of the actual parameters:

    PROCEDURE DefaultClose (<*UNUSED*> wr: Wr.T) =
       BEGIN (* do nothing *) END DefaultClose;

<*OBSOLETE*>

The pragma <*OBSOLETE*> may precede any declaration (e.g. <*OBSOLETE*> PROCEDURE P ();). A warning is emitted in any module that references an obsolete symbol. This feature is used to warn clients of an evolving interface that they are using features that will disappear in the future.

<*NOWARN*>

The pragma <*NOWARN*> may appear anywhere. It prevents warning messages from being issued for the line containing the pragma. It is probably better to use this pragma in a few places and enable all warnings with the -w1 switch than to ignore all warnings.

<*LINE*>

For the benefit of preprocessors that generate Modula-3 programs, the compiler recognizes a <*LINE ... *> pragma, in two forms:

    <*LINE number filename *>
    <*LINE number *>
where number is an integer literal and filename is a text literal. This pragma causes the compiler to believe, for purposes of error messages and debugging, that the line number of the following source line is number and that the current input file is filename. If filename is omitted, it is assumed to be unchanged. <*LINE ... *> may appear between any two Modula-3 tokens; it applies to the source line following the line on which it appears. Here's an example: <*LINE 32 "SourceLoc.nw" *>.

<*PRAGMA*>

The pragma <*PRAGMA id-list*> may appear anywhere. It notifies the compiler that pragmas beginning with the identifiers in ``id-list'' may occur in this compilation unit. Since the compiler is free to ignore any pragma, the real effect of <*PRAGMA*> is to tell the compiler that pragmas it doesn't implement are coming, but they shouldn't cause ``unrecognized pragma'' warnings.

<*calling convention*>

Any of the ``languages'' allowed in the <*EXTERNAL*> pragma may be used to indicate the calling convention associated with a procedure or procedure type. The pragma must appear immediately prior to the PROCEDURE keyword. For example:

    TYPE WindowsCallBack = <*CALLBACK*> PROCEDURE (h: HANDLE);

    <*CALLBACK*> PROCEDURE Foo (h: HANDLE) =
       BEGIN ....
declares a procedure and procedure type that use the Windows/NT CALLBACK (i.e. __stdcall) calling convention.

The CM Modula-3 compiler treats procedure types that are equal except for their calling conventions as different types.