MAINSAIL System-Specific User's Guides, Chapter 9

previous   next   top   contents   index   framed top   this page unframed


9. Foreign Language Interface

This chapter contains information about the MAINSAIL Foreign Language Interface (FLI) specific to NTPNT. Refer to the Chapter 7 of the MAINSAIL Compiler User's Guide for a general description of the FLI.

9.1. FLI Compilers

The Foreign Call Compiler (FCC) is used to call foreign procedures from MAINSAIL. The MAINSAIL Entry Compiler (MEC) is used to call MAINSAIL PROCEDUREs from a foreign language. If the foreign language to be called does not conform to the C calling conventions, then the standard FLI compilers cannot be used. Contact XIDAK if you need an interface between such a language and NTPNT MAINSAIL.

The compiler subcommands required to specify the FLIs to and from C are FLI TC and FLI FC.

The default output file name for the MAINSAIL FLI compilers is:

module name, converted to lower case.s

9.2. Data Types

Use the appropriate C data type macros ($CSHORT, $CINT, etc.; see
Appendix L of the MAINSAIL Language Manual) when declaring parameter types for FLI procedures (on NTPNT, this works even for MAINSAIL versions before 16.29).

In addition, use the correspondences below for data types not listed in Appendix L of the MAINSAIL Language Manual:

C Type MAINSAIL Type Representation Passed
pointer POINTER, ADDRESS 4 bytes
char array or char * STRING, CHARADR, $REFERENCE $CHAR $INPLACEARRAY address of first character (STRING passed to C must be explicitly NUL-terminated)
array ARRAY, $REFERENCE $INPLACEARRAY address of first element
dataType * ADDRESS, $REFERENCE to aligned CLASS address of record or first ARRAY element

USES parameters are passed by value. MODIFIES, PRODUCES, and $REFERENCE parameters are passed by reference. The C * operator may be used when declaring MODIFIES, PRODUCES, and $REFERENCE parameters.

USES parameters of MAINSAIL types STRING and POINTER can be passed from MAINSAIL to C. Parameters of MAINSAIL types POINTER and STRING cannot be passed from C to MAINSAIL. MODIFIES and PRODUCES parameters of MAINSAIL types STRING and POINTER are not allowed.

MAINSAIL STRINGs can be directly passed to C, i.e., the parameter is declared using the MAINSAIL STRING data type. C expects strings to be terminated with a NUL byte; $cStr(s) can be used to append a NUL byte to the MAINSAIL STRING s.

When a MAINSAIL POINTER is passed to C, the C structure and the MAINSAIL CLASS must be declared such that the data in the structure are accessed correctly by both languages; use the $ALIGN directive to accomplish this.

Inplace ARRAYs and records can be passed only as $REFERENCE parameters.

The MAINSAIL representation of a BOOLEAN should be translated into C as a short, with 0 representing MAINSAIL FALSE and 1 representing MAINSAIL TRUE.

9.2.1. MAINSAIL and C Arrays

ARRAY parameters are passed to C by passing the address of the first element of the ARRAY. The Foreign Call Compiler generates code to convert each MAINSAIL dynamic ARRAY parameter to the address of its first element. MAINSAIL stores ARRAYs in row-major form. If your C implementation does not follow this convention, care must be taken with the indices.

A MAINSAIL NULLARRAY is passed to C as a Zero address. C must check that the address is non-Zero before accessing any array elements if there is a possibility that a MAINSAIL NULLARRAY has been passed.

In order to get the address of the first element of a MAINSAIL ARRAY that is not a parameter, but rather a field or element of a data structure passed to C, you must use the C function xiAdrOfFirstElement; see Section 7.9 of the MAINSAIL Compiler User's Guide.

9.3. Caveat

When dealing with collectable MAINSAIL data types (STRINGs, POINTERs, and dynamic ARRAYs), care must be taken not to violate the data boundaries. Overwriting the wrong parts of these structures may cause MAINSAIL to crash in ways that are difficult to trace. If, for example, a garbage collection link is destroyed, MAINSAIL may run until a collection is triggered, at which point the results are unpredictable.

9.4. MAINSAIL Foreign Call Compiler Example

Suppose that the MAINSAIL MODULE CALLC calls the C procedure proc1. Figures
9–1, 9–2, and 9–3 show the MODULE CALLC, the C procedure proc1, and the MAINSAIL FLI MODULE MSTOC, respectively.

Figure 9–1. MAINSAIL MODULE CALLC That Calls C Procedure proc1
MODULE CALLC (in file callc.msl):

BEGIN "callC"

