Mixing "C" and BCX Code

! Inline "C" Code operator

Purpose: BCX allows you pass inline "C" code using the exclamation mark (!) as an operator.


Syntax:

 ! /* "C" statement goes here */

Remarks: When ! is used outside of a BCX FUNCTION or SUB procedure, the emitted "C" code is located in the main function of the "C" translation.

Example: The following sample shows how to create a "C" coded local DWORD variable.


 PRINT GetMachineName$()

 FUNCTION GetMachineName$
  LOCAL A$
  ! DWORD b; /* allocate a local variable in "C" and include "C" comments! */
  b = 256
  GetComputerName(A$, &b) ' the & operator means "PASS THE ADDRESS" of b
  FUNCTION = A$
 END FUNCTION

$CCODE directive

Purpose: BCX allows you pass inline "C" code using a $CCODE directive placed before and after the "C" code.


Syntax 1:

 $CCODE
    
  /* "C" statements go here */

 $CCODE

Remarks: When $CCODE ... $CCODE is used without an optional parameter or if it is outside of a BCX FUNCTION or SUB procedure, the emitted "C" code is located in the main function of the "C" translation..

Example:


 PRINT "BCX Code Here."

 $CCODE

 // declare the variables:
    int nNumber;
    int *pPointer;
  
 // now, give a value to them:
    nNumber = 15;
    pPointer = &nNumber;
  
 // print out the value of nNumber:
    printf("nNumber is equal to : %d\n", nNumber);
 
 // now, alter nNumber through pPointer:
    *pPointer = 25;
  
 // prove that nNumber has changed as a result of the above
 // by printing its value again:
    printf("nNumber is equal to : %d\n", nNumber);
    
 $CCODE

 PRINT "BCX Code Here."

Result:


 BCX Code Here.
 nNumber is equal to : 15
 nNumber is equal to : 25
 BCX Code Here.


Syntax 2:

 $CCODE HEADER
    
  /* "C" statements go here */

 $CCODE

Parameters:

  • HEADER [OPTIONAL] When the $CCODE HEADER directive is used, everything sandwiched between the $CCODE HEADER and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User Defined Constants' section. $CCODE HEADER is useful, particularly, for inlined "C" source pragma statements.

Example:


 $CCODE HEADER 

  #if VERSION == 1
  #define INCFILE "vers1.h"
  #elif VERSION == 2
  #define INCFILE "vers2.h" // and so on
  #else
  #define INCFILE "versN.h"
  #endif 
  #include INCFILE

 $CCODE


Syntax 3:

 $CCODE ENUM
    
  /* "C" statements go here */

 $CCODE

Parameters:

  • ENUM [OPTIONAL] When the $CCODE ENUM directive is used, everything sandwiched between the $CCODE ENUM and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User's GLOBAL Enumerations' section.

Example:


 $CCODE ENUM
    
  enum a{a=100,b,c,d=200,e,f};
 
 $CCODE
 
 PRINT a, b, c, d, e, f

Result:


 100 101 102 200 201 202


Syntax 4:

 $CCODE CONST

  /* "C" statements go here */

 $CCODE

Parameters:

  • CONST [OPTIONAL] When the $CCODE CONST directive is used, everything sandwiched between the $CCODE CONST and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User Defined Constants' section.

Syntax 5:

 $CCODE UDT

  /* "C" statements go here */

 $CCODE

Parameters:

  • UDT [OPTIONAL] When the $CCODE UDT directive is used, everything sandwiched between the $CCODE UDT and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User Defined Types And Unions' section.

Example:

For $CCODE CONST and $CCODE UDT.


 $CCODE CONST

  #define QWERTY_CLASS struct _QWERTY*

 $CCODE
 
 $CCODE UDT

  typedef struct _QWERTY
  {
   int   a;
   float b;
   char  c[80];
  }
  QWERTY, *LPQWERTY;
 
 $CCODE
  
 GLOBAL MyType [10,10,10] AS QWERTY
  
 MyType [2,3,4].a  =  1
 MyType [2,3,4].b! =  2.345
 MyType [2,3,4].c$ = "hello world from a poly-dimensional udt!"
  
 PRINT        MyType[2,3,4].a
 PRINT        MyType[2,3,4].b!
 PRINT UCASE$(MyType[2,3,4].c$)
 

Result:


 1
 2.345
 HELLO WORLD FROM A POLY-DIMENSIONAL UDT!


Syntax 6:

 $CCODE SET

  /* "C" statements go here */

 $CCODE

Parameters:

  • SET [OPTIONAL] When the $CCODE SET directive is used, everything sandwiched between the $CCODE SET and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User's GLOBAL SET Statements' section.

Example:


 TYPE foo
  A AS INTEGER
  B AS INTEGER
  C AS BYTE
 END TYPE
 
 $CCODE SET
 
 static foo MyFoo[]=
  {
   {12,13},
   {19,20}
  };
 
 $CCODE
 
 ? MyFoo[0].A
 ? MyFoo[0].B
 ? MyFoo[0].C
 ? MyFoo[1].A
 ? MyFoo[1].B
 ? MyFoo[1].C

Result:


 12
 13
  0
 19
 20
  0


Syntax 7:

 $CCODE FUNCSUB

  /* "C" statements go here */

 $CCODE

Parameters:

  • FUNCSUB [OPTIONAL] When the $CCODE FUNCSUB directive is used, everything sandwiched between the $CCODE FUNCSUB and the terminating $CCODE statements is placed at the file scope level of the emitted "C" source in the 'User's C code' section.

