OCS: a mirror of the ocaml OCS scheme interpreter
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


1. General

Ocs is an implementation of Scheme, as defined by R5RS.  It is
written entirely in OCaml and can be trivially embedded in any
OCaml program.

Known deviations from R5RS:

 - transcript-on and transcript-off are currently not implemented
 - scheme-report-environment and null-environment ignore their

Anything else that does not work as specified in R5RS is a bug.

2. Installation


 - GNU make or pmake (BSD make)
 - OCaml 3.x (versions 3.06 and newer tested)

Type make or gmake in the src directory.  This should produce the

 - A bytecode library (ocs.cma)
 - A native library (ocs.cmxa, ocs.a)
 - A stand-alone, native interpreter (ocscm)

2.1 The 'ocscm' command

If invoked without arguments, the interpreter will run in interactive

If invoked with arguments, the interpreter will read and evaluate
the files listed as arguments and exit.  The evaluation results are
not printed.

3. Implementation Details

Implementing Scheme in OCaml is so straightforward that it hardly
needs any documentation.  The following mappings between languages
are done:

 - Scheme is dynamically typed.  Scheme values are represented by
the OCaml type Ocs_types.sval.

 - In Scheme, top-level bindings are global and all variables are
mutable.  Variables references are bound through environments
(Ocs_types.env) to global slots (Ocs_types.gvar) or frame indices
(the actual frames are visible at evaluation-time through

 - Scheme has capturable, first-class continuations.  Most of the
evaluator is written in continuation-passing style in order to allow

Where discussing types, the rest of this section assumes that the
types defined in the module Ocs_types are visible.

3.1 Evaluation

Scheme values (S-expressions) are of the type sval.

Before evaluation Scheme values are compiled to internal representations
of the type code.  This is done by the function

  Ocs_compile.compile : env -> sval -> code

The env type is used during compilation for variable bindings.  A
new env is created for each new scope and frame.  The base
environment with the basic language bindings can be created using

  Ocs_top.make_env : unit -> env

Evaluation is done by

  Ocs_eval.eval : thread -> (sval -> unit) -> code -> unit

where the second argument is a continuation to pass the result to.

The thread type is used during evaluation for storing the current
frame and display for local variables, the input/output ports and
the current dynamic extent.  It does not represent a thread in the
concurrent sense, but rather the evaluation state, and is copied and
changed rather than modified in place.  The initial thread to be
passed to the evaluator can be created using
Ocs_top.make_thread : unit -> thread.

3.2 Continuations and I/O

Any continuations captured are associated with the thread at the
time of capture, so if a continuation is used to escape a
with-input-from-file or with-output-to-file, the input/output port
is restored to those of the time of capture.

If a continuation is used to return to a with-input-from-file or
with-output-to-file, the port is once again set to the one
opened by the with-...-file call.  However, if the thunk has
already exited once, the port will be closed and no longer be
valid for I/O calls.

3.3 Numbers

The full R5RS numeric tower is implemented, with the following
internal representations:

Exact numbers are
  - 31- or 63-bit integers (OCaml int)
  - Big_int objects from the Num library when unboxed integers are
    too small
  - Ratio objects from the Num library for rationals

Inexact numbers are
  - 64-bit IEEE floats for reals (OCaml float)
  - Pairs of 64-bit IEEE floats for complex numbers (OCaml Complex.t)

Since inexact numbers are represented internally as binary floating
point, conversions to exact numbers are most precise for fractions of
powers of two

  (inexact->exact 2.125) ==> 17/8

compared to

  (inexact->exact 0.3) ==> 5404319552844595/18014398509481984

And in fact many rationals will not satisfy

  (= (inexact->exact (exact->inexact r)) r)


  (rationalize (inexact->exact 0.3) (expt 2 -54)) ==> 3/10