Registered macros – Crunch CRiSP File Editor 6 User Manual

Page 42

Advertising
background image

Page 42

Static macros are very useful, as they are in the C language, to hide private macros in a large macro so that
name conflicts do not occur either with the supplied macros or anything else which has no reason to know
the names of these private macros.

Static macros should be used wherever possible to avoid name conflicts which can cause CRiSP to hang or
crash by accidentally replacing an internal macro. Conflicts which can occur because the static keyword has
not been used can happen at any time especially as CRiSP demand-loads macros.

Modules and static macros

Although the CRiSP macro language looks and feels largely like C, there are inherent problems in try to
perform data abstraction and hiding of functions and data. One of the problem areas is to do with static
functions. A static function can be referred to within the current file scope, but cannot be referred to from
another file. Also, because CRiSP does not provide support for pointers, it can be difficult to hide a static
function yet pass a reference to it around.

For example, CRiSP macros make use of registered callbacks, whether for various editing events, key
presses, or dialog box events. These events are specified as pure strings, and the CRUNCH compiler does
not attempt to parse or understand these strings. The strings are executed at the point they are needed.
This is a problem because for most functions it is possible to declare them static and if you get something
wrong, such as differing function declarations and definitions, then the compiler will tell you something is up.

It is quite possible to mark a callback static, but not have it in visible scope at the time it is required for
execution, resulting in a macro execution error and possibly very difficult to verify correctness of the code.

The modules mechanism is designed to address this problem with run-time support. A module is a way of
giving one or more macro files a name such that functions can be identified in these modules. For example,
you might implement a macro package to perform searching. The macros to implement these functions may
be spread about a number of source files, with many of the macros being private to the implementation, yet
some functions are required for external consumption.

With the modules mechanism you can safely make all internal functions static, yet still be allowed to access
them in callback functions via the module reference. A module reference is a string such as "search::find_it".
The name preceding the "::" characters is the module name, and the "find_it" is simply a macro name, used
in much the same way as any other macro reference in a string literal. If no module name is specified, e.g.
"::find_it" then this is a shorthand for referring to the current file. (CRiSP automatically creates private
modules for every loaded macro file. You will see these implicit module references in the debug out from
CRiSP if you use the "::function" notation in your code).

Because Because static functions can potentially lead to programming errors at run-time, especially if you
have not used the "::" module syntax, then you can use the command line switch "-warnings" which will log
entries in the crisp.log file with the keyword "WARNING:" wherever an assign_to_key(), register_macro,
register_timer() or create_object(DBOX_CALLBACK) is used which could potentially lead to a run-time error.
(Note the -warnings switch is specified when invoking CRiSP, not the macro compiler).

For example, the following is one way of accessing a function:

assign_to_key("<Alt-A>", "handle_alt_a");

With a module reference you would do:

assign_to_key("<Alt-A>", "module_name::handle_alt_a");

This facility is designed for implementors of macros who wish to try and maintain as much privacy of the
implementation as possible yet need to be able to refer to their own function definitions as part of the entire
package. Macro writers should be very careful about calling static functions in someone elses macro
package as this negates the whole raison d'etre for static function definitions in the first place.

A module is defined using the module() primitive. Refer to the manual page for further details on this
function.

Registered Macros

Registered macros are a means of creating a macro which gets called when certain events internal to
CRiSP happen. These definitions are available in the crisp.h macro file, and documented in the table below.

Any macro can be registered for one of these events by calling the register_macro() primitive. Whenever the
event is triggered the macro will be called. A macro can be unregistered by calling the primitive
unregister_macro().

Advertising