Computing: DOS, OS/2 & Windows Programming

Free Lisp development environments for DOS.

"Lisp (historically LISP, an abbreviation of "list processing") is a family of programming languages with a long history and a distinctive, fully parenthesized prefix notation. Originally specified in the late 1950s, it is the second-oldest high-level programming language still in common use, after Fortran. Lisp has changed since its early days, and many dialects have existed over its history. Today, the best-known general-purpose Lisp dialects are Common Lisp, Scheme, Racket, and Clojure." [from the Lisp (programming language) article in Wikipedia].

"Common Lisp is a dialect of the Lisp programming language, published in American National Standards Institute (ANSI) standard document ANSI INCITS 226-1994 (S2018), formerly X3.226-1994 (R1999). It is a general-purpose, multi-paradigm programming language that supports a combination of procedural, functional, and object-oriented programming paradigms. As a dynamic programming language, it facilitates evolutionary and incremental software development, with iterative compilation into efficient run-time programs. This incremental development is often done interactively without interrupting the running application." [from the Common Lisp article in Wikipedia].

Concerning Lisp in modern times, Wikipedia writes: "After having declined somewhat in the 1990s, Lisp has experienced a resurgence of interest after 2000. Most new activity has been focused around implementations of Common Lisp, Scheme, Emacs Lisp, Clojure, and Racket, and includes development of new portable libraries and applications. As of 2010, there were eleven actively maintained Common Lisp implementations."

Thus, Lisp already existed in the times of DOS, and there were, of course, Lisp environments available for the first PCs (ex: Microsoft LISP). Other Lisp distributions were/are continued during this century, and include/included a version for DOS (ex: XLISP-PLUS). This text is a review of my experiences when installing some Lisp distributions on FreeDOS resp. MS-DOS 6.22.

Installing XLISP-PLUS on FreeDOS.

"XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers. Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users. Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects object and class as primitives." [from the XLISP article on audacity-forum.de]. "XLISP_PLUS is an evolutionary improvement over David Betz's Xlisp 2.1. It contains many enhancements and bug fixes. XLISP-PLUS contains the work of many individuals. While most have contributed their efforts to the public domain, a few reserve their copyrights when Xlisp is used commercially. For that reason, XLISP-PLUS is only distributed for non-commercial (or educational) use. XLISP-PLUS was designed to run under multiple platforms. Executable files are available for several 80x86 based operating systems." That's how the programming environment is described on the XLISP-PLUS Homepage. It's from there, that you can download the installation files for DOS, referenced in this article.

There are two implementations of the XLISP-PLUS interpreter version 3.04 available for DOS: A 16-bit real mode version (file xl304exe.zip), and a 32-bit protected mode version (file xl304386.zip), that uses DJ Delorie's GO32 extender and is compatible with DPMI, VCPI, and XMS. There is no real sense to install the 16-bit version (especially on FreeDOS, that has 32-bit support): With the memory limitations of real mode programs, and the interpreter staying in memory, there will not be lots of place left for the source code, and thus you can only write small programs; also, this interpreter is slower than the 32-bit one. On the other hand, you don't hurt anyone if you install both interpreters. They don't require lots of space, have different file names and don't interfere with one another in any way.

Beside the interpreter binary (binaries), you'll need the XLISP files required for operation (file xl305req.zip). Not mandatory, but highly recommendable, to download the documentation (xl305doc.zip). If you want so, you can also download the XLISP-PLUS sources (file xl305src.zip) and the solutions to Project Euler problems done in XLISP to help verify operation (file xlisp_euler.zip).

I unzipped the download archives on my Windows 10 into a temporary directory, then burned the relevant files (no need to copy the __MACOSX files to your DOS machine) onto a CDROM (aka I created an ISO with the files). Be sure that the directory structure is conserved when unpacking the archives.

On my FreeDOS machine, I created a new directory (c:\xlisp), and copied the extracted files and folders to there using the xcopy command. Supposing the the actual directors is C:\ and F: being the drive letter of my CD-drive, here are the commands to be run:
    mkdir xlisp
    f:
    xcopy *.* c:\xlisp /E /I /H /Q

The screenshot shows how I copied the files from the CDROM to the harddisk. The directory structure in c:\xlisp will be exactly the same as the one shown for drive F: on the screenshot. Note, that the only required directories are "bin" (containing the executables of the two interpreters) and "lsp" (containing the required XLISP files).

XLISP-PLUS on FreeDOS: Copying the directory structure to the harddisk

To use XLISP-PLUS, the following environment variables have to be set:

Creating a custom batch file.

