[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Modifiers (revisited)



>  Date: Mon, 13 May 96 06:47:12 EDT
>  From: Mike Griebling <grieblm@trt.allied.com>
>  
>  I would like to request that we adopt a more relaxed view on what
>  is contained in a module.  The current modifiers for modules (ie.
>  ["C"] EXTERNAL ["lib.o"]) seem to require that all procedures in
>  a module be external C routines.  It is sometimes convenient,
>  however to also place Oberon2 routines in the same module.  
>  ...

There already exists a draft for the format of modules interfacing to
external C files (plain C code, object file or library).  Most of it
is implemented (untested, of course) for the ANSI-C back-end.  It
should cover most of your needs.  

As I said, it's just a draft, and it's bound to change.  Any comments
are welcome.

-- mva

file: ooc/back-end/ansi-c/doc/ExternalC
------------------------------------------------------------------------

#	$Id: ExternalC,v 1.2 1996/05/07 14:29:10 acken Exp oberon1 $
-*-Mode: Text-*-

Note 1: This document describes the facilities for interfacing to
external object files, similar to the facilities provided by o2c.
Unlike o2c, the format described here also covers the implementation
of true Oberon-2 modules in C.

Note 2: External modules have to be considered as unsafe, low-level,
and system (or rather compiler) dependent.  Any module accessing such
modules inherits all those unpleasant attributes unless, of course,
it's a well designed library module  ;-).

Note 3: This files overides most of the stuff found in 
frontend/doc/Modifiers 

------------------------------------------------------------------------

External C code comes in three flavors:
1) uncompiled file (E.c; example: low-level Files module implemented
   in C) 
2) object file resp. object archive (E.o, E.a; example: Boehm's
   conservative garbage collector is linked in as gc.a)
3) library (-lE; example: X11 libraries)

Obviously the first category must be turned into the second before it
can be of any use.  Therefore oo2c compiles a C file E.c if either the
object file E.o is missing or the file E.c is more recent than E.o.
Note that oo2c cannot detect if a file included into E.c has changed
and forces a recompilation of E.c.  The user has to compile E.c
himself if this occurs.

Category 2 adds input files to the linker command, 3) adds -lXXX
command line options.  It's up to the user to make sure that the
libraries (e.g. for -lX11) are on the linker's search path, either by
setting the appropriate environment variable or by adjusting the
"ldflags" option (part of the configuration file, can also be set from
the command line).

--------

Modifier Syntax 
[note: an object modifier is placed right after the declaration's
 name, a type modifier after the introducing keyword resp. before the
 formal parameter list]

ModuleModifiers = 
  "[" [ "INTERFACE" | "FOREIGN"] CallingConvention ["CODE_FILE"] 
      [ ";" "LINK" LinkSection {";" LinkSection} "END" ] "]".
CallingConvention = string.  
LinkSection = File | Object | Library.
File = "FILE" string.
Object = "OBJ" string.
Library = "LIB" string [DependenceList].
DependenceList = "(" string {"," string} ")".

Modifiers = "[" Modifier {"," Modifier} "]".
Modifier = 
  "NOT_EXTENSIBLE" | "NO_DESCRIPTOR" | "NO_LENGTH_INFO" |
  "STATIC_POINTER" | "DISABLE_NEW" | 
  "NO_TYPE_TAG" | "NO_LENGTH_TAG" | "NIL_COMPAT" |
  string | "HAS_BODY".

Examples of external modules:
MODULE Files0 [FOREIGN "C"; LINK FILE "FilesUnix.c" END];
MODULE GC [INTERFACE "C"; LINK OBJ "gc.a" END];
MODULE X11 [INTERFACE "C"; LINK LIB "X11" END];


  The word INTERFACE signals that this module is an interface to a C
object file (with all its different type and heap conventions).
Setting this flag influences the default behaviour of the objects
(most importantly types) defined later on.
  FOREIGN signals an Oberon module implemented in another language.
By default all declarations are assumed to comply to standard Oberon
behaviour. A foreign module M has to provide a function "void M__init
(void);".  It will be called during module initialization.
  The string after FOREIGN/INTERFACE specifies the calling convention,
i.e. the way parameters are passed to procedures.  The oo2c back-end
will only accept "C" here.
  With CODE_FILE this module is tranlated both into a header and a
code file.  Normally it's only necessary to emit the declarations into
the header, but sometimes it's desireable to be able to place standard
Oberon procedures into the external module, e.g. to model C macros.
  The FILE, OBJ, and LIB parts give the C files, object files, or
