$PP directive

Purpose: $PP directive causes a preprocessor named bcxpp.dll to be invoked and each succeeding source line to be preprocessed until a second $PP is encountered.


 Syntax:

 $PP' Loads and turns on preprocessor.
 ' source code here to be preprocessed
 $PP' Turn off preprocessor.

The preprocessor is a dynamic link library named bcxpp.dll that is located within the paths that Win32 looks for .dlls. See Win32 SDK help file under "LoadLibrary" for details.

The template(bcxpp.bas) for making a pp dll can be downloaded from the BCX Yahoo Files/BCX_Files section. The pp dll contains one exported procedure called ProcessLine. After processing all directives and just before parsing a line of code, BCX passes the line to the preprocessor for handling as it sees fit. Then the pp passes the line back to BCX which proceeds normally.

Here is a template for a Preprocessor DLL:


 '====================================================================
 ' BEGIN Preprocessor DLL TEMPLATE
 '====================================================================

 $DLL

 '====================================================================
 ' BCX Preprocessor DLL
 ' Created by Vic McClung    4/19/2003
 ' ===================================================================
 ' This dll must be in a place where Win32 looks for DLLs. I
 ' recommend putting it in the /bin folder of BCX.
 '====================================================================
 ' FUNCTION ProcessLine(Src$) AS LONG EXPORT
 '    put code to preprocess modify Src$
 '    Src$ is passed by reference so any changes
 '    will be returned to BCX for final processing.
 '  FUNCTION = 1 ' Return 0 means error
 '               ' Return 2 means to goto ReProcess: label and reprocess line
 ' END FUNCTION
 '====================================================================
 ' Note: When you arrive here, BCX has already TRIM$(Src$) and processed
 ' all lines with directives such as $COMMENT, $CCODE, $LIBRARY, etc. If you
 ' want BCX to run the line back thru from the start, then return 2 and it
 ' will goto ReProcess label and it will behave just as if it had read the
 ' line from the source file.  Be careful if you do this.  In fact, be
 ' careful when you use the preprocessor, period.
 '
 ' One other thing is worth mentioning, BCX has removed the _ continuation
 ' characters at the end of lines and concatenated those into one long line
 ' when this procedure is called.
 '====================================================================

 ' Enums for tokkinds - kinds of tokens
 ENUM  TOK_ERROR,  _ ' Error
       TOK_EOF,    _ ' End-Of-File
       TOK_NL,     _ ' Newline
       TOK_ID,     _ ' identifier
       TOK_NUM,    _ ' number
       TOK_STR,    _ ' string literal
       TOK_OP,     _ ' operators
       TOK_SYM,    _ ' symbol
       TOK_CMT,    _ ' comment
       TOK_INC,    _ ' include
       TOK_META,   _ ' meta statement
       TOK_ILC,    _ ' in line 'C' code
       TOK_LCC,    _ ' line continuation char '_' in BASIC
       TOK_KW,     _ ' Keyword
       TOK_CMD,    _ ' Command
       TOK_FUNC,   _ ' built in function
       TOK_EOL,    _ ' End of Line CHR$(0)
       TOK_LABEL     ' label:

 GLOBAL stack$[512]
 GLOBAL tokkind[512] AS LONG
 GLOBAL index AS LONG
 GLOBAL p AS CHAR PTR
 GLOBAL token$

 FUNCTION ProcessLine(Src$) AS LONG EXPORT
   LOCAL kind AS LONG, i AS LONG
   p = Src$
   index = 0
   DO
     IF *p = 0 THEN EXIT LOOP
     token$ = ""
     kind = getNext()
     IF kind THEN
       IF kind = TOK_CMT THEN
         token$ = MID$(Src$,(p - Src$))
         *p = 0
       END IF
       IF kind = TOK_EOL THEN
         EXIT LOOP
       END IF
       stack$[index] = token$
       tokkind[index] = kind
       index++
     ELSE ' error
       Src$ = token$ ' put error message in Src$ to pass back to BCX
       FUNCTION = 0' return 0 to indicate error!
     END IF
     '===============================================================
     ' code goes here to process the tokens contained in stack$ array
     '===============================================================
   LOOP
 '====================================================================
 ' Return a zero to throw an error back to BCX and return the error
 ' message in the Src$ string.  Return 2 if you want to run this line
 ' back thru from the top just remember that you may get it again
 ' as the next line to process, depends on what line contains.
 '====================================================================
   FUNCTION = 1
 END FUNCTION

 FUNCTION getNext() AS BOOLEAN
 ' see bcxpp.bas code for parser/tokenizer code
 END FUNCTION
 '====================================================================
 ' END Preprocessor DLL TEMPLATE
 '====================================================================

The BCX Preprocessor:

Normally, BCX reads each line from the source file, one line at a time. Before BCX reads the next line, a flurry of stuff happens -- called parsing and tokenizing. If BCX's parser / tokenizer does not understand the line coming in from the BASIC source file, either an error is thrown or bad code is emitted.

The preprocessor is a dynamic link library named bcxpp.dll that is located within the paths that Win32 looks for .dlls. See Win32 SDK help file under "LoadLibrary" for details. Simply put, what the bcxpp.dll does is intercept the line of code coming in from the Basic source file and allows the user to change or modify it to suit and then pass the modifed code back to BCX's parser/tokenizer routines to handle as it would normally.

The bcxpp.dll allows one to introduce new meta-commands, structures,functions, constants, almost anything, and to translate these new(NOT BUILT IN FEATURES) into a format that BCX will accept -before- BCX parser/tokenizer gets a crack at it.

Think of the BCX preprocessor(dll) as a user-defined PLUGIN. The bcxpp.dll is only needed if you try to use the functionality defined inside a bcxpp.dll, otherwise BCX will function without it.

Notes about $PP:

  1. When BCX encounters the first occurence of $PP, it loads the dll if it can find it. If it cannot find the dll or cannot locate the ProcessLine procedure in the dll, it aborts with appropriate message. In addition to loading the dll on the first instance, BCX turns on preprocessing and passes the source code line to the preprocessor. Each subsequent encounter simple turns the preprocessor on if off and off if on. The dll is unloaded by BCX upon termination.
  2. Each line of code which is not part of a directive or directive is passed to the preprocessor. For example, lines of code beginning with a comment is not passed, lines of between $comment directives are not passed, etc.
  3. BCX passes the source code line(Src$) with the spaces removed from both ends of the line.
  4. BCX passes a long line or one that has had all of the line continuation characters removed and the line concatenated into one long line of code.
  5. BCX preprocessor has its own parser/tokenizer to build the stack$/tokkind$ arrays and index token counter variable.
  6. Do not use the STDCALL directive with $DLL.
  7. Do not link with the -nounderscores liner switch because the preprocessor function will be called as '_ProcessLine' from BCX.