Remarks: $CCODE FUNCSUB is used to enclose a complete "C" code procedure. A prototype is not needed in this case because the placement in the emitted "C" source is before the main procedure.

Example:


 DIM a$
 DIM b$
  
 a$ = "     this   is    a     test      "
  
 b$ = Remove_All_White_Space(a$)
  
 PRINT b$
  
 END PROGRAM
  
 $CCODE FUNCSUB

 char* Remove_All_White_Space(char* str1)
  {
   char *obuf,*nbuf;
   if (str1)
    {
     for (obuf=str1,nbuf=str1;*obuf;
      ++obuf)
      {
       if (!isspace(*obuf))
       *nbuf++=*obuf;
      }
    *nbuf=0;
    }
   return str1;
  }

 $CCODE

Remarks: The top to bottom order of placement of the "C" code translated from the $CCODE directives is

  1. $CCODE HEADER
  2. $CCODE ENUM
  3. $CCODE CONST
  4. $CCODE UDT
  5. $CCODE SET
  6. $CCODE FUNCSUB

$HEADER directive

Purpose: The $HEADER directive works like $CCODE except everything sandwiched between two $HEADER statements is placed at the file scope level of the emitted "C" source. $HEADER is useful particularly for pragma statements and declaring prototypes for inlined "C" source functions. A $HEADER directive is placed before and after the "C" code.


Syntax:

 $HEADER

  /* "C" statements go here */

 $HEADER

Example:


 $HEADER 

  #define KitchenSinkIsIncluded 

 $HEADER


 $HEADER

  #ifndef KitchenSinkIsIncluded
   #include <KitchenSink.h>
  #else
   #define CallThePlumber 1
  #endif

 $HEADER 

$CPROTO directive

Purpose: The $CPROTO directive is used for declaring prototypes for inlined "C" source functions.


Syntax 1:

 $CPROTO ! ProcedureDataType ProcedureName(ParameterDataType);

Remarks: When using $CPROTO with a "C" language prototype, a space-exclamation mark-space must precede the prototype. Also remember, that in "C", a semicolon is required at the end of of the prototype.

Everything following the $CPROTO ! is placed at the file scope level of the emitted "C" source in the 'User's Prototypes' section.

Example:


 $CPROTO ! char* Remove_All_White_Space(char*);
    
 DIM a$
 DIM b$
   
 a$ = "     this   is    a     test      "
   
 b$ = Remove_All_White_Space(a$)
   
 PRINT b$
   
 END PROGRAM
   
 $CCODE
  char* Remove_All_White_Space(char* str1)
   {
    char *obuf,*nbuf;
    if (str1)
     {
      for (obuf=str1,nbuf=str1;*obuf;
       ++obuf)
       {
        if (!isspace(*obuf))
        *nbuf++=*obuf;
       }
     *nbuf=0;
     }
    return str1;
   }
  $CCODE


Syntax 2:

 $CPROTO [FUNCTION/SUB] Foo$(a%, b$)

Remarks: $CPROTO, also, will accept a BCX FUNCTION or SUB declaration which will be translated to "C" code and placed correctly in the 'User Prototypes' section of the "C" translation.

Example:


 $CPROTO FUNCTION Remove_All_White_Space$(a$)
   
 DIM a$
 DIM b$
  
 a$ = "     this   is    a     test      "
  
 b$ = Remove_All_White_Space(a$)
  
 PRINT b$
  
 END PROGRAM
  
 ! char* Remove_All_White_Space(char* str1)
 !  {
 !   char *obuf,*nbuf;
 !   if (str1)
 !    {
 !     for (obuf=str1,nbuf=str1;*obuf;
 !      ++obuf)
 !      {
 !       if (!isspace(*obuf))
 !       *nbuf++=*obuf;
 !      }
 !    *nbuf=0;
 !    }
 !   return str1;
 !  }

$PRAGMA directive

Purpose : The $PRAGMA directive is translated to the C keyword #pragma. The utility and syntax varies between compilers for the #pragma directives.


Syntax:

 $PRAGMA compiler specific instruction and arguments

Example: To include the Dwmapi.lib library to a code compilation using Microsoft or Pelles C, use this


 $PRAGMA comment(lib, "Dwmapi.lib")

For a MinGW compiler use this


 $PRAGMA lib "Dwmapi.lib"

Remarks:

Details for using pragma directives with the Microsoft compiler are available on their Microsoft Pragma directives and the __pragma and _Pragma keywords page.

Pragma information for the MinGW compilers can be found at Pragmas Accepted by GCC page.

Here is a snippet of code from the BCX translator which shows how $PRAGMA is used to suppress a MinGW compiler generated warning. A $PRAGMA "diagnostic ignored" is placed immediately before the cast to CPP_FARPROC that causes the warning. The $PRAGMA "diagnosic pop" restores the diagnostics to their previous condition.


 $IFDEF (__GNUC__)
     $PRAGMA GCC diagnostic ignored "-Wcast-function-type"
     PPProc = (CPP_FARPROC) GetProcAddress (PPDLL_HANDLE,"ProcessLine");
     $PRAGMA GCC diagnostic pop
 $ELSE
     PPProc = (CPP_FARPROC) GetProcAddress (PPDLL_HANDLE,"ProcessLine"); 
 $ENDIF