Mixing C and BCX Code

! Inline C Code operator

Purpose:

BCX allows you to 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 to pass inline C code using a $CCODE directive placed before and after the C code.

Syntax:

$CCODE
  
 /* C statements go here */

$CCODE

Remarks:

When $CCODE ... $CCODE 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:

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.

$CCODE HEADER directive

Purpose:

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.

Syntax:

$CCODE HEADER
  
 /* C statements go here */

$CCODE

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

$CCODE ENUM directive

Purpose:

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.

Syntax:

$CCODE ENUM
  
 /* C statements go here */

$CCODE

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

$CCODE CONST directive

Purpose:

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:

$CCODE CONST

 /* C statements go here */

$CCODE

$CCODE UDT directive

Purpose:

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.

Syntax:

$CCODE UDT

 /* C statements go here */

$CCODE

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!

$CCODE SET directive

Purpose:

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.

Syntax:

$CCODE SET

 /* C statements go here */

$CCODE

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

$CCODE FUNCSUB directive

Purpose:

$CCODE FUNCSUB is used to enclose a complete C code procedure.

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.

A prototype is not needed in this case because the placement in the emitted C source is before the main procedure.

Syntax:

$CCODE FUNCSUB

 /* C statements go here */

$CCODE

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")

Remarks:

Details for using pragma directives with the Microsoft compiler are available on their Microsoft Pragma directives and the __pragma and _Pragma keywords 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