.c -*-bolio-*-

.chapter "Foreign Language Interface"

.section "Introduction"

It is desireable to be able to call from lan{nil} procedures that are
written in other VMS supported languages, such as lan{Fortran},
lan{Cobol}, lan{PL1}, lan{Bliss}, lan{C}, lan{Pascal},
lan{Basic}, et. al., not to mention procedures written in
lan{Macro32}, and VMS library routines and system services.
Fortunately this is easy, due to the the uniform VMS object and symbol
table file format, uniform procedure call mechanism, and rich set of
lan{nil} datatypes from which to construct datastructures compatible
with what various foreign language routines expect to receive.

The presently implemented interface is by no means the last word in
such endevors; for example it makes no attempt to enforce datatype
restrictions in argument passing; however, it is found to be functional,
and is used in the lan{nil} system itself to access some VMS system services,
to incrementaly debug parts of the assembly-language kernal, and to
interface to "number-crunching" lan{Fortran} subroutines and to some
users existing lan{C} libraries.

.section "Kernel and System-Services"

The executable code for such procedures is already in the lisp process
address space, therefore accessing them is only a matter of defining
an argument-data-convention interface, searching the lisp or
system symbol table to get the required machine address, and creating
a lisp subr trampoline, similar to an element of a transfer vectors the
VMS linker would create when one references sharable libraries.

.defspec si:defsyscall (lisp-name vms-symbol) &rest argumentspecs
Does everything needed to reference a routine in "LISP.STB" or "SYS.STB".
The lisp-name is defined as a special-form taking alternating named
arguments as in a defstruct defined constuctor. For example, the
routine to convert a vms error code into a human-readable string:
.lisp
(defsyscall ($getmsg sys$getmsg)
  (msgid :in :long :required)
  (msglen :out :word :required)
  (bufadr :out :string :required)
  (flags :in :byte)
  (outadr :in :bits))

(defun decode-vms-error-code (loss-code &optional (flags 15)
			      &aux len)
  (using-resource (string-buffer string 256)
    ($getmsg msgid loss-code msglen len
	     bufadr string flags flags)
.end_lisp
N.B. Calls to 3SI:DEFSYSCALL*, and to many other system
internal primitives work when *compiled*, but not when intepreted.
The example above is from code in the systems-internals package.
.end_defspec

.section "VMS object files"
To call a procedure in a vms object file the user must do three things,
define an argument interface, call the dynamic loader,
and enable the trampolines for specific procedures. For example:

.lisp
(def-vms-call-interface myfoo)

(defun hack-foo ()
  (list (hack-vms-object-file "[gjc.nil]footest")
	(enable-vms-call-trampoline
	   'myfoo 'foo "[gjc.nil]footest.stb")))

(hack-foo)

! Sets up for this BLISS

MODULE FOOTEST =
BEGIN
GLOBAL ROUTINE FOO = 259;
END
ELUDOM

.end_lisp

.defun si:def-vms-call-interface name &rest arglist
Same as defsyscall, but doesn't actually look into any symbol table
or create any trampoline. Only works when compiled.
.end_defun

.defun si:hack-vms-object-file obj-file
Calls the VMS linker on a single object file, and then reads the executable
code into a bitstring in the lisp address space. Presently a VMS subprocess
interface is not implemented, (which is the easiest way for lisp to invoke
the VMS linker), so instead the user is asked to execute a VMS command
file lisp writes. This happens twice for every file so hacked. What
a kludge.
.end_defun

.defun si:enable-vms-call-trampoline name vms-symbol stb-file
Sets up the trampline for name using the address of the vms-symbol
from the stb-file.
.end_defun

.section "Data Conversion"

At a certain level it helps to know the data representations supported
by the VAX hardware itself, and what representations the various
language compilers, including lisp, build on this base. Lets face it,
at this point, unless you are willing to deal with such issues its
best to forward specific interface requests to the implementors,
and we'll try to at least provide a family of existing examples
which should make things obvious, or presolved. Even though the
macrology provided by 3defsyscall* et al. may make it easy,
it by no means makes things foolproof, as any such excursions outside
the lisp-world-firewall we set up are frought with frustrating
debugging problems.

In garbage collection, the system will not be forgiving of any violation
of the rules of register and stack usage, and raw address placement.

.section "lower level routines"
As if the ones above weren't low-level enough.

.defun si:locate-symbol-table-value symbol &rest stb-filenames
Returns null or a fixnum.
.end_defun
.defun si:construct-system-symbol-trampoline hi8-bits lo24-bits
Returns a trampoline subr which jumps to the address specified.
.end_defun


