Prolog on a VAX

Prolog on a VAX

SWI-Prolog 3.2.6, Jan Wielemaker’s Prolog from the University of Amsterdam (the January 1999 tree), running on my VAXstations under OpenVMS VAX 7.3: Edinburgh syntax, the ISO-style built-ins of its day, modules, garbage collection, DCG, assert/retract, format/2 and a standard library. It is built with DEC C, installed for every user with an installer and an uninstaller, and runs as an ordinary unprivileged user.

Claude Code did most of the hard work.

This one needed source changes: the 1999 sources have no VMS code at all. Twelve small patches, about 140 changed lines, and the interesting part is what a VAX does to a Prolog system that expects a Unix and an IEEE machine: floating point overflow is a hardware fault, the C library’s getcwd answers in VMS syntax, and the compiler’s optimiser breaks the interpreter’s recovery from a stack overflow. The download folder has the upstream archive with its hash, every patch with its reason, and a recipe to recreate the kit from nothing.

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

Licence

SWI-Prolog 3.2.6 is distributed under the SWI-Prolog LICENCE of 1990, a GPL-like licence: copies must carry the licence, the complete source must accompany or be offered with any executable, and derived works go under the same terms. The full text is in LICENSE.TXT exactly as the author wrote it. The kit therefore carries the complete corresponding source (the original prolog-3_2_6.tgz, my patches and the build procedure) in [.SOURCE] and the source kit above. The installer, uninstaller, setup procedure, patches and examples are mine, under the same terms.

Which Prolog

I looked for the most capable, reasonably standard Prolog that builds on a VAX with DEC C 6.4 (no VAX C, no GCC here). Checked 14-OCT-2026:

VersionWhereWhat I did
SWI-Prolog 3.2.6 (Jan Wielemaker, 1999)DECUS VMSLT99A CDbuilt: portable C, malloc-based stacks with a stack shifter, no VMS code
C-Prolog 1.5 (Pereira, Damas and Byrd, Edinburgh, 1984)Computer History Museum copy, SHA-256 6db9e4db921ba3758b4d7c0dbd40e5d5325fcb4b07e0f97265bd065bf534fdf5built with one changed line (below); installed on my machines, not in the download
SWI-Prolog 1.8.6 (1994)DECUS LT93B CDnot built: its save/1 is GNU Emacs unexec(), which VMS has no equivalent of
GNU Prolog 1.0.0 and 1.2.8DECUS VMSLT99A, VMSLT02Acannot be built: native code for mips, alpha, sparc, ix86 and powerpc only, and GCC global registers
YAP 4.2.0DECUS VMSLT99Anot built: sbrk/mmap/GCC-isms, no VMS code, more risk than SWI for nothing it adds here
Berkeley PLM (Aquarius, 1988)DECUS LT91Anot built: its compiler is written in Quintus Prolog
SB-Prolog 2.3.2 (1988)DECUS VAX88A1not built: LZW-compressed tar tapes and a csh installer
prolog.exe (ENST Paris, 1988), a Pascal interpreter (York, 1983)DECUS VAX90B1, VAX92Bnot used: no source / far less than SWI

SWI-Prolog 3.2.6 is the most capable of the ones that can be built; later SWI needs 64-bit integers, GMP and a much newer C. There is also a Prolog on these machines already, inside Poplog (PROLOG file.pl, from the Poplog kit); I timed the two against each other below.

What was built

  • Source: prolog-3_2_6.tgz, 1,061,797 bytes, SHA-256 15f02277431a735942a128e035bd2fde8a0004d9b8c4b8dd4c5c6aa01d3c1442.
  • Compiler: DEC C V6.4, a DCL procedure (BUILD_PL.COM) instead of autoconf, a hand-written config.h; pl-wam.c is compiled /NOOPTIMIZE.
  • Measured on the VAXstation 4000/90 (71 MHz KA49), in a batch job, a clean rebuild by the recipe in RECREATE.md: unzip 24 seconds; 38 modules and 4 library modules, 0 failures, 6 minutes 23 seconds to compile, link 3 seconds, boot state (BOOT.PRC, 134 blocks) 5 seconds, library index 2 seconds; 6 minutes 33 seconds for the whole job. PL.EXE is 734 blocks.
  • The kit: 88 files, 5,101 blocks installed (the saveset is 2.9 MB). The lifecycle test (install, refuse a second install, uninstall with a changed file kept, reinstall, replace twice: 21 checks) takes 1 minute 48 seconds on the 4000/90 and each install about 15 seconds. On the VAXstation 4000/60 (about 2.3 times slower) the same lifecycle takes 2 minutes 53 seconds and the restore of the files about 28 seconds.