I created a batch file called lisp.bat, that I placed in my custom directory c:\freedos\batch (you can use any directory, that is in the executables' path; e.g. c:\freedos). It may be used to run either the 16-bit, or the 32-bit interpreter, just starting the interpreter, or also loading a Lisp source file. The script may be called without, with one, or with 2 arguments:

The script also sets the PATH and XLPATH as required (note that %path0% is a custom environment variable on my system, set to %path% in fdauto,bat and that the environment variable "devel" is specific to my system; you can just comment it out or delete the corresponding line in the file). Before starting the interpreter, the script sets the actual directory to my XLISP-PLUS development directory (directory with my XLisp source files), that actually is d:\devel\xlisp.

Here are the commands:
    @echo off
    if "%1"=="-r" set _MODE=real
    if "%1"=="-p" set _MODE=protected
    if "%1"=="-16" set _MODE=real
    if "%1"=="-32" set _MODE=protected
    if not "%2"=="" goto TwoParams
    if not "%1"=="" goto OneParam
    :NoParam
    set _MODE=protected
    goto RunXLisp
    :OneParam
    if not "%_MODE%"=="" goto RunXLisp
    set _SOURCE=%1
    goto RunXLisp
    :TwoParams
    if "%_MODE%"=="" goto InvalidMode
    set _SOURCE=%2
    :RunXLisp
    set path=%path0%;c:\xlisp
    set xlpath=.;c:\xlisp;
    set devel=xlisp
    d:
    cd \devel\xlisp
    if "%_MODE%"=="real" goto Real
    :Prot
    c:\xlisp\bin\xlisp.exe %_SOURCE%
    goto End
    :Real
    c:\xlisp\bin\xlispsml.exe %_SOURCE%
    goto End
    :InvalidMode
    echo Invalid mode
    echo Usage: lisp -r/-16 or xlisp -p/-32
    :End
    set _MODE=
    set _SOURCE=

Some examples of Lisp expressions.

Lisp uses S-expressions to denote both code and data structure. Function calls, macro forms and special forms are written as lists, with the name of the operator first. Some examples:
    - Adding the integers from 1 to 4:
        (+ 1 2 3 4)
    - Adding the fractions from 1/2, 1/4 and 1/8:
        (+ 1/2 1/4 1/8)
    - Setting the variable x to 5:
        (setq x 5)
    - Setting the global variable *x* to 1.5:
        (setf *x* 1.5)
    - Defining a function, that calculates the square of a number and calling this function with x = 5:
        (defun square (x)
            (* x x))
        (square 5)

As further example, here is the code of the definition of the factorial function:
    (defun fact(x)
        (if (> x 0)
            (* x (fact(- x 1)))
            1
        )
    )

This code is interpreted as: If x > 0 then fact(x) = x * fact(x - 1), else fact(x) = 1.

The screenshots show the execution of the 16-bit interpreter (on the left), and the 32-bit interpreter (on the right). The only difference that you notice with these examples is that the 32-bit interpreter is slow, and the 16-bit interpreter is even slower. The real difference occurs, if you write large programs; in this case you risk to get an "out o memory" error when using the real mode interpreter.

XLISP-PLUS on FreeDOS: Running the 16-bit interpreter
XLISP-PLUS on FreeDOS: Running the 32-bit interpreter

As you can see on the screenshots, to quit the interpreter (and return to the DOS command line), you have to use (exit). If you want XLISP-PLUS to load a source file at startup, specify this file as command line argument (if no file extension is given, it is supposed to be .lsp). If the file is not found, the message error: can't load file is displayed. You can also load a source, if you are within the interpreter environment; to do so, use the expression (load "<filename>"). The definitions are loaded at the top level, thus all functions defined in the file source are fully available.

To terminate my description of XLISP-PLUS, here are three functions with a string argument. The first function (in file hello1.lsp) requires a name as mandatory argument, and outputs the message "Hello <name>!". The second one (file hello2.lsp), has a second argument, that actually is a key argument. If this (optional) argument is specified and set to t (t stands for "true"), a happy smiley is displayed at the end of the message, otherwise, i.e. if no key argument is specified, or the key argument set to nil (nil stands for "false"), just the message is displayed. The third function (file happy3.lsp) uses a predicate variable to define the function behavior for the case where the key argument is set to nil: display of an unhappy smiley at the end of the message). Here is the code of the three functions:

    (defun hello1 (name)
        (format t "Hello ~a!~&" name)
    )

    (defun hello2 (name &key happy)
        format t "Hello ~a " name)
        (when happy
            (format t ":)~&")
        )
    )

    (defun hello (name &key (happy nil happy-p))
        (format t "Hello ~a " name)
        (when happy-p
            (if happy
                (format t ":)")
                (format t ":(")
            )
        )
    )

In these examples, ~a is the most used format directive to print a variable aesthetically, and ~& prints a newline. The key argument is called "happy"; you can specify it as :happy t or :happy nil in the function call. In the third function, "happy-p" is the predicate variable (the usage of the -p suffix is just a convention; you can call the variable differently if you want). To note that these three examples are from the O'Reilly book The Common Lisp Cookbook, that you can find as PDF on the Internet.

The screenshots below show how I loaded the Lisp source code from my .lsp files into the interpreter environment and called the functions with different arguments. Please, note that, as a difference with the code above, the function is called "hello" in all three files (redefining the function just replaces the old definition with the new one, just as assigning a new value to a variable replaces the old value by the new one).

XLISP-PLUS on FreeDOS: Execution of some string function calls [1]
XLISP-PLUS on FreeDOS: Execution of some string function calls [2]

Installing XLISP on MS-DOS 6.22.

.....

Installing Microsoft LISP on FreeDOS.

.....

Installing CLISP on MS-DOS 6.22.

.....

Installing FLISP on MS-DOS 6.22.

.....


If you find this text helpful, please, support me and this website by signing my guestbook.