5.2. Skeleton of a Preprocessor

[<<<] [>>>]

An internal preprocessor implemented as a .dll or .so file has to export a single function named preproc. The declaration of this function should look like this:

int DLL_EXPORT preproc(pPrepext pEXT,
                       long *pCmd,
                       void *p);

The first argument of the function is the preprocessor pointer. This pointer points to a structure. For each preprocessor loaded there is a separate structure of this type. This structure hold information on the preprocessor and there is some storage pointer in the structure that the preprocessor can access.

The definition of the structure is:

typedef struct _Prepext {
  long lVersion;
  void *pPointer;
  void *pMemorySegment;
  struct _SupportTable *pST;
  } Prepext, *pPrepext;

The field lVersion is the version of the interface that ScriptBasic wants to use when communicating with the preprocessor. If this version is not the same as the interface version that the preprocessor was compiled for then the preprocessor has to ask ScriptBasic not to use it and may return an error code or zero indicating that no error has happened. This may be useful in some cases when the preprocessor is optional and in case the preprocessor can not be loaded the program still may function. Read on how the preprocessor has to do this.

The field pPointer is initialized to NULL and is never changed by ScriptBasic. This is a pointer that can be used by the preprocessor to access its own thread local variables.

The field pMemorySegment is initialized to point to a memory segment that can be used via the memory allocation routines of ScriptBasic. These routines, however need not be linked to the DLL, because they are already in the process loaded as part of the executable and can be reached via the function support table.

This support table is pointed by the field pST and is the same type of struct as the support table available for the extension modules. Although this support table is the same type of struct it is not the same struct. The fields pointing to the different functions are eventually pointing to the same function, but when the program starts to execute a new support table is allocated and initialized. Thus there is no reason for the preprocessor to alter this table, because altering the table will have no effect on the execution of the program. Also the preprocessor if decides to stay in memory while the program is executed (for example a debugger), may rely on this support table even if a module altering the run-time support table is used.

In case there are more than one internal preprocessors used they will share the same support table. This way a preprocessor altering the preprocessor support table may alter the behavior of another internal preprocessor. However doing that need deep and detailed information of both ScriptBasic code and the other preprocessor and may result code that closely depends on the different versions of the different programs that work together.

The next argument to the function pCmd is an input and output variable. When the function is called by ScriptBasic it contains the command that the preprocessor is expected to perform. In other words this value defines the reason why the preprocessor was loaded. There are numerous points when ScriptBasic calls the preprocessor and at each point it sets this variable differently.

When the function returns it is supposed to set the variable *pCmd to one of the following values:

The preprocessors function preproc may at any call return an int value. This value will be used by the interpreter as error code. This code is zero in case there was no error. This value has to be returned to ensure that the interpreter goes on. The error code 1 is used at any code in ScriptBasic to signal memory allocation problems. The symbolic constant COMMAND_ERROR_PREPROCESSOR_ABORT can be used to tell the interpreter to stop. For example the sample debugger preprocessor uses this error code when the user gives the command q to quit debugging.

[<<<] [>>>]