The source changes

SWI-Prolog’s src has code for Unix, MS-DOS, OS/2 and Windows; for VMS, only config.sub. Twelve patches, each guarded for __VMS (the Unix build is unchanged), most found by running something and looking at what came out:

  • File names. pl-os.c treats names with a device or [dir] as absolute (12), does not expand $VAR in a name (SYS$SCRATCH: would become the environment variable SYS$SYSDEVICE) (04), asks getcwd for the Unix form (06, the plain call answers SYS$DISK:[HOME.USER]), and makes temporary names, hasConsole and okToExec work (01). pl-main.c does not derive the home directory from argv[0], which on VMS is a file specification (02). access_file(F, write) for a new file in an existing directory (09), and directory listings come back lower-cased without ;version so that '*.pl' finds LISTS.PL (10).
  • shell/1. DCL says 1 for success; the Unix convention is 0 (11).
  • Floating point. The VAX has no infinity and no NaN. Overflow in + - * / is a hardware fault; the C library turns it into signal 10 and returning from the handler kills the process. pl-arith.c refuses an operation that would overflow, with evaluation_error(float_overflow), before executing it (07), and a float literal out of range is a syntax error (08).
  • Order of evaluation. Two places depended on the order in which a C compiler evaluates arguments or a PC + *PC++ + 1 (03, 05): a Unix compiler and DEC C disagree.
  • The optimiser. With the DEC C 6.4 optimiser on, pl-wam.c builds an interpreter that dies with an access violation when the local stack overflows instead of raising resource_error. Compiled /NOOPTIMIZE, the stack overflow is caught three times in a row. I did not pin down which transformation does it.

Testing

  • Examples, nine programs ([.EXAMPLES], with expected output; the VMS-specific ones read and write files by VMS names and call DCL through shell/1). As a fresh USER1 over Telnet: 9 of 9 PASS in 54 seconds. LISTS, DCG, DERIV and EXPERT print byte for byte what the same sources print on Linux.
  • Robustness, in batch jobs with a /CPUTIME guard: a float overflow, 1/0, an undefined procedure, an existence error on a file with a device that does not exist, and runaway recursion (resource_error(stack)) each caught, and each twice in a row, so the second occurrence is also an error and not a dead process.
  • Interactive as USER1: X is 6*7, backtracking over append/3 with ;, tell/consult/delete_file on SYS$SCRATCH: names, shell('SHOW TIME'), halt..
  • On the 4000/60, installed from the same saveset: the lifecycle 21 of 21; as a fresh USER1, the nine examples 9 of 9 PASS in 1 minute 57 seconds, and the float overflow, tell/consult/delete_file on SYS$SCRATCH: and shell checks pass.

Speed, and Poplog’s Prolog

One run of each, CPU time of a batch job on the 4000/90 (the machine had no other user). SWI-Prolog 3.2.6 against the Prolog of Poplog 15.53 (the same programs, PL file.pl against PROLOG file.pl); every program writes its result to a file so I know it did the work. Both start-up times are included.

ProgramSWI-Prolog 3.2.6Poplog Prolog
start-up only (:- halt.)0.8 s0.25 s
naive reverse of 30 elements, 100 times3.5 s0.83 s
queens 6, all solutions (findall)1.05 s0.40 s
queens 8, all solutions (92)5.0 s0.84 s
2000 x retract + assert of a counter1.7 sstopped after 2.4 s: MEMORY LIMIT (pop_prolog_lim) EXCEEDED
queens 4, 5, 6 counted with assert/retract1.1 sdid not finish in 5 minutes of CPU
queens 4..8 counted the same way, plus 100 naive reverses by recursion8.6 to 9.3 sdid not finish in 8 minutes of CPU

