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 argument Anything else that does not work as specified in R5RS is a bug. 2. Installation Requirements: - 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 following: - 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 mode. 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 Ocs_types.thread). - Scheme has capturable, first-class continuations. Most of the evaluator is written in continuation-passing style in order to allow this. 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) However (rationalize (inexact->exact 0.3) (expt 2 -54)) ==> 3/10