XLISP on a VAX

XLISP on a VAX

XLISP-PLUS 3.05, Tom Almy’s Common-Lisp-flavoured descendant of David Betz’s small Lisp, is now running on my VAXstations under OpenVMS VAX 7.3: bignums, ratios, complex numbers, FORMAT, structures, and XLISP’s own object system, all from a 590-block image. It is built with DEC C, installed for every user with an installer and an uninstaller, and runs as an ordinary unprivileged user. Alongside it is XLISP 1.4 from 1985, the original VAX/VMS port, rebuilt with DEC C from the unchanged sources.

Claude Code did most of the hard work.

This one needed a source change, so the download folder has the whole story: the upstream archives with their hashes, my patches kept apart from the upstream files, and a recipe to recreate the kit from nothing. The change is one new file, the “system module” that every XLISP port has to supply (vmsstuff.c, 363 lines), plus 38 lines of configuration in the header files. No XLISP language source was touched.

Downloads, with SHA-256 sums in SHA256SUMS.TXT:

What it is

XLISP is David Betz’s tiny Lisp for microcomputers; version 1.4 (January 1985) is the one that was ported to the VAX. Version 2 added the Common-Lisp-like parts. XLISP-PLUS, Tom Almy’s version, is the most capable one that exists in source: arbitrary-precision integers, exact ratios, complex numbers, &key arguments, FORMAT, DEFSTRUCT, sequence functions, and the original class-and-message object system, in an interpreter whose VAX image is 295 kilobytes. Version 3.05 is the 2015 release.

I weighed these, all checked 14-OCT-2026:

VersionWhereWhat I did
XLISP-PLUS 3.05almy.us/xlisp.htmlbuilt: needs a VMS system module (Unix, DOS, Windows, Amiga, OS X modules exist)
XLISP 1.4 (1985, VAX/VMS port)DECUS VAX85A on my CD-ROM setbuilt unchanged; installed as XLISP14
XLISP 2.0 / 2.1 (Betz)my DECUS CDs, CMU AI repositorynot built: a subset of PLUS, PC-only system code
“XLISP 3.0”no source foundXLISP-PLUS’s 3.x is Almy’s numbering

What was built

  • Source: xl305src.zip, 390,123 bytes, SHA-256 f0eeb81447eff358a95b5702aaa224206cdfec64f2af8eae40ea121a0908da14, and the Lisp library xl305req.zip (ddee2919...), both from almy.us/files/.
  • Compiler: DEC C V6.4, CC/NAMES=AS_IS/FLOAT=G_FLOAT/OPTIMIZE, a short DCL procedure instead of the Unix makefile; no MMS.
  • Measured on the VAXstation 4000/90 (71 MHz KA49): 29 modules, 0 compile failures, 3 minutes 35 seconds in a batch job, a 590-block XLISP.EXE. XLISP 1.4: 23 modules, 1 minute 4 seconds, a 114-block image. The kit with BACKUP: 10 seconds.
  • Findings that cost a build each (3.5 minutes; this machine is fast):
    1. the code wants ANSI defined (prototypes with char parameters clash with unprototyped declarations; the Unix branch gets away with it);
    2. the VAX default floating format, D_float, stops at 1.7E38 and the sources compare against 1e100: I compile with /FLOAT=G_FLOAT, which has the range of an IEEE double (1E308);
    3. the evaluation stack (4000 entries on Unix) overflows at a recursion depth of about 1,000, so a naive (fact 1000) died; the VMS block sets 40,000 and 60,000 and it works (1000! has 2,568 digits and prints; all five examples together run in 8 seconds).

The source change

XLISP keeps everything operating-system specific in one “stuff” file per platform: the terminal, the file names, time, SYSTEM. The author’s own note says “you’ll need to write a *STUFF.C file for your system”. The Unix one is built around a raw termio terminal and its own line editor. On a VT-style Telnet session under VMS the terminal driver already echoes and edits a line, so vmsstuff.c is the short one:

  • input is read a line at a time with fgets; Ctrl/Z is end of file;
  • Ctrl/C arrives as SIGINT (the C library turns it into one); the handler sets a flag and the evaluator’s regular oscheck() and the line reader turn it into a return to the top level. Measured: an endless (loop (setq x 1)) stops at once and the prompt comes back;
  • (system "DIRECTORY") runs a DCL command in a subprocess and returns T for an odd (success) VMS status, otherwise the number. An empty string is an error: the other ports start an interactive shell, which here would leave a subprocess behind a Telnet line;
  • file names are VMS names: SYS$SCRATCH:XLISP_DEMO.TMP, logical names, search lists ((load "hanoi") looks in XLPATH: first, then the current directory);
  • backup copies are not made: VMS file versions are the backup.

xlisp.h gets an #ifdef XLVMS block modelled on the Unix one, and the two function-table headers lose GET-KEY (it needs a raw terminal). That is all; the patches are separate files in the source kit, with a reason for each hunk.

Installing and using

You need OpenVMS VAX 7.3 and SYSTEM (or SYSPRV). About 3,700 free blocks.

  1. Put the saveset and the two .COM files in one directory on the VAX (.BCK in binary, .COM in ASCII; the installer puts back the saveset’s record attributes that a binary transfer loses).
  2. As SYSTEM: $ @XLISP_INSTALL. It restores 112 files into SYS$COMMON:[SYSLIB.XLISP], writes a manifest (name, size and revision date of every file), and smoke-tests the result. No INSTALL, no rights identifier, no startup or login file, no account touched. Measured: the whole procedure takes 20 seconds on the 4000/90 and 30 on the 4000/60.
  3. Each user: $ @SYS$COMMON:[SYSLIB.XLISP]XLISP_SETUP, then $ XLISP.