libraries that must be linked in whenever the interface module is used
(i.e. imported).  The LIB section has an extended syntax to cater for
dependencies between Unix libraries.  Example: a lib B building on
another lib A is referred to as LIB "B" ("A") meaning that "B" relies
on "A", and that they have to be linked in the sequence "-lB -lA".
The file names given as FILE or OBJ are put through the same file
search mechanism as Oberon-2 source files to get their directory,
unless their directory part isn't empty.  Example: FILE "lib/E.c"
would use the file <cwd>/lib/E.c (where <cwd> is the current working
directory), while FILE "E.c" refer to a file somewhere in the paths
defined in the configuration file.
  The rule `Modifiers' summarizes the flags that can be added to type,
parameter, variable, and procedure declarations.  Which flag is legal
depends on the kind of declaration it appears in.  A warning is given
if a flag that appears in the list is already set.



Flags modifying a type's behaviour:

RECORD Type
o NOT_EXTENSIBLE
  the record type cannot appear as base type of another record
o NO_DESCRIPTOR
  the record isn't associated with a type descriptor
o UNION
  translate this type into a C union instead of a struct

ARRAY Type
o NO_LENGTH_INFO
  the open array type hasn't any length information; such an array
  cannot have another open array as element type
o NO_DESCRIPTOR
  the array isn't associated with a type descriptor


POINTER Type
o STATIC_POINTER
  the pointer hasn't a type tag; if the pointer's base type is a
  record or an open array with NO_DESCRIPTOR, then this flag is
  automatically for the pointer type
o DISABLE_NEW
  Only SYSTEM.NEW (resp. a suitable low-level function of the OS) can
  allocate storage for a variable of this type; automatically set if
  the pointer or the base type is marked with one of the above flags
  (except for NOT_EXTENSIBLE)

PROCEDURE Type
A procedure type (this includes procedure declarations) inherits the
calling convention specified at the beginning of the module, unless a
string appear in the modifier list, which will be interpreted as the
procedure's calling convention and overides the global one.
  The special parameter `...' is allowed as final formal parameter of
a (bodyless) procedure declaration; it corresponds to the `variable
arguments' parameter in C, as used e.g. by printf().



Properties of External Objects:

Variable Declaration
  If its type is a record with NO_DESCRIPTOR, then it cannot appear in
type tests and type guards, and it cannot be passed to formal
parameter that expects a type tag.  
  The dynamic type of a record pointer that is marked as
STATIC_POINTER is always equal to its static type.
  If the variable is an (open) array type with NO_LENGTH_INFO, then
the predefined function LEN cannot be called on it.  The array value
cannot be passed to a formal open array parameter that expects to get
the length of every open dimension.

Parameter Declaration
  NO_TYPE_TAG means that a formal variable parameter of record type
isn't accompanied by a type tag.  Therefore this parameter can't
appear in a type test or type guard, and it cannot be passed to a
formal parameter that expects to get a type tag itself.  This flag is
implicitly set if the record type is marked with NO_DESCRIPTOR.
  A open array parameter with NO_LENGTH_TAG cannot be passed as first
argument to LEN, and it cannot be passed to a formal open array
parameter that expects to get the length of the open dimensions.  This
flag is implicitly set if the array type is marked with NO_LENGTH_INFO. 
  The value NIL can be passed to any formal parameter that has
NIL_COMPAT set.  This flag can only be set for parameters that are
passed by reference.

External Names
  Putting a string into the list of system flags of a declaration
(most notably a variable or a procedure) sets this name as the
declaration's C-level name.  This means, that instead of the name
generated by the oo2c compiler (normally module plus underscore plus
name), the given name is put into the C code.

Oberon-2 Procedures
  Normally a procedure declaration in an external module is taken to
be a declaration of an externally linked procedure definition,
i.e. they don't have a body.  By writing CODE_FILE into the module
header it's possible to define standard Oberon-2 procedures (including
a body part) in the module.  These procedures have to be marked with
HAS_BODY.

Miscellaneous stuff
o An underscore `_' can be used like a character in any identifier 
  defined in an INTERFACE module except for the module name itself.
o With the extended semantics of parameters, it's necessary to adjust
  the rules for matching parameter lists: two corresponding parameters
  are required to share the same system flags in order to match.


Summary INTERFACE
Linker names for variables and procedures are their respective Oberon
names, the other names are built like "module_objname".
The following flags are set:
  RECORD: NOT_EXTENSIBLE, NO_DESCRIPTOR
  ARRAY: NO_DESCRIPTOR, additional NO_LENGTH_INFO for open arrays
  POINTER: STATIC_POINTER, DISABLE_NEW
  Parameter: NO_TYPE_TAG resp. NO_LENGTH_TAG
Rest parameter `...' is allowed. Underscore is allowed in names.

Summary FOREIGN
Linker names for variables and procedures are built like
"module_objname".  No type flags are set, the types have standard
Oberon behaviour by default.  Rest parameter `...' is not
allowed. Underscore isn't allowed in names.