Obsolete.
This commit is contained in:
parent
2da600ffbb
commit
676cbbb8a8
|
@ -1,690 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<!-- HTML file produced from file: external.tex --
|
||||
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
|
||||
-- on Emacs 19.34.1, Tue Feb 23 18:21:44 1999 -->
|
||||
<HEAD>
|
||||
<TITLE>Mixing Scheme 48 and C</TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1 ALIGN=CENTER>Using C code with Scheme 48</H1>
|
||||
<H2 ALIGN=CENTER>Mike Sperber<BR><TT><FONT SIZE=-1>sperber@informatik.uni-tuebingen.de</FONT></TT><BR>Richard Kelsey<BR><TT><FONT SIZE=-1>kelsey@research.nj.nec.com</FONT></TT>
|
||||
</H2>
|
||||
<H3 ALIGN=CENTER>February 23, 1999</H3>
|
||||
<H3 ALIGN=CENTER>Abstract</H3>
|
||||
<BLOCKQUOTE>
|
||||
This document describes an interface for calling C functions
|
||||
from Scheme, calling Scheme functions from C, and allocating
|
||||
storage in the Scheme heap.
|
||||
These facilities are designed to link
|
||||
existing C libraries into Scheme 48 in order to use them from Scheme.
|
||||
To this end, Scheme 48 manages stub functions in C that
|
||||
negotiate between the calling conventions of Scheme and C and the
|
||||
memory allocation policies of both worlds.
|
||||
No stub generator is available yet, but writing them is a straightforward task.
|
||||
</BLOCKQUOTE>
|
||||
<H1><A NAME="1">Available Facilities</A></H1>
|
||||
|
||||
<P>The following facilities are available for interfacing between
|
||||
Scheme 48 and C:
|
||||
<UL><LI>Scheme code can call C functions.
|
||||
<LI>The external interface provides full introspection for all
|
||||
Scheme objects. External code may inspect, modify, and allocate
|
||||
Scheme objects arbitrarily.
|
||||
<LI>External code may raise exceptions back to Scheme 48 to
|
||||
signal errors.
|
||||
<LI>External code may call back into Scheme. Scheme 48
|
||||
correctly unrolls the process stack on non-local exits.
|
||||
<LI>External modules may register bindings of names to values with a
|
||||
central registry accessible from
|
||||
Scheme. Conversely, Scheme code can register shared
|
||||
bindings for access by C code.
|
||||
</UL>
|
||||
This document has three parts: the first describes how bindings are
|
||||
moved from Scheme to C and vice versa, the second tells how to call
|
||||
C functions from Scheme, and the third covers the C interface
|
||||
to Scheme objects, including calling Scheme procedures, using the
|
||||
Scheme heap, and so forth.
|
||||
<H2><A NAME="2">Scheme structures</A></H2>
|
||||
<P>The structure <CODE>external-calls</CODE> has
|
||||
most of the Scheme functions described here.
|
||||
The others are in
|
||||
<CODE>dynamic-externals</CODE>, which has the functions for dynamic loading and
|
||||
name lookup from
|
||||
|
||||
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>,
|
||||
and <CODE>shared-bindings</CODE>, which has the additional shared-binding functions
|
||||
described in
|
||||
|
||||
the section on the <A HREF="#more-shared-bindings">complete shared-binding interface</A>.
|
||||
<H2><A NAME="3">C naming conventions</A></H2>
|
||||
<P>The names of all of Scheme 48's visible C bindings begin
|
||||
with `<CODE>s48_</CODE>' (for procedures and variables) or
|
||||
`<CODE>S48_</CODE>' (for macros).
|
||||
Whenever a C name is derived from a Scheme identifier, we
|
||||
replace `<CODE>-</CODE>' with `<CODE>_</CODE>' and convert letters to lowercase
|
||||
for procedures and uppercase for macros.
|
||||
A final `<CODE>?</CODE>' converted to `<CODE>_p</CODE>' (`<CODE>_P</CODE>' in C macro names).
|
||||
A final `<CODE>!</CODE>' is dropped.
|
||||
Thus the C macro for Scheme's <CODE>pair?</CODE> is <CODE>S48_PAIR_P</CODE> and
|
||||
the one for <CODE>set-car!</CODE> is <CODE>S48_SET_CAR</CODE>.
|
||||
Procedures and macros that do not check the types of their arguments
|
||||
have `<CODE>unsafe</CODE>' in their names.
|
||||
<P>All of the C functions and macros described have prototypes or definitions
|
||||
in the file <CODE>c/scheme48.h</CODE>.
|
||||
The C type for Scheme values is defined there to be <CODE>s48_value</CODE>.
|
||||
<H1><A NAME="4">Shared bindings</A></H1>
|
||||
|
||||
<P>Shared bindings are the means by which named values are shared between Scheme
|
||||
code and C code.
|
||||
There are two separate tables of shared bindings, one for values defined in
|
||||
Scheme and accessed from C and the other for values going the other way.
|
||||
Shared bindings actually bind names to cells, to allow a name to be looked
|
||||
up before it has been assigned.
|
||||
This is necessary because C initialization code may be run before or after
|
||||
the corresponding Scheme code, depending on whether the Scheme code is in
|
||||
the resumed image or is run in the current session.
|
||||
<H2><A NAME="5">Exporting Scheme values to C</A></H2>
|
||||
<UL><LI><CODE>(define-exported-binding<I> name value</I>) -> <I>shared-binding</I></CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value s48_get_imported_binding(char *name)</CODE>
|
||||
<LI><CODE>s48_value S48_SHARED_BINDING_REF(s48_value shared_binding)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Define-exported-binding</CODE> makes <CODE><I>value</I></CODE> available to C code
|
||||
under as <CODE><I>name</I></CODE> which must be a <CODE><I>string</I></CODE>, creating a new shared
|
||||
binding if necessary.
|
||||
The C function <CODE>s48_get_imported_binding</CODE> returns the shared binding
|
||||
defined for <CODE>name</CODE>, again creating it if necessary.
|
||||
The C macro <CODE>S48_SHARED_BINDING_REF</CODE> dereferences a shared binding,
|
||||
returning its current value.
|
||||
<H2><A NAME="6">Exporting C values to Scheme</A></H2>
|
||||
<UL><LI><CODE>void s48_define_exported_binding(char *name, s48_value value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>(lookup-imported-binding<I> string</I>) -> <I>shared-binding</I></CODE>
|
||||
<LI><CODE>(shared-binding-ref<I> shared-binding</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
<P>These are used to define shared bindings from C and to access them
|
||||
from Scheme.
|
||||
Again, if a name is looked up before it has been defined, a new binding is
|
||||
created for it.
|
||||
<P>The common case of exporting a C function to Scheme can be done using
|
||||
the macro <CODE>S48_EXPORT_FUNCTION(<EM>name</EM>)</CODE>.
|
||||
This expands into
|
||||
<P><CODE>s48_define_exported_binding("<CODE><I>name</I></CODE>", s48_enter_pointer(<CODE><I>name</I></CODE>))</CODE>
|
||||
<P>which boxes the function into a Scheme byte vector and then
|
||||
exports it.
|
||||
Note that <CODE>s48_enter_pointer</CODE> allocates space in the Scheme heap
|
||||
and might trigger a
|
||||
<A HREF="#gc">garbage collection</A>.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-definition <CODE><I>name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-definition <CODE><I>name c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
</UL>
|
||||
These macros simplify importing definitions from C to Scheme.
|
||||
They expand into
|
||||
<P><CODE>(define <CODE><I>name</I></CODE> (lookup-imported-binding <CODE><I>c-name</I></CODE>))</CODE>
|
||||
<P>where <CODE><I>c-name</I></CODE> is as supplied for the second form.
|
||||
For the first form <CODE><I>c-name</I></CODE> is derived from <CODE><I>name</I></CODE> by
|
||||
replacing `<CODE>-</CODE>' with `<CODE>_</CODE>' and converting letters to lowercase.
|
||||
For example, <CODE>(import-definition my-foo)</CODE> expands into
|
||||
<P><CODE>(define my-foo (lookup-imported-binding "my_foo"))</CODE>
|
||||
<H2><A NAME="more-shared-bindings">Complete shared binding interface</A></H2>
|
||||
|
||||
<P>There are a number of other Scheme functions related to shared bindings;
|
||||
these are in the structure <CODE>shared-bindings</CODE>.
|
||||
<UL><LI><CODE>(shared-binding?<I> x</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(shared-binding-name<I> shared-binding</I>) -> <I>string</I></CODE>
|
||||
<LI><CODE>(shared-binding-is-import?<I> shared-binding</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(shared-binding-set!<I> shared-binding value</I>)</CODE>
|
||||
<LI><CODE>(define-imported-binding<I> string value</I>)</CODE>
|
||||
<LI><CODE>(lookup-exported-binding<I> string</I>)</CODE>
|
||||
<LI><CODE>(undefine-imported-binding<I> string</I>)</CODE>
|
||||
<LI><CODE>(undefine-exported-binding<I> string</I>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Shared-binding?</CODE> is the predicate for shared-bindings.
|
||||
<CODE>Shared-binding-name</CODE> returns the name of a binding.
|
||||
<CODE>Shared-binding-is-import?</CODE> is true if the binding was defined from C.
|
||||
<CODE>Shared-binding-set!</CODE> changes the value of a binding.
|
||||
<CODE>Define-imported-binding</CODE> and <CODE>lookup-exported-binding</CODE> are
|
||||
Scheme versions of <CODE>s48_define_exported_binding</CODE>
|
||||
and <CODE>s48_lookup_imported_binding</CODE>.
|
||||
The two <CODE>undefine-</CODE> procedures remove bindings from the two tables.
|
||||
They do nothing if the name is not found in the table.
|
||||
<P>The following C macros correspond to the Scheme functions above.
|
||||
<UL><LI><CODE>int S48_SHARED_BINDING_P(x)</CODE>
|
||||
<LI><CODE>int S48_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||||
<LI><CODE>s48_value S48_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||||
<LI><CODE>void S48_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||||
</UL>
|
||||
<H1><A NAME="8">Calling C Functions from Scheme</A></H1>
|
||||
|
||||
<P>There are three different ways to call C functions from Scheme, depending on
|
||||
how the C function was obtained.
|
||||
<UL><LI><CODE>(call-imported-binding<I> binding arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
<LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
<LI><CODE>(call-external-value<I> value name arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
Each of these applies its first argument, a C function, to the rest of
|
||||
the arguments.
|
||||
For <CODE>call-imported-binding</CODE> the function argument must be an
|
||||
imported binding.
|
||||
For <CODE>call-external</CODE> the function argument must be an external
|
||||
bound in the current process
|
||||
(see
|
||||
|
||||
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>).
|
||||
For <CODE>call-external-value</CODE> <CODE><I>value</I></CODE> must be a byte vector
|
||||
whose contents is a pointer to a C function and <CODE><I>name</I></CODE> should be
|
||||
a string naming the function.
|
||||
The <CODE><I>name</I></CODE> argument is used only for printing error messages.
|
||||
<P>For all of these, the C function is passed the <CODE><I>arg<I><sub>i</sub></I></I></CODE> values
|
||||
and the value returned is that returned by C procedure.
|
||||
Up to twelve arguments may be passed.
|
||||
There is no method supplied for returning multiple values to
|
||||
Scheme from C (or vice versa) (mainly because C does not have multiple return
|
||||
values).
|
||||
<P>Keyboard interrupts that occur during a call to a C function are ignored
|
||||
until the function returns to Scheme (this is clearly a
|
||||
problem; we are working on a solution).
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...))</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...) <CODE><I>c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
</UL>
|
||||
These macros simplify importing functions from C.
|
||||
They define <CODE><I>name</I></CODE> to be a function with the given formals that
|
||||
applies those formals to the corresponding C binding.
|
||||
<CODE><I>C-name</I></CODE>, if supplied, should be a string.
|
||||
These expand into
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define temp (lookup-imported-binding <CODE><I>c-name</I></CODE>))
|
||||
(define <CODE><I>name</I></CODE>
|
||||
(lambda (<CODE><I>formal</I></CODE> ...)
|
||||
(external-apply temp <CODE><I>formal</I></CODE> ...)))
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>
|
||||
If <CODE><I>c-name</I></CODE> is not supplied, it is derived from <CODE><I>name</I></CODE> by converting
|
||||
all letters to lowercase and replacing `<CODE>-</CODE>' with `<CODE>_</CODE>'.
|
||||
<H1><A NAME="9">Adding external modules to the <CODE>Makefile</CODE></A></H1>
|
||||
|
||||
<P>Getting access to C bindings from Scheme requires that the C code be
|
||||
compiled an linked in with the Scheme 48 virtual machine and that the
|
||||
relevent shared-bindings be created.
|
||||
The Scheme 48 makefile has rules for compiling and linking external code
|
||||
and for specifying initialization functions that should be called on
|
||||
startup.
|
||||
There are three Makefile variables that control which external modules are
|
||||
included in the executable for the virutal machine (<CODE>scheme48vm</CODE>).
|
||||
<CODE>EXTERNAL_OBJECTS</CODE> lists the object files to be included in
|
||||
<CODE>scheme48vm</CODE>,
|
||||
<CODE>EXTERNAL_FLAGS</CODE> is a list of <CODE>ld</CODE> flags to be used when
|
||||
creating <CODE>scheme48vm</CODE>, and
|
||||
<CODE>EXTERNAL_INITIALIZERS</CODE> is a list of C procedures to be called
|
||||
on startup.
|
||||
The procedures listed in <CODE>EXTERNAL_INITIALIZERS</CODE> should take no
|
||||
arguments and have a return type of <CODE>void</CODE>.
|
||||
After changing the definitions of any of these variables you should
|
||||
do <CODE>make scheme48vm</CODE> to rebuild the virtual machine.
|
||||
<H1><A NAME="dynamic-externals">Dynamic Loading</A></H1>
|
||||
|
||||
<P>External code can be loaded into a running Scheme 48 process
|
||||
and C object-file bindings can be dereferenced at runtime and
|
||||
their values called
|
||||
(although not all versions of Unix support all of this).
|
||||
The required Scheme functions are in the structure <CODE>dynamic-externals</CODE>.
|
||||
<UL><LI><CODE>(dynamic-load<I> string</I>)</CODE>
|
||||
</UL>
|
||||
<CODE>Dynamic-load</CODE> loads the named file into the current
|
||||
process, raising an exception if the file cannot be found or if dynamic
|
||||
loading is not supported by the operating system.
|
||||
The file must have been compiled and linked appropriately.
|
||||
For Linux, the following commands compile <CODE>foo.c</CODE> into a
|
||||
file <CODE>foo.so</CODE> that can be loaded dynamically.
|
||||
<BLOCKQUOTE><PRE>
|
||||
% gcc -c -o foo.o foo.c
|
||||
% ld -shared -o foo.so foo.o
|
||||
</PRE></BLOCKQUOTE>
|
||||
<UL><LI><CODE>(get-external<I> string</I>) -> <I>external</I></CODE>
|
||||
<LI><CODE>(external?<I> x</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(external-name<I> external</I>) -> <I>string</I></CODE>
|
||||
<LI><CODE>(external-value<I> external</I>) -> <I>byte-vector</I></CODE>
|
||||
</UL>
|
||||
These functions give access to values bound in the current process, and
|
||||
are used for retrieving values from dynamically-loaded files.
|
||||
<CODE>Get-external</CODE> returns an <I>external</I> object that contains the
|
||||
value of <CODE><I>name</I></CODE>, raising an exception if there is no such
|
||||
value in the current process.
|
||||
<CODE>External?</CODE> is the predicate for externals, and
|
||||
<CODE>external-name</CODE> and <CODE>external-value</CODE> return the name and
|
||||
value of an external.
|
||||
The value is returned as byte vector of length four (on 32-bit
|
||||
architectures).
|
||||
The value is that which was extant when <CODE>get-external</CODE> was
|
||||
called.
|
||||
The following two functions can be used to update the values of
|
||||
externals.
|
||||
<UL><LI><CODE>(lookup-external<I> external</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(lookup-all-externals<I></I>) -> <I>boolean</I></CODE>
|
||||
</UL>
|
||||
<CODE>Lookup-external</CODE> updates the value of <CODE><I>external</I></CODE> by looking its
|
||||
name in the current process, returning <CODE>#t</CODE> if it is bound and <CODE>#f</CODE>
|
||||
if it is not.
|
||||
<CODE>Lookup-all-externals</CODE> calls <CODE>lookup-external</CODE> on all extant
|
||||
externals, returning <CODE>#f</CODE> any are unbound.
|
||||
<UL><LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
An external whose value is a C procedure can be called using
|
||||
<CODE>call-external</CODE>.
|
||||
See
|
||||
|
||||
the section on <A HREF="#8">calling C functions from Scheme</A>
|
||||
for more information.
|
||||
<P>In some versions of Unix retrieving a value from the current
|
||||
process may require a non-trivial amount of computation.
|
||||
We recommend that a dynamically-loaded file contain a single initialization
|
||||
procedure that creates shared bindings for the values exported by the file.
|
||||
<H1><A NAME="11">Compatibility</A></H1>
|
||||
<P>Scheme 48's old <CODE>external-call</CODE> function is still available in the structure
|
||||
<CODE>externals</CODE>, which now also includes <CODE>external-name</CODE> and
|
||||
<CODE>external-value</CODE>.
|
||||
The old <CODE>scheme48.h</CODE> file has been renamed <CODE>old-scheme48.h</CODE>.
|
||||
<H1><A NAME="12">Accessing Scheme data from C</A></H1>
|
||||
|
||||
<P>The C header file <CODE>scheme48.h</CODE> provides
|
||||
access to Scheme 48 data structures
|
||||
(for compatibility, the old <CODE>scheme48.h</CODE> file is available
|
||||
as <CODE>old-scheme48.h</CODE>).
|
||||
The type <CODE>s48_value</CODE> is used for Scheme values.
|
||||
When the type of a value is known, such as the integer returned
|
||||
by <CODE>vector-length</CODE> or the boolean returned by <CODE>pair?</CODE>,
|
||||
the corresponding C procedure returns a C value of the appropriate
|
||||
type, and not a <CODE>s48_value</CODE>.
|
||||
Predicates return <CODE>1</CODE> for true and <CODE>0</CODE> for false.
|
||||
<H2><A NAME="13">Constants</A></H2>
|
||||
|
||||
<P>The following macros denote Scheme constants:
|
||||
<DL><DT><B><CODE>S48_FALSE</CODE></B><DD> is <CODE>#f</CODE>.
|
||||
<DT><B><CODE>S48_TRUE</CODE></B><DD> is <CODE>#t</CODE>.
|
||||
<DT><B><CODE>S48_NULL</CODE></B><DD> is the empty list.
|
||||
<DT><B><CODE>S48_UNSPECIFIC</CODE></B><DD> is a value used for functions which have no
|
||||
meaningful return value
|
||||
(in Scheme this value returned by the nullary procedure <CODE>unspecific</CODE>
|
||||
in the structure <CODE>util</CODE>).
|
||||
<DT><B><CODE>S48_EOF</CODE></B><DD> is the end-of-file object
|
||||
(in Scheme this value is returned by the nullary procedure <CODE>eof-object</CODE>
|
||||
in the structure <CODE>i/o-internal</CODE>).
|
||||
</DL>
|
||||
<H2><A NAME="14">Converting values</A></H2>
|
||||
<P>The following functions convert values between Scheme and C
|
||||
representations.
|
||||
The `extract' ones convert from Scheme to C and the `enter's go the other
|
||||
way.
|
||||
<UL><LI><CODE>unsigned char s48_extract_char(s48_value)</CODE>
|
||||
<LI><CODE>char * s48_extract_string(s48_value)</CODE>
|
||||
<LI><CODE>long s48_extract_integer(s48_value)</CODE>
|
||||
<LI><CODE>double s48_extract_double(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_enter_char(unsigned char)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_string(char *)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_integer(long)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_double(double)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<P>The value returned by <CODE>s48_extract_string</CODE> points to the actual
|
||||
storage used by the string; it is valid only until the next
|
||||
<A HREF="#gc">garbage collection</A>.
|
||||
<P><CODE>s48_enter_integer()</CODE> needs to allocate storage when
|
||||
its argument is too large to fit in a Scheme 48 fixnum.
|
||||
In cases where the number is known to fit within a fixnum (currently 30 bits
|
||||
including the sign), the following procedures can be used.
|
||||
These have the disadvantage of only having a limited range, but
|
||||
the advantage of never causing a garbage collection.
|
||||
<UL><LI><CODE>long s48_extract_fixnum(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_enter_fixnum(long)</CODE>
|
||||
<LI><CODE>long S48_MAX_FIXNUM_VALUE</CODE>
|
||||
<LI><CODE>long S48_MIN_FIXNUM_VALUE</CODE>
|
||||
</UL>
|
||||
<P>An error is signalled if <CODE>s48_extract_fixnum</CODE>'s argument
|
||||
is not a fixnum or if the argument to <CODE>s48_enter_fixnum</CODE> is less than
|
||||
<CODE>S48_MIN_FIXNUM_VALUE</CODE> or greater than <CODE>S48_MAX_FIXNUM_VALUE</CODE>
|
||||
(<I>-2<sup>29</sup></I> and <I>2<sup>29</sup>-1</I> in the current system).
|
||||
<H2><A NAME="15">C versions of Scheme procedures</A></H2>
|
||||
<P>The following macros and procedures are C versions of Scheme procedures.
|
||||
The names were derived by replacing `<CODE>-</CODE>' with `<CODE>_</CODE>',
|
||||
`<CODE>?</CODE>' with `<CODE>p</CODE>', and dropping `<CODE>!</CODE>.
|
||||
<UL><LI><CODE>int S48_EQ_P(s48_value)</CODE>
|
||||
<LI><CODE>int S48_CHAR_P(s48_value)</CODE>
|
||||
<LI><CODE>int S48_INTEGER_P(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_PAIR_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_CAR(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_CDR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_SET_CAR(s48_value, s48_value)</CODE>
|
||||
<LI><CODE>void S48_SET_CDR(s48_value, s48_value)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_cons(s48_value, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>long s48_length(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_VECTOR_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_vector(long, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_STRING_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_STRING_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_STRING_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_STRING_SET(s48_value, long, char)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_string(long, char)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_SYMBOL_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_SYMBOL_TO_STRING(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_BYTE_VECTOR_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_byte_vector(long, int)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<H1><A NAME="16">Calling Scheme functions from C</A></H1>
|
||||
|
||||
<P>External code that has been called from Scheme can call back to Scheme
|
||||
procedures using the following function.
|
||||
<UL><LI><CODE>scheme_value s48_call_scheme(s48_value proc, long nargs, ...)</CODE>
|
||||
</UL>
|
||||
This calls the Scheme procedure <CODE>proc</CODE> on <CODE>nargs</CODE>
|
||||
arguments, which are passed as additional arguments to <CODE>s48_call_scheme</CODE>.
|
||||
There may be at most ten arguments.
|
||||
The value returned by the Scheme procedure is returned by the C procedure.
|
||||
Invoking any Scheme procedure may potentially cause a garbage collection.
|
||||
<P>There are some complications that occur when mixing calls from C to Scheme
|
||||
with continuations and threads.
|
||||
C only supports downward continuations (via <CODE>longjmp()</CODE>).
|
||||
Scheme continuations that capture a portion of the C stack have to follow the
|
||||
same restriction.
|
||||
For example, suppose Scheme procedure <CODE>s0</CODE> captures continuation <CODE>a</CODE>
|
||||
and then calls C procedure <CODE>c0</CODE>, which in turn calls Scheme procedure
|
||||
<CODE>s1</CODE>.
|
||||
Procedure <CODE>s1</CODE> can safely call the continuation <CODE>a</CODE>, because that
|
||||
is a downward use.
|
||||
When <CODE>a</CODE> is called Scheme 48 will remove the portion of the C stack used
|
||||
by the call to <CODE>c0</CODE>.
|
||||
On the other hand, if <CODE>s1</CODE> captures a continuation, that continuation
|
||||
cannot be used from <CODE>s0</CODE>, because by the time control returns to
|
||||
<CODE>s0</CODE> the C stack used by <CODE>c0</CODE> will no longer be valid.
|
||||
An attempt to invoke an upward continuation that is closed over a portion
|
||||
of the C stack will raise an exception.
|
||||
<P>In Scheme 48 threads are implemented using continuations, so the downward
|
||||
restriction applies to them as well.
|
||||
An attempt to return from Scheme to C at a time when the appropriate
|
||||
C frame is not on top of the C stack will cause the current thread to
|
||||
block until the frame is available.
|
||||
For example, suppose thread <CODE>t0</CODE> calls a C procedure which calls back
|
||||
to Scheme, at which point control switches to thread <CODE>t1</CODE>, which also
|
||||
calls C and then back to Scheme.
|
||||
At this point both <CODE>t0</CODE> and <CODE>t1</CODE> have active calls to C on the
|
||||
C stack, with <CODE>t1</CODE>'s C frame above <CODE>t0</CODE>'s.
|
||||
If thread <CODE>t0</CODE> attempts to return from Scheme to C it will block,
|
||||
as its frame is not accessable.
|
||||
Once <CODE>t1</CODE> has returned to C and from there to Scheme, <CODE>t0</CODE> will
|
||||
be able to resume.
|
||||
The return to Scheme is required because context switches can only occur while
|
||||
C code is running.
|
||||
<CODE>T0</CODE> will also be able to resume if <CODE>t1</CODE> uses a continuation to
|
||||
throw past its call to C.
|
||||
<H1><A NAME="gc">Interacting with the Scheme Heap</A></H1>
|
||||
|
||||
|
||||
<P>Scheme 48 uses a copying, precise garbage collector.
|
||||
Any procedure that allocates objects within the Scheme 48 heap may trigger
|
||||
a garbage collection.
|
||||
Variables bound to values in the Scheme 48 heap need to be registered with
|
||||
the garbage collector so that the value will be retained and so that the
|
||||
variables will be updated if the garbage collector moves the object.
|
||||
The garbage collector has no facility for updating pointers to the interiors
|
||||
of objects, so such pointers, for example the ones returned by
|
||||
<CODE>EXTRACT_STRING</CODE>, will likely become invalid when a garbage collection
|
||||
occurs.
|
||||
<H2><A NAME="18">Registering Objects with the GC</A></H2>
|
||||
|
||||
<P>A set of macros are used to manage the registration of local variables with the
|
||||
garbage collector.
|
||||
<UL><LI><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||||
<LI><CODE>void S48_GC_PROTECT_<I>n</I>(s48_value<I><sub>1</sub></I>, <I>...</I>, s48_value<I><sub>n</sub></I>)</CODE>
|
||||
<LI><CODE>void S48_GC_UNPROTECT()</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>, where <I>1 <= n <= 9</I>, allocates
|
||||
storage for registering <I>n</I> variables.
|
||||
At most one use of <CODE>S48_DECLARE_GC_PROTECT</CODE> may occur in a block.
|
||||
<CODE>S48_GC_PROTECT_<I>n</I>(<I>v<sub>1</sub></I>, <I>...</I>, <I>v<sub>n</sub></I>)</CODE> registers the
|
||||
<I>n</I> variables (l-values) with the garbage collector.
|
||||
It must be within scope of a <CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||||
and be before any code which can cause a GC.
|
||||
<CODE>S48_GC_UNPROTECT</CODE> removes the block's protected variables from
|
||||
the garbage collectors list.
|
||||
It must be called at the end of the block after
|
||||
any code which may cause a garbage collection.
|
||||
Omitting any of the three may cause serious and
|
||||
hard-to-debug problems.
|
||||
Notably, the garbage collector may relocate an object and
|
||||
invalidate <CODE>s48_value</CODE> variables which are not protected.
|
||||
<P>A <CODE>gc-protection-mismatch</CODE> exception is raised if, when a C
|
||||
procedure returns to Scheme, the calls
|
||||
to <CODE>S48_GC_PROTECT()</CODE> have not been matched by an equal number of
|
||||
calls to <CODE>S48_GC_UNPROTECT()</CODE>.
|
||||
<P>Global variables may also be registered with the garbage collector.
|
||||
<UL><LI><CODE>void S48_GC_PROTECT_GLOBAL(<CODE><I>value</I></CODE>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_GC_PROTECT_GLOBAL</CODE> permanently registers the
|
||||
variable <CODE><I>value</I></CODE> (an l-value) with the garbage collector.
|
||||
There is no way to unregister the variable.
|
||||
<H2><A NAME="19">Keeping C data structures in the Scheme heap</A></H2>
|
||||
|
||||
<P>C data structures can be kept in the Scheme heap by embedding them
|
||||
inside byte vectors.
|
||||
The following macros can be used to create and access embedded C objects.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value S48_MAKE_VALUE(type)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>type S48_EXTRACT_VALUE(s48_value, type)</CODE>
|
||||
<LI><CODE>type * S48_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||||
<LI><CODE>void S48_SET_VALUE(s48_value, type, value)</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_MAKE_VALUE</CODE> makes a byte vector large enough to hold an object
|
||||
whose type is <CODE><I>type</I></CODE>.
|
||||
<CODE>S48_EXTRACT_VALUE</CODE> returns the contents of a byte vector cast to
|
||||
<CODE><I>type</I></CODE>, and <CODE>S48_EXTRACT_VALUE_POINTER</CODE> returns a pointer
|
||||
to the contents of the byte vector.
|
||||
The value returned by <CODE>S48_EXTRACT_VALUE_POINTER</CODE> is valid only until
|
||||
the next <A HREF="#gc">garbage collection</A>.
|
||||
<P><CODE>S48_SET_VALUE</CODE> stores <CODE>value</CODE> into the byte vector.
|
||||
<H2><A NAME="20">C code and heap images</A></H2>
|
||||
|
||||
<P>Scheme 48 uses dumped heap images to restore a previous system state.
|
||||
The Scheme 48 heap is written into a file in a machine-independent and
|
||||
operating-system-independent format.
|
||||
The procedures described above may be used to create objects in the
|
||||
Scheme heap that contain information specific to the current
|
||||
machine, operating system, or process.
|
||||
A heap image containing such objects may not work correctly on
|
||||
when resumed.
|
||||
<P>To address this problem, a record type may be given a `resumer'
|
||||
procedure.
|
||||
On startup, the resumer procedure for a type is applied to each record of
|
||||
that type in the image being restarted.
|
||||
This procedure can update the record in a manner appropriate to
|
||||
the machine, operating system, or process used to resume the
|
||||
image.
|
||||
<UL><LI><CODE>(define-record-resumer<I> record-type procedure</I>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Define-record-resumer</CODE> defines <CODE><I>procedure</I></CODE>,
|
||||
which should accept one argument, to be the resumer for
|
||||
<I>record-type</I>.
|
||||
The order in which resumer procedures are called is not specified.
|
||||
<P>The <CODE><I>procedure</I></CODE> argument to <CODE>define-record-resumer</CODE> may
|
||||
be <CODE>#f</CODE>, in which case records of the given type are
|
||||
not written out in heap images.
|
||||
When writing a heap image any reference to such a record is replaced by
|
||||
the value of the record's first field, and an exception is raised
|
||||
after the image is written.
|
||||
<H1><A NAME="21">Using Scheme records in C code</A></H1>
|
||||
<P>External modules can create records and access their slots
|
||||
positionally.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value S48_MAKE_RECORD(s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>int S48_RECORD_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_RECORD_TYPE(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_RECORD_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
The argument to <CODE>S48_MAKE_RECORD</CODE> should be a shared binding
|
||||
whose value is a record type.
|
||||
In C the fields of Scheme records are only accessible via offsets,
|
||||
with the first field having offset zero, the second offset one, and
|
||||
so forth.
|
||||
If the order of the fields is changed in the Scheme definition of the
|
||||
record type the C code must be updated as well.
|
||||
<P>For example, given the following record-type definition
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type thing :thing
|
||||
(make-thing a b)
|
||||
thing?
|
||||
(a thing-a)
|
||||
(b thing-b))
|
||||
</PRE></BLOCKQUOTE>
|
||||
the identifier <CODE>:thing</CODE> is bound to the record type and can
|
||||
be exported to C:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-exported-binding "thing-record-type" :thing)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<CODE>Thing</CODE> records can then be made in C:
|
||||
<BLOCKQUOTE><PRE>
|
||||
static scheme_value thing_record_type_binding = SCHFALSE;
|
||||
|
||||
void initialize_things(void)
|
||||
{
|
||||
S48_GC_PROTECT_GLOBAL(thing_record_type_binding);
|
||||
thing_record_type_binding =
|
||||
s48_get_imported_binding("thing-record-type");
|
||||
}
|
||||
|
||||
scheme_value make_thing(scheme_value a, scheme_value b)
|
||||
{
|
||||
s48_value thing;
|
||||
s48_DECLARE_GC_PROTECT(2);
|
||||
|
||||
S48_GC_PROTECT_2(a, b);
|
||||
|
||||
thing = s48_make_record(thing_record_type_binding);
|
||||
S48_RECORD_SET(thing, 0, a);
|
||||
S48_RECORD_SET(thing, 1, b);
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
|
||||
return thing;
|
||||
}
|
||||
</PRE></BLOCKQUOTE>
|
||||
Note that the variables <CODE>a</CODE> and <CODE>b</CODE> must be protected
|
||||
against the possibility of a garbage collection occuring during
|
||||
the call to <CODE>s48_make_record()</CODE>.
|
||||
<H1><A NAME="22">Raising exceptions from external code</A></H1>
|
||||
|
||||
<P>The following macros explicitly raise certain errors, immediately
|
||||
returning to Scheme 48.
|
||||
Raising an exception performs all
|
||||
necessary clean-up actions to properly return to Scheme 48, including
|
||||
adjusting the stack of protected variables.
|
||||
<UL><LI><CODE>s48_raise_scheme_exception(int type, int nargs, ...)</CODE>
|
||||
</UL>
|
||||
<P><CODE>s48_raise_scheme_exception</CODE> is the base procedure for
|
||||
raising exceptions.
|
||||
<CODE>type</CODE> is the type of exception, and should be one of the
|
||||
<CODE>S48_EXCEPTION_</CODE>...constants defined in <CODE>scheme48arch.h</CODE>.
|
||||
<CODE>nargs</CODE> is the number of additional values to be included in the
|
||||
exception; these follow the <CODE>nargs</CODE> argument and should all have
|
||||
type <CODE>s48_value</CODE>.
|
||||
<CODE>s48_raise_scheme_exception</CODE> never returns.
|
||||
<P>The following procedures are available for raising particular
|
||||
types of exceptions.
|
||||
Like <CODE>s48_raise_scheme_exception</CODE> these never return.
|
||||
<UL><LI><CODE>s48_raise_argument_type_error(scheme_value)</CODE>
|
||||
<LI><CODE>s48_raise_argument_number_error(int nargs, int min, int max)</CODE>
|
||||
<LI><CODE>s48_raise_index_range_error(long value, long min, long max)</CODE>
|
||||
<LI><CODE>s48_raise_closed_channel_error()</CODE>
|
||||
<LI><CODE>s48_raise_os_error(int errno)</CODE>
|
||||
<LI><CODE>s48_raise_out_of_memory_error()</CODE>
|
||||
</UL>
|
||||
<P>An argument type error indicates that the given value is of the wrong
|
||||
type.
|
||||
An argument number error is raised when the number of arguments, <CODE>nargs</CODE>,
|
||||
should be, but isn't, between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||||
Similarly, and index range error is raised when <CODE>value</CODE> is not between
|
||||
between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||||
<P>The following macros raise argument type errors if their argument does not
|
||||
have the required type.
|
||||
<UL><LI><CODE>void S48_CHECK_SYMBOL(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_PAIR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_STRING(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_INTEGER(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_CHANNEL(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_BYTE_VECTOR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_RECORD(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_SHARED_BINDING(s48_value)</CODE>
|
||||
</UL>
|
||||
<H1><A NAME="23">Unsafe functions and macros</A></H1>
|
||||
<P>All of the C procedures and macros described above check that their
|
||||
arguments have the appropriate types and that indexes are in range.
|
||||
The following procedures and macros are identical to those described
|
||||
above, except that they do not perform type and range checks.
|
||||
They are provided for the purpose of writing more efficient code;
|
||||
their general use is not recommended.
|
||||
<UL><LI><CODE>char S48_UNSAFE_EXTRACT_CHAR(s48_value)</CODE>
|
||||
<LI><CODE>char * S48_UNSAFE_EXTRACT_STRING(s48_value)</CODE>
|
||||
<LI><CODE>long S48_UNSAFE_EXTRACT_INTEGER(s48_value)</CODE>
|
||||
<LI><CODE>long S48_UNSAFE_EXTRACT_DOUBLE(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_EXTRACT_FIXNUM(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_ENTER_FIXNUM(long)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_CAR(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_CDR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_CAR(s48_value, s48_value)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_CDR(s48_value, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_STRING_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_UNSAFE_STRING_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_STRING_SET(s48_value, long, char)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_SYMBOL_TO_STRING(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_UNSAFE_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_REF(s48_value s_b)</CODE>
|
||||
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_P(x)</CODE>
|
||||
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_RECORD_TYPE(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_RECORD_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>type S48_UNSAFE_EXTRACT_VALUE(s48_value, type)</CODE>
|
||||
<LI><CODE>type * S48_UNSAFE_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_VALUE(s48_value, type, value)</CODE>
|
||||
</UL>
|
||||
<HR ><ADDRESS><a href="http://www-pu.informatik.uni-tuebingen.de/users/sperber/">Mike
|
||||
Sperber</a>, <a href="http://www.neci.nj.nec.com/homepages/kelsey/">Richard Kelsey</a></ADDRESS><BR>
|
||||
</BODY></HTML>
|
|
@ -1,315 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<!-- HTML file produced from file: utilities.tex --
|
||||
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
|
||||
-- on Emacs 19.34.1, Tue Feb 23 18:25:11 1999 -->
|
||||
<HEAD>
|
||||
<TITLE>Untitled</TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1 ALIGN=CENTER>Scheme 48 User's Guide</H1>
|
||||
<H2 ALIGN=CENTER>Richard A. Kelsey</H2>
|
||||
<H3 ALIGN=CENTER>February 23, 1999</H3>
|
||||
<H1><A NAME="1">ASCII character encoding</A></H1>
|
||||
<P>These are in the structure <CODE>ascii</CODE>.
|
||||
<UL><LI><CODE>(char->ascii<VAR> char</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(ascii->char<VAR> integer</VAR>) -> <VAR>char</VAR></CODE>
|
||||
</UL>
|
||||
These are identical to <CODE>char->integer</CODE> and <CODE>integer->char</CODE> except that
|
||||
they use the ASCII encoding.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>ascii-limit</CODE></td> <td align=right>integer</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>ascii-whitespaces</CODE></td> <td align=right>list of integers</td></tr></table>
|
||||
</UL>
|
||||
<CODE>Ascii-limit</CODE> is one more than the largest value that <CODE>char->ascii</CODE>
|
||||
may return.
|
||||
<CODE>Ascii-whitespaces</CODE> is a list of the ASCII values of whitespace characters
|
||||
(space, tab, line feed, form feed, and carriage return).
|
||||
<H1><A NAME="2">Bitwise integer operations</A></H1>
|
||||
<P>These functions use the two's-complement representation for integers.
|
||||
There is no limit to the number of bits in an integer.
|
||||
They are in the structures <CODE>bitwise</CODE> and <CODE>big-scheme</CODE>.
|
||||
<UL><LI><CODE>(bitwise-and<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-ior<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-xor<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-not<VAR> integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
These perform various logical operations on integers on a bit-by-bit
|
||||
basis. `<CODE>ior</CODE>' is inclusive OR and `<CODE>xor</CODE>' is exclusive OR.
|
||||
<UL><LI><CODE>(arithmetic-shift<VAR> integer bit-count</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
Shifts the integer by the given bit count, which must be an integer,
|
||||
shifting left for positive counts and right for negative ones.
|
||||
Shifting preserves the integer's sign.
|
||||
<H1><A NAME="3">Arrays</A></H1>
|
||||
<P>These are N-dimensional, zero-based arrays and
|
||||
are in the structure <CODE>arrays</CODE>.
|
||||
<P>The array interface is derived from one written by Alan Bawden.
|
||||
<UL><LI><CODE>(make-array<VAR> value dimension<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
<LI><CODE>(array<VAR> dimensions element<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
<LI><CODE>(copy-array<VAR> array</VAR>) -> <VAR>array</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Make-array</CODE> makes a new array with the given dimensions, each of which
|
||||
must be a non-negative integer.
|
||||
Every element is initially set to <CODE><VAR>value</VAR></CODE>.
|
||||
<CODE>Array</CODE> Returns a new array with the given dimensions and elements.
|
||||
<CODE><VAR>Dimensions</VAR></CODE> must be a list of non-negative integers,
|
||||
The number of elements should be the equal to the product of the
|
||||
dimensions.
|
||||
The elements are stored in row-major order.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(make-array 'a 2 3) <CODE>-></CODE> {Array 2 3}
|
||||
|
||||
(array '(2 3) 'a 'b 'c 'd 'e 'f)
|
||||
<CODE>-></CODE> {Array 2 3}
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P><CODE>Copy-array</CODE> returns a copy of <CODE><VAR>array</VAR></CODE>.
|
||||
The copy is identical to the <CODE><VAR>array</VAR></CODE> but does not share storage with it.
|
||||
<UL><LI><CODE>(array?<VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
</UL>
|
||||
Returns <CODE>#t</CODE> if <CODE><VAR>value</VAR></CODE> is an array.
|
||||
<UL><LI><CODE>(array-ref<VAR> array index<I><sub>0</sub></I> ...</VAR>) -> <VAR>value</VAR></CODE>
|
||||
<LI><CODE>(array-set!<VAR> array value index<I><sub>0</sub></I> ...</VAR>)</CODE>
|
||||
<LI><CODE>(array->vector<VAR> array</VAR>) -> <VAR>vector</VAR></CODE>
|
||||
<LI><CODE>(array-dimensions<VAR> array</VAR>) -> <VAR>list</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Array-ref</CODE> returns the specified array element and <CODE>array-set!</CODE>
|
||||
replaces the element with <CODE><VAR>value</VAR></CODE>.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(let ((a (array '(2 3) 'a 'b 'c 'd 'e 'f)))
|
||||
(let ((x (array-ref a 0 1)))
|
||||
(array-set! a 'g 0 1)
|
||||
(list x (array-ref a 0 1))))
|
||||
<CODE>-></CODE> '(b g)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P><CODE>Array->vector</CODE> returns a vector containing the elements of <CODE><VAR>array</VAR></CODE>
|
||||
in row-major order.
|
||||
<CODE>Array-dimensions</CODE> returns the dimensions of
|
||||
the array as a list.
|
||||
<UL><LI><CODE>(make-shared-array<VAR> array linear-map dimension<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Make-shared-array</CODE> makes a new array that shares storage with <CODE><VAR>array</VAR></CODE>
|
||||
and uses <CODE><VAR>linear-map</VAR></CODE> to map indicies to elements.
|
||||
<CODE><VAR>Linear-map</VAR></CODE> must accept as many arguments as the number of
|
||||
<CODE><VAR>dimension</VAR></CODE>s given and must return a list of non-negative integers
|
||||
that are valid indicies into <CODE><VAR>array</VAR></CODE>.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(array-ref (make-shared-array a f i0 i1 ...)
|
||||
j0 j1 ...)
|
||||
</PRE></BLOCKQUOTE>
|
||||
is equivalent to
|
||||
<BLOCKQUOTE><PRE>
|
||||
(apply array-ref a (f j0 j1 ...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>As an example, the following function makes the transpose of a two-dimensional
|
||||
array:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define (transpose array)
|
||||
(let ((dimensions (array-dimensions array)))
|
||||
(make-shared-array array
|
||||
(lambda (x y)
|
||||
(list y x))
|
||||
(cadr dimensions)
|
||||
(car dimensions))))
|
||||
|
||||
(array->vector
|
||||
(transpose
|
||||
(array '(2 3) 'a 'b 'c 'd 'e 'f)))
|
||||
<CODE>-></CODE> '(a d b e c f)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<H1><A NAME="4">Records</A></H1>
|
||||
<P>New types can be constructed using the <CODE>define-record-type</CODE> macro
|
||||
from the <CODE>define-record-types</CODE> structure
|
||||
The general syntax is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
(<CODE><VAR>constructor-name</VAR></CODE> <CODE><VAR>field-tag</VAR></CODE> ...)
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
|
||||
...)
|
||||
</PRE></BLOCKQUOTE>
|
||||
This makes the following definitions:
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE><CODE><VAR>type-name</VAR></CODE></CODE></td> <td align=right>type</td></tr></table>
|
||||
<LI><CODE>(<CODE><VAR>constructor-name</VAR></CODE><VAR> field-init ...</VAR>) -> <VAR>type-name</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>predicate-name</VAR></CODE><VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>accessor-name</VAR></CODE><VAR> type-name</VAR>) -> <VAR>value</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>modifier-name</VAR></CODE><VAR> type-name value</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE><VAR>Type-name</VAR></CODE> is the record type itself, and can be used to
|
||||
specify a print method (see below).
|
||||
<CODE><VAR>Constructor-name</VAR></CODE> is a constructor that accepts values
|
||||
for the fields whose tags are specified.
|
||||
<CODE><VAR>Predicate-name</VAR></CODE> to a predicate that can returns <CODE>#t</CODE> for
|
||||
elements of the type and <CODE>#f</CODE> for everything else.
|
||||
The <CODE><VAR>accessor-name</VAR></CODE>s retrieve the values of fields,
|
||||
and the <CODE><VAR>modifier-name</VAR></CODE>'s update them.
|
||||
The <CODE><VAR>tag</VAR></CODE> is used in printing instances of the record type and
|
||||
the field tags are used in the inspector and to match
|
||||
constructor arguments with fields.
|
||||
<UL><LI><CODE>(define-record-discloser<VAR> type discloser</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE>Define-record-discloser</CODE> determines how
|
||||
records of type <CODE><VAR>type</VAR></CODE> are printed.
|
||||
<CODE><VAR>Discloser</VAR></CODE> should be procedure which takes a single
|
||||
record of type <CODE><VAR>type</VAR></CODE> and returns a list whose car is
|
||||
a symbol.
|
||||
The record will be printed as the value returned by <CODE><VAR>discloser</VAR></CODE>
|
||||
with curly braces used instead of the usual parenthesis.
|
||||
<P>For example
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type pare :pare
|
||||
(kons x y)
|
||||
pare?
|
||||
(x kar set-kar!)
|
||||
(y kdr))
|
||||
</PRE></BLOCKQUOTE>
|
||||
defines <CODE>kons</CODE> to be a constructor, <CODE>kar</CODE> and <CODE>kdr</CODE> to be
|
||||
accessors, <CODE>set-kar!</CODE> to be a modifier, and <CODE>pare?</CODE> to be a predicate
|
||||
for a new type of object.
|
||||
The type itself is named <CODE>:pare</CODE>.
|
||||
<CODE>Pare</CODE> is a tag used in printing the new objects.
|
||||
<P>By default, the new objects print as <CODE>#Pare</CODE>.
|
||||
The print method can be modified using DEFINE-RECORD-DISCLOSER:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-discloser :pare
|
||||
(lambda (p) `(pare ,(kar p) ,(kdr p))))
|
||||
</PRE></BLOCKQUOTE>
|
||||
will cause the result of <CODE>(kons 1 2)</CODE> to print as
|
||||
<CODE>#{pare 1 2}</CODE>.
|
||||
<H1><A NAME="5">Finite record types</A></H1>
|
||||
<P>The structure <CODE>finite-types</CODE> has
|
||||
two macros for defining `finite' record types.
|
||||
These are record types for which there are a fixed number of instances,
|
||||
which are created when the record type is defined.
|
||||
The syntax for the defining a finite type is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-finite-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> ...)
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
<CODE><VAR>vector-of-elements-name</VAR></CODE>
|
||||
<CODE><VAR>name-accessor</VAR></CODE>
|
||||
<CODE><VAR>index-accessor</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
|
||||
...
|
||||
((<CODE><VAR>element-name</VAR></CODE> <CODE><VAR>field-value</VAR></CODE> ...)
|
||||
...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
This differs from <CODE>define-record-type</CODE> in the following ways:
|
||||
<UL><LI>No name is specified for the constructor, but the field arguments
|
||||
to the constructor are listed.
|
||||
<LI>The <CODE><VAR>vector-of-elements-name</VAR></CODE> is added; it will be bound
|
||||
to a vector containing all of the elements of the type.
|
||||
These are constructed by applying the (unnamed) constructor to the
|
||||
initial field values at the end of the form.
|
||||
<LI>There are names for accessors for two required fields, name
|
||||
and index.
|
||||
These fields are not settable, and are not to be included
|
||||
in the argument list for the constructor.
|
||||
<LI>The form ends with the names and the initial field values for
|
||||
the elements of the type.
|
||||
The name must be first.
|
||||
The remaining values must match the <CODE><VAR>field-tag</VAR></CODE>s in the constructor's
|
||||
argument list.
|
||||
<LI><CODE><VAR>Tag</VAR></CODE> is bound to a macro that maps <CODE><VAR>element-name</VAR></CODE>s to the
|
||||
the corresponding element of the vector.
|
||||
The name lookup is done at macro-expansion time.
|
||||
</UL>
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-finite-type color :color
|
||||
(red green blue)
|
||||
color?
|
||||
colors
|
||||
color-name
|
||||
color-index
|
||||
(red color-red)
|
||||
(green color-green)
|
||||
(blue color-blue)
|
||||
((white 255 255 255)
|
||||
(black 0 0 0)
|
||||
(yellow 255 255 0)
|
||||
(maroon 176 48 96)))
|
||||
|
||||
(color-name (vector-ref colors 0)) <CODE>-></CODE> white
|
||||
(color-name (color black)) <CODE>-></CODE> black
|
||||
(color-index (color yellow)) <CODE>-></CODE> 2
|
||||
(color-red (color maroon)) <CODE>-></CODE> 176
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>Enumerated types are finite types whose only fields are the name
|
||||
and the index.
|
||||
The syntax for defining an enumerated type is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-enumerated-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
<CODE><VAR>vector-of-elements-name</VAR></CODE>
|
||||
<CODE><VAR>name-accessor</VAR></CODE>
|
||||
<CODE><VAR>index-accessor</VAR></CODE>
|
||||
(<CODE><VAR>element-name</VAR></CODE> ...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
In the absence of any additional fields, both the constructor argument
|
||||
list and the initial field values are not required.
|
||||
<P>The above example of a finite type can be pared down to the following
|
||||
enumerated type:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-enumerated-type color :color
|
||||
color?
|
||||
colors
|
||||
color-name
|
||||
color-index
|
||||
(white black yellow maroon))
|
||||
|
||||
(color-name (vector-ref colors 0)) <CODE>-></CODE> white
|
||||
(color-name (color black)) <CODE>-></CODE> black
|
||||
(color-index (color yellow)) <CODE>-></CODE> 2
|
||||
</PRE></BLOCKQUOTE>
|
||||
<H1><A NAME="6">Hash tables</A></H1>
|
||||
<P>These are generic hash tables, and are in the structure <CODE>tables</CODE>.
|
||||
Strictly speaking they are more maps than tables, as every table has a
|
||||
value for every possible key (for that type of table).
|
||||
All but a finite number of those values are <CODE>#f</CODE>.
|
||||
<UL><LI><CODE>(make-table<VAR></VAR>) -> <VAR>table</VAR></CODE>
|
||||
<LI><CODE>(make-symbol-table<VAR></VAR>) -> <VAR>symbol-table</VAR></CODE>
|
||||
<LI><CODE>(make-string-table<VAR></VAR>) -> <VAR>string-table</VAR></CODE>
|
||||
<LI><CODE>(make-integer-table<VAR></VAR>) -> <VAR>integer-table</VAR></CODE>
|
||||
<LI><CODE>(make-table-maker<VAR> compare-proc hash-proc</VAR>) -> <VAR>procedure</VAR></CODE>
|
||||
<LI><CODE>(make-table-immutable!<VAR> table</VAR>)</CODE>
|
||||
</UL>
|
||||
The first four functions listed make various kinds of tables.
|
||||
<CODE>Make-table</CODE> returns a table whose keys may be symbols, integer,
|
||||
characters, booleans, or the empty list (these are also the values
|
||||
that may be used in <CODE>case</CODE> expressions).
|
||||
As with <CODE>case</CODE>, comparison is done using <CODE>eqv?</CODE>.
|
||||
The comparison procedures used in symbol, string, and integer tables are
|
||||
<CODE>eq?</CODE>, <CODE>string=?</CODE>, and <CODE>=</CODE>.
|
||||
<P><CODE>Make-table-maker</CODE> takes two procedures as arguments and returns
|
||||
a nullary table-making procedure.
|
||||
<CODE><VAR>Compare-proc</VAR></CODE> should be a two-argument equality predicate.
|
||||
<CODE><VAR>Hash-proc</VAR></CODE> should be a one argument procedure that takes a key
|
||||
and returns a non-negative integer hash value.
|
||||
If <CODE>(<CODE><VAR>compare-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE> <CODE><VAR>y</VAR></CODE>)</CODE> returns true,
|
||||
then <CODE>(= (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE>) (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>y</VAR></CODE>))</CODE>
|
||||
must also return true.
|
||||
For example, <CODE>make-integer-table</CODE> could be defined
|
||||
as <CODE>(make-table-maker = abs)</CODE>.
|
||||
<P><CODE>Make-table-immutable!</CODE> prohibits future modification to its argument.
|
||||
<UL><LI><CODE>(table?<VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
<LI><CODE>(table-ref<VAR> table key</VAR>) -> <VAR>value or <CODE>#f</CODE></VAR></CODE>
|
||||
<LI><CODE>(table-set!<VAR> table key value</VAR>)</CODE>
|
||||
<LI><CODE>(table-walk<VAR> procedure table</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE>Table?</CODE> is the predicate for tables.
|
||||
<CODE>Table-ref</CODE> and <CODE>table-set!</CODE> access and modify the value of <CODE><VAR>key</VAR></CODE>
|
||||
in <CODE><VAR>table</VAR></CODE>.
|
||||
<CODE>Table-walk</CODE> applies <CODE><VAR>procedure</VAR></CODE>, which must accept two arguments,
|
||||
to every associated key and non-<CODE>#f</CODE> value in <CODE>table</CODE>.
|
||||
<UL><LI><CODE>(default-hash-function<VAR> value</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(string-hash<VAR> string</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>default-hash-function</CODE> is the hash function used in the tables
|
||||
returned by <CODE>make-table</CODE>, and <CODE>string-hash</CODE> it the one used
|
||||
by <CODE>make-string-table</CODE>.
|
||||
<HR >
|
||||
</BODY></HTML>
|
Loading…
Reference in New Issue