$ XLISP
XLISP-PLUS version 3.05
Portions Copyright (c) 1988, by David Betz.
Modified by Thomas Almy and others.
OpenVMS VAX version
...
> (defun fact (n) (if (<= n 1) 1 (* n (fact (- n 1)))))
fact
> (fact 40)
815915283247897734345611269596115894272000000000
> (list (/ 1 3) (+ 1/3 1/6) (sqrt 2) (float (/ 355 113)))
(1/3 1/2 1.41421 3.14159)
> (system "WRITE SYS$OUTPUT F$GETSYI(\"HW_NAME\")")
VAXstation 4000-90
t
> (exit)

That is a real session as USER1 on the 4000/90. XLISP14 starts the 1985 version (integers only: 1.5 is not a number to it).

@XLISP_UNINSTALL CHECK shows what would go, @XLISP_UNINSTALL does it: only the files the manifest lists, and only if they are still as installed; a file you changed, or put in the directory, stays, and so does its directory.

Notes for VMS users

  • ERRSET only catches an error when *BREAKENABLE* is NIL. Otherwise XLISP enters its break loop (1>) first. (setq *breakenable* nil).
  • READ-LINE at end of file is an error, as in Common Lisp: (read-line stream nil nil) returns NIL instead.
  • DELETE-FILE removes the newest version only (it is the C remove). A second run of a program that creates X.TMP and fails before deleting it leaves X.TMP;1 behind, and the next OPEN of the name finds it.
  • The Telnet terminal driver breaks a line at the screen width; the same program with its output redirected to a file does not, so the expected-output files have lines of over 80 characters (100!) where a terminal shows two.
  • Switches go in quotes (XLISP "-b" FILE.LSP): DCL changes case. -b is “batch”: an uncaught error ends the program instead of entering the break loop. With SYS$INPUT redirected (DEFINE/USER SYS$INPUT NL:) the program exits at end of input, which is how the test procedures use it.
  • Ctrl/Y returns to DCL and leaves the program suspended; CONTINUE resumes it (measured once: the first line typed after CONTINUE was not seen; press Return first), anything else ends it. Measured: LOGOUT after Ctrl/Y leaves no process.
  • XLISP-PLUS’s own library prefers its package system: (load "common") first if a library file complains about provide.

Examples

Five programs in [.EXAMPLES] (and the zip): all produce the same output on both machines, and RUN_EXAMPLES.COM compares each with its .EXP file. I checked the numbers against an independent calculation (Python’s integers and fractions), not only against themselves.

  • RECURSION.LSP: factorial with bignums (30!, 100!, 1000! has 2568 digits), Fibonacci, Ackermann, Towers of Hanoi (1023 moves for 10 disks), 2^200, gcd(20!, 2^70) = 262144, 1/3 + 1/6 = 1/2, the Collatz length of 27 (111).
  • DERIV.LSP: a symbolic differentiator with simplification, then numeric evaluation of the derivatives (d/dx x^5 at 3 is 405).
  • OBJECTS.LSP: XLISP’s own class system: a shape class with a class variable, circle, rectangle and square subclasses, send-super, an account object that refuses an overdraft. With 355/113 for pi the areas are exact ratios: 35500/113 and a total area of 39681/113.
  • FILEIO.LSP: write a file by VMS name, read it back (READ-LINE, READ), count lines and words, delete it.
  • VMSDCL.LSP: (system ...) with DCL lexical functions (F$GETSYI("VERSION") prints V7.3) and the status values it returns.

Tests

All measured on the real machines, as the unprivileged USER1 over Telnet.

  • LIFECYCLE_TEST.COM: install; refused second install; uninstall CHECK; uninstall that keeps a changed file and a user’s file in a sub-directory; uninstall; second uninstall says “not installed”; reinstall; REPLACE. 21 of 21 passed, in 1 minute 58 seconds on the 4000/90 and 3 minutes 9 seconds on the 4000/60.
  • RUN_EXAMPLES: 5 of 5, 8 seconds on the 4000/90 (19 seconds on the 4000/60).
  • A REPL session: evaluate, LOAD by full VMS name and from XLPATH:, an endless loop and Ctrl/C, Ctrl/Z, (exit), Ctrl/Y and CONTINUE; SHOW USERS afterwards each time: no process left.

Not measured

  • I did not run XLISP’s own regression suite ([.LSP.VERIFY]) as a gate; it is installed.
  • Saving and restoring a workspace (SAVE, RESTORE) is compiled in but I did not test it on VMS.
  • Graphics, GET-KEY and POPEN are not available, by choice.
  • I did not try VAX C, GNU C or Alpha/Itanium; the system module should work with any DEC C but I have only run the VAX.

Licence

XLISP is not free software in the GNU sense. Every XLISP source file carries

Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use

and Tom Almy’s page says “distribution is limited to non-commercial or educational use”. The 1985 version says the same in its manual (“free of charge to non-commercial users”). So: non-commercial use only. I redistribute the kit on that basis, with the notices intact (the exact texts are in XLISP_LICENSE.TXT). Most of the contributors to XLISP-PLUS put their work in the public domain; the installer, uninstaller, setup procedure, the system module and the examples are mine, under the same terms as XLISP.