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