An external class which interfaces to ANSI C is designated with the language identifier 'C'. Unlike external Fortran classes, external C classes may be instantiated (may point to runtime objects). External C classes may not be parameterized. Types defined by external C classes are called external C types.
In external C classes, signatures without bodies must only use external C types. Routines with bodies (are not abstract signatures) defined in external C classes may use other types, but if they do, these routines are not visible to C code. Routines that could be called from C may not be overloaded. 'out' and 'inout' arguments are passed by a pointer to a local, which may be legally modified by the routine. The Sather implementation must guarantee that such modifications cannot be observed until the routine returns.
Attributes may be placed in external C classes; they are interpreted as fields of a C struct. Such attributes may only have external C types. Similarly, shareds are interpreted as C global variables. Constants of external C types are interpreted as C constants or macros.
Example 15-1. For example, this C code:
typedef struct { int a,b; } *FOO; FOO xxyyz; |
Example 15-2. can be accessed by users of this Sather class:
external C class FOO is const C_name:STR:="FOO"; attr a, b:C_INT; shared xxyyz:FOO; end; |
There are two features of external C classes that have a special semantics. The STR constant 'C_name' may be used to force a particular C declaration to be used for an external C type. Similarly the STR constant 'C_header' may specify a space separated list of C header files that must be emitted at the beginning of any file in which the C declaration appears. 'C_name' and 'C_header' which must be constant STR when present.
Example 15-3. For example, this creates a Sather type 'X_WIDGET' which may be used to declare variables, parameterize classes, and so forth. Furthermore, the C declaration used for variables of type 'X_WIDGET' will be 'struct XSomeWidget *'. Any generated C file containing any variable of this type will also include '<widgets.h>'.
external C class X_WIDGET is const C_name:STR := "struct XSomeWidget *"; const C_header:STR := "<widgets.h>"; end; |
Sometimes it isn't possible to decide at the time the external C class is written whether a routine will be implemented in the C code with a macro. This presents a portability problem, because the writer of the external class can't know ahead of time whether the routine will be obtained by linking or by a header file. Such petulant cases can be dealt with by the call 'SYS::inlined_C'. The argument must be a string literal, and is placed directly into the generated code, except that identifiers following '#' that correspond to locals and arguments are translated into the appropriate C name. An alternate form accepts two arguments, making it possible to specify an include file or macro required by the inlined code, which will be placed at the top of the generated file.
Example 15-4. Here's an example from the UNIX headers:
SYS::inlined_C("#res = EPERM", "#include <errno.h>\n"); |
The following C types are built into the extended library; these external types also define appropriate creation routines which may be used for convenient casting between Sather and C types.
Table 15-2.
Sather type | ANSI C type | Sather type | ANSI C type |
---|---|---|---|
C_CHAR | char | C_UNSIGNED_CHAR_PTR | unsigned char * |
C_UNSIGNED_CHAR | unsigned char | C_SIGNED_CHAR_PTR | signed char * |
C_SIGNED_CHAR | signed char | C_SHORT_PTR | short * |
C_SHORT | short | C_INT_PTR | int * |
C_INT | int | C_LONG_PTR | long * |
C_LONG | long | C_UNSIGNED_SHORT_PTR | unsigned short * |
C_UNSIGNED_SHORT | unsigned short | C_UNSIGNED_INT_PTR | unsigned int * |
C_UNSIGNED_INT | unsigned int | C_UNSIGNED_LONG_PTR | unsigned long * |
C_UNSIGNED_LONG | signed long | C_FLOAT_PTR | float * |
C_FLOAT | float | C_DOUBLE_PTR | double * |
C_DOUBLE | double | C_LONG_DOUBLE_PTR | long double * |
C_LONG_DOUBLE | long double | C_SIZE_T | size_t |
C_PTR | void * | C_PTRDIFF_T | ptrdiff_t |
C_CHAR_PTR | char * |
In addition, 'AREF{T}' defines a routine 'array_ptr:C_PTR' which may be used to obtain a pointer to the first item in the array portion of Sather objects. The external routine may modify the contents of this array portion, but must not store the pointer; there is no guarantee that the pointer will remain valid after the external routine returns. This restriction ensures that the Sather type system and garbage collector will not be corrupted by external code, while not sacrificing efficiency for the most important cases.