Get the latest source code via SVN from the Google Code CPSCM project page (which is also where you can report bugs):
svn checkout http://cpscm.googlecode.com/svn/trunk/ cpscm
Older releases are in http://cpscm.googlecode.com/svn/tags/.
CPSCM runs under SISC and Chicken. To run:
cd cpscm/scm; ./setup.sh
Follow the instructions printed on the screen. At the Scheme prompt, use
(import <backend>) (<backend>:compile src dst-file) where <backend> is one of scm2js or scm2lisp and src is either a list of s-expressions, or a Scheme source file. The import statement is only required once per session. For example:
(import scm2js) (scm2js:compile "../static/scheme-examples/fact.txt" "prog.js")
All R5RS standard macros are supported, along with user-defined
syntax-rules macros. I'm planning to add
define-macro support, since certain things are not expressible (easily) with hygienic macros.
cond-expand) is built-in; feature cpscm allows you to include custom code that will be seen only by CPSCM.
call/cc are fully supported and interact correctly with
error. CPSCM borrows from SISC the concept of failure continuations, accessible via
Eval and the related environment functions are not supported yet. Once R5RS support is complete,
eval will be added by "compiling the compiler" for each back-end.
The conformance page details which procedures required by the R5RS standard are not yet implemented. Some backends offer extras (such as support for various SRFIs).
Assuming you saved your compiled program in prog.js, fire up Rhino:
java -jar /path/to/rhino/js.jar
... and type:
js> load ("cpscm-drv.js"); load ("prelude.js"); load ("prog.js")
var result = cpscm__drive (cpscm__call_scm (cpscmfun (cpscm__id, arg1, arg2 /* ... */));
To run a compiled program, bring up a new shell, start Lisp and type
lisp> (mapc #'load '("cpscm-drv.lsp" "prelude.lsp" "prog.lsp"))
Common Lisp is a 2-Lisp, which means that functions exist in a namespace separate from symbols. CPSCM takes the easy way out by
setqinstead (for example,
(defparameter inc1 (lambda (x) (+ x 1)))).
CPSCM uses a modified version of the alexpander program to expand R5RS syntax-rules macros. The macroless code is converted to ANF, which in turn is CPS-transformed.
The CPS step generates a large number of redexes. Simple β and η reductions cut down on the number of closures (see simplify-sexp in scm/analysis.scm); however, the output can still be difficult to read.
The "intermediate Scheme" representation is then fed to one of the back-ends (e.g. Common Lisp). The language-specific translator renames identifiers to prevent conflicts with the host (for example,
cpscmcar in all back-ends).
The back-end translators insert trampolines at each step to avoid unbounded stack growth and implement tail-call optimization. All back-ends include a trampoline "driver" loop to run the generated code. Many of the trampoline wrappers are not necessary (and cost time and space); in future versions there will hopefully be an optimizer to deal with them.
Many R5RS procedures are expressible in terms of a core set of primitives. This eases the burden of the implementor (my own definitions are in r5rs-bootstrap.scm). Each backend includes a
(create-*-prelude) procedure to compile the non-primitive procedures to a corresponding prelude.* file.
For debugging and educational purposes, there is a "simple Scheme" back-end. The underlying Scheme need not provide continuations, multiple values or
dynamic-wind. The relevant backend is scm/scm2scm.scm, and the "driver" is in static/scheme-backend/cpscm-drv.scm (the latter embeds the "prelude" file which stands separate in the Common Lisp backend).