On plain inference Poplog’s compiled Prolog is four to seven times faster than SWI-Prolog’s interpreter (the two longer programs, with the start-up taken off), and starts three times faster. Programs that keep state in the database in a loop are another matter: Poplog’s default memory limit stops them or they run for minutes, where SWI does them in seconds. I did not tune pop_prolog_lim, so that last result is “with the defaults”, not “Poplog cannot”.

On the 4000/60 (the slower machine) the same two show the same ratio: naive reverse 7.7 s against 2.0 s, queens 8 all solutions 11.7 s against 1.9 s, start-up 1.7 s against 0.5 s.

C-Prolog 1.5, the 1984 Edinburgh original, runs the DCG, DERIV and EXPERT examples with the expected output (its top level adds a banner and a prompt); the permutation count in LISTS did not finish in three minutes of CPU, and QUEENS and ARITH do not match (** is not an operator in 1984).

What to know

  • No bignums: integers are 32 bits and an overflowing result becomes a float; floats are VAX D_floating (about 17 digits, range 1.7E38, no infinity, no NaN).
  • File names are VMS names or Unix-style names; $ is part of a name.
  • pl-wam.c is compiled with the optimiser off: with it on, Compaq C 6.4 builds an interpreter that dies with an access violation when a stack overflows instead of raising resource_error.
  • The image finds its library in SYS$COMMON:[SYSLIB.PROLOG] (compiled in); SWI_HOME_DIR (a Unix-style path) overrides it.
  • The kit is not relocatable and the source tree must be shallow: the compiler makes [.SRC.RC.CXX_REPOSITORY], and ODS-2 stops at eight directory levels (a build one level deeper failed, as %CC-E-CANTMKRPSTORY).

C-Prolog needed one line

The 1984 C-Prolog 1.5 already knew about VMS (makesys.com, #ifdef vms) and compiled and linked unchanged in under a minute. Its bootstrap, though, gave a syntax error on every clause and then looped at full speed on the end of its input: the reader parses a number with sscanf(s, "%F", &d), the DEC C run-time apparently reads %F as a single-precision float and fills only the first four bytes of the eight-byte double, so every integer came out as a float: the 76 in the clause that defines the op/3 built-in was stored as a float, op/3 was never entered, no operator was ever defined, and :- op(...) was a syntax error. %lf fixes it. (It was not the optimiser; I tried that first.) It is installed beside SWI-Prolog on my machines. Its source and binary are not in the download folder: the sources carry a copyright notice and no licence, so I link the archive instead.

Installing and using

As SYSTEM, in a directory that holds the saveset and the two procedures (no INSTALL, no startup-file edit, no privileged image, nothing outside SYS$COMMON:[SYSLIB.PROLOG]):

$ @PROLOG_INSTALL                 ! install; "@PROLOG_INSTALL "" REPLACE" replaces
$ @PROLOG_UNINSTALL CHECK         ! what would be removed
$ @PROLOG_UNINSTALL               ! removes what the manifest recorded

Then each user, once per login or from LOGIN.COM:

$ @SYS$COMMON:[SYSLIB.PROLOG]PROLOG_SETUP
$ PL                              ! interactive; end with halt. or Ctrl/Z
$ PL "-q" "-f" FILE.PL "-t" "halt"    ! run a program (quote the switches)
$ @PROLOG_EXAMPLES:RUN_EXAMPLES   ! the nine examples against their expected output

An uploaded saveset arrives with the wrong record attributes; the installer sets them. The kit installs about 5,100 blocks (2.6 MB).

Measured results are from 14-15 October 2026 on a VAXstation 4000/90 and a VAXstation 4000/60 under OpenVMS VAX 7.3 with DEC C 6.4; the timings come from batch jobs of one run each, with the machine otherwise idle. Sources, logs and the recipe: the download folder.