MODULE msToC (
    
PROCEDURE proc1 (
        
PRODUCES $CSHORT        i;
        
$CSHORT                 j,k;
        
PRODUCES CHARADR        c;
        
POINTER(cl)             p;
        
STRING                  s;
        
BOOLEAN($shortSizeARRAY(1 TO 2)
                                
ary);
    );

$ALIGN CLASS cl ($CINT li1,li2);

INITIAL PROCEDURE;
BEGIN
INTEGER                 i;
STRING                  s;
POINTER(cl)             p;
CHARADR                 c;
BOOLEAN ARRAY(1 TO 2)   ary;
C procedure proc1 does the following:
#   (1) 
adds j and k and returns the result in i
#   (2) 
creates a string and returns the address of its
#       
first character in c
#   (3) 
swaps the values of the fields of CLASS c1
#   (4) 
prints the value of s
#   (5) 
sets ary[1] to be FALSE
p := new(cl); p.li1 := 1L; p.li2 := 2L;
s := $cStr("Hello there!");
new(ary); ary[1] := ary[2] := TRUE;
proc1(i,1,2,c,p,s,ary);
write(logFile,"i = ",i,eol &
    "
String returned by proc1 = ",$msStr(c),eol &
    "
p.li1 = ",p.li1,"; p.li2 = ",p.li2,eol &
    "
ary[1] = ary[2]: ",
        
IF ary[1] = ary[2] THEN "TRUEEL "FALSE",eol);
END;

END "callC"

Figure 9–2. C Procedure proc1
C procedure proc1 (in file cproc.c):

proc1 (i,j,k,c,p,s,ary)
short *i;
short j,k;
char **c;
struct {int li1,li2;} *p;
char s[];
short ary[];
{
int temp;
*
i = j + k;
*
c = "Bye for now..."; /* New value for string */
temp = p->li1p->li1 = p->li2p->li2 = temp;
printf("String is %s\n",s);
ary[1] = 0;
}

Figure 9–3. MAINSAIL Foreign Language Interface MODULE MSTOC
MAINSAIL MODULE MSTOC (in file mstoc.msl):

BEGIN "msToC"

MODULE msToC (
    
PROCEDURE proc1 (
        
PRODUCES $CSHORT        i;
        
$CSHORT                 j,k;
        
PRODUCES CHARADR        c;
        
POINTER(cl)             p;
        
STRING                  s;
        
BOOLEAN($shortSizeARRAY(1 TO 2)
                                
ary);
    );

PROCEDURE proc1 (
    
PRODUCES $CSHORT        i;
    
$CSHORT                 j,k;
    
PRODUCES CHARADR        c;
    
POINTER(cl)             p;
    
STRING                  s;
    
BOOLEAN($shortSizeARRAY(1 TO 2)
                            
ary);
;

END "msToC"

Take the following steps to compile and link the program of Figures 9–1, 9–2, and 9–3:

  1. Compile CALLC with the normal MAINSAIL compiler for NTPNT. Compile MSTOC with the FCC to C (by specifying the compiler subcommand FLI TC):

    *compil<eol>
    MAINSAIL (Rcompiler
    Copyright (c) ...

    compile (? for help): callc.msl<eol>
    Opening intmod for $SYS...

    callc.msl 1 ...

    Objmod for CALLC on callc-mpn.obj
    Intmod for CALLC not stored

    compile (? for help): mstoc.msl,<eol>
    >
    fli tc<eol>
    >
    <eol>
    Opening intmod for $SYS...

    mstoc.msl 1 ...

    Output for MSTOC on mstoc.s
    Intmod for MSTOC not stored

    compile (? for help):
    *

  2. Make a new MAINSAIL bootstrap that declares MSTOC to be a foreign MODULE. The foreign MODULE names must be uppercase; the NTPNT assembler is case-sensitive.

    *conf<eol>
    MAINSAIL (RBootstrap Configurator
    Restoring configuration values from file
        
    c:\mainsail\16.20.1\ntpnt.cnf
    CONFbootfilename fcc.s<eol>
    CONFforeignmodules<eol>
    FOREIGNMODULES is
    ...
    Should be:
    =<eol>
    MSTOC<eol>
    <eol>
    CONF<eol>
    Bootstrap written in file fcc.s
    *
    <eol>

  3. Compile the C code with the C compiler to create a .obj file (refer to your compiler documentation for other options you may wish to set).

    C:\MYDIR>cl /c cproc.c<eol>

  4. Assemble the output from CONF:

    C:\MYDIR>ml /c /coff fcc.s<eol>

  5. Assemble the output from the FLI compiler:

    C:\MYDIR>ml /c /coff mstoc.s<eol>

  6. Link the new MAINSAIL bootstrap (the command shown is for a Windows-based application; to make a character-based application, use mc.txt instead of m.txt):

    C:\MYDIR>link -out:fcc.exe fcc.obj cproc.obj mstoc.obj @c:\mainsail\16.20.1\m.txt<eol>

  7. Run the new executable MAINSAIL bootstrap and call the foreign procedure.

    C:\MYDIR>fcc<eol>
    MAINSAIL (RVersion 16.20.1 (? for help)
    ...
    *
    callc<eol>

9.5. MAINSAIL Entry Compiler Example

The MAINSAIL Entry Compiler (MEC) provides the ability to invoke MAINSAIL from a C main program or from a C function.

Suppose that the C procedure callms is to call the MAINSAIL PROCEDURE proc1. Figures 9–4, 9–5, 9–6, and 9–7 show the C procedure callms, the MAINSAIL MODULE MSMOD that contains the PROCEDURE proc1, the MAINSAIL FLI MODULE MSTOC, and the MAINSAIL MODULE CALLC that calls the C procedure callms, respectively.

Figure 9–4. C Procedure That Calls MAINSAIL PROCEDURE proc1
C program (in file callms.c):

callms ()
{
/*  
MAINSAIL proc1 does the following:
    (1) 
Adds its first two arguments and returns
        
the result
    (2) 
Sets bo to be TRUE
*/
short bo;
int result,li1,li2;
bo = 0; li1 = 1; li2 = 2;
result = proc1(li1,li2,&bo);
printf("Result is %d\n",result);
if (bo == 0) {printf("FAILUREbo should be nonZero\n");}
}

Figure 9–5. MAINSAIL MODULE MSMOD Called by C Procedure callms
MAINSAIL MODULE MSMOD (in file msmod.msl):

BEGIN "msMod"

MODULE msMod (
    
$CINT PROCEDURE proc1 (
        
$CINT               li1,li2;
        
PRODUCES BOOLEAN($shortSize)
                            
bo);
    );

$CINT PROCEDURE proc1 (
    
$CINT               li1,li2;
    
PRODUCES BOOLEAN($shortSize)
                        
bo);
BEGIN
bo := TRUE;
RETURN(li1 + li2);
END;

END "msMod"

Figure 9–6. MAINSAIL Foreign Language Interface MODULE MSTOC
MAINSAIL MODULE MSTOC (in file mstoc.msl):

BEGIN "msToC"

MODULE msToC (PROCEDURE callMs);

PROCEDURE callMs;;

END "msToC"

Figure 9–7. MAINSAIL MODULE CALLC That Calls C Procedure callms
MAINSAIL MODULE CALLC (in file callc.msl):

BEGIN "callC"

MODULE msToC (PROCEDURE callMs);

INITIAL PROCEDURE;
callMs;

END "callC"

Follow these steps to compile and run callms:

  1. Compile MSMOD and CALLC with the regular MAINSAIL compiler for NTPNT. Compile MSMOD with the MEC from C (by specifying the compiler subcommand FLI FC). Compile MSTOC with the FCC to C (by specifying the compiler subcommand FLI TC).

    *compil<eol>
    MAINSAIL (RCompiler
    Copyright...

    compile (? for help): msmod.msl<eol>
    Opening intmod for $SYS...

    msmod.msl 1 ...

    compile (? for help): callc.msl<eol>
    Opening intmod for $SYS...

    callc.msl ...

    compile (? for help): msmod.msl,<eol>
    >
    fli fc<eol>
    >
    <eol>
    Opening intmod for $SYS...

    msmod.msl 1 ...

    compile (? for help): mstoc.msl,<eol>
    >
    fli tc<eol>
    >
    <eol>
    Opening intmod for $SYS...

    mstoc.msl ...

    compile (? for help): <eol>
    *
    <eol>

  2. Make a new MAINSAIL bootstrap that declares MSTOC to be a foreign MODULE. The foreign MODULE names must be uppercase. The NTPNT assembler is case-sensitive.

    *conf<eol>
    MAINSAIL (RBootstrap Configurator
    Restoring configuration values from file
        
    c:\mainsail\16.20.1\ntpnt.cnf

    CONFbootfilename mec.s<eol>
    CONFforeignmodules<eol>
    FOREIGNMODULES is
    ...
    Should be:
    =<eol>
    MSTOC<eol>
    <eol>
    CONF<eol>
    Bootstrap written in file mec.s
    *
    <eol>

  3. Compile the C code with the C compiler to create a .obj file (refer to your compiler documentation for other options you may wish to set).

    C:\MYDIR>cl /c callms.c<eol>

  4. Assemble the output from CONF:

    C:\MYDIR>ml /c /coff mec.s<eol>

  5. Assemble both output files from the FLI compilers:

    C:\MYDIR>ml /c /coff msmod.s<eol>
    C:\MYDIR>ml /c /coff mstoc.s<eol>

  6. Link the new MAINSAIL bootstrap (the command shown is for a Windows-based application; to make a character-based application, use mc.txt instead of m.txt):

    C:\MYDIR>link -out:mec.exe mec.obj msmod.obj mstoc.obj callms.obj @c:\mainsail\16.20.1\m.txt<eol>

  7. Run the new executable MAINSAIL bootstrap and call the foreign procedure.

    C:\MYDIR>mec<eol>
    MAINSAIL (RVersion 16.20.1 (? for help)
    ...
    *
    callc<eol>
    Result is 3

If the foreign program is to start execution (i.e., the function main is part of your C program), you must modify the above sequence of steps as follows:

9.6. Additional FLI Considerations

9.6.1. Default Foreign Labels and Label Prefixes

On NTPNT, there is no label prefix, as there is on some operating systems. The default foreign label corresponding to a MAINSAIL PROCEDURE is just the MAINSAIL PROCEDURE name, converted to lower case, without any special prefix. This default label may be overridden with an ENCODE directive, as described in
Section 16.6 of the MAINSAIL Language Manual.
previous   next   top   contents   index   framed top   this page unframed

MAINSAIL System-Specific User's Guides, Chapter 9