Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

XLISP 2.0


XLISP: An Object-oriented Lisp  Version 2.0, February 6, 1988, by David Michael Betz, 127 Taylor Road, Peterborough, NH 03458

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


  1. Introduction
  2. A Note From The Author
  3. Command Loop
  4. Break Loop
  5. Data Types
  6. The Evaluator
  7. Lexical Conventions
  8. The Readtable
  9. Lambda Lists

1  Introduction


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. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances [it is the only object that is an instance of itself].

This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming. I recommend the book 'Lisp' by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. You will probably also need a copy of 'Common Lisp, The Language' by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document.

A list with Lisp books and documents available for free in the internet can be found under Lisp Links.

  Back to Top


2  A Note From The Author


If you have any problems with XLISP, feel free to contact me [David Betz] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me.

If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it.

Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However,

PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!!

I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run.

The official XLISP homepage is:

  Back to top


3  Command Loop


When XLISP is started, it first tries to load the workspace 'xlisp.wks' from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols. Then XLISP attempts to load 'init.lsp' from the current directory. It then loads any files named as parameters on the command line [after appending '.lsp' to their names].

XLISP then issues the following prompt:

>

This indicates that XLISP is waiting for an expression to be typed. When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed.

Interactive Programming

There are several symbols maintained by the read-eval-print loop:

   *   -  the most recent result
   **   -  the second recent result
   ***   -  the third recent result
   +   -  the most recent input expression
   ++   -  the second recent input expression
   +++   -  the third recent input expression
     -  the expression currently being evaluated, becomes the value of + at the end of the evaluation

These symbols are for interactive programming. It is not recommended to use them in program code.

Special Characters

When XLISP is running from a console [not in the Nyquist Java IDE], some control characters invoke operations:

   Control-c   -  executes the top-level function
   Control-g   -  executes the clean-up function
   Control-p   -  executes the continue function
   Control-b   -  stops execution and enters the break command loop, execution can be continued by typing Control-p or (continue)
   Control-e   -  turns on character echoing [Linux and Mac OS X only]
   Control-f   -  turns off character echoing [Linux and Mac OS X only]
   Control-t   -  evaluates the info function
   Control-u   -  erases the entire input line

Backspace and Delete characters erase the previous character on the input line [if any].

  Back to top


4  Break Loop


When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way:

1. If the symbol *breakenable* is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed.

XLISP then enters a 'read-eval-print' loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level 'read-eval-print' loop in that if the user invokes the continue function:

1> (continue)

XLISP will continue from a correctable error. If the user invokes the clean-up function:

1> (clean-up)

XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt with a number.

2. If the symbol *breakenable* is NIL, XLISP looks for a surrounding errset function:

  Back to top


5  Data Types


There are several different data types available to XLISP programmers:

See also the type-of function.

  Back to top


6  The Evaluator


The process of evaluation in XLISP:

  Back to top


7  Lexical Conventions


The following conventions must be followed when entering XLISP programs:

  Back to top


8  The Readtable


The behavior of the reader is controlled by a data structure called a 'readtable'. The reader uses the symbol *readtable* to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things:

    NIL   -   indicating an invalid character    [see nil]
   :CONSTITUENT   -   indicating a symbol constituent    [see :constituent]
   :WHITE-SPACE   -   indicating a whitespace character    [see :white-space]
   (:TMACRO . function)   -   terminating readmacro    [see :tmacro]
   (:NMACRO . function)   -   non-terminating readmacro    [see :nmacro]
   :SESCAPE   -   single escape character '\'    [see :sescape]
   :MESCAPE   -   multiple escape character '|'    [see :mescape]

In the case of :tmacro and :nmacro, the 'fun' component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return NIL to indicate that the character should be treated as white space or a value consed with NIL to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream.

XLISP defines several useful read macros:

   'expression   =   (quote expr)
   #'expression   =   (function expr)
   #(expression...)   =   an array of the specified expressions
   #xdigits   =   a hexadecimal number [0-9,A-F]
   #odigits   =   an octal number [0-7]
   #bdigits   =   a binary number [0-1]
   #\character   =   a single character
   #| ... |#   =   a comment
   #:symbol   =   an uninterned symbol
   `expression   =   (backquote expr)
   ,expression   =   (comma expr)
   ,@expression   =   (comma-at expr)

Characters names handled by the reader:

   #\Tab   =   horiz. tab    [ASCII decimal value 9]
   #\Newline   =   newline    [ASCII decimal value 10]
   #\Space   =   space    [ASCII decimal value 32]

  Back to top


9  Lambda Lists


9.1  Arguments


There are several forms in XLISP that require that a 'lambda list' be specified. A lambda list is a definition of the arguments accepted by a function.

  Back to top


9.1.1  Required Arguments


The lambda list starts with 'required' arguments. Required arguments must be specified in every call to the function.

The function 'print-x' has exactly one required argument 'x':

(defun print-x (x)
  (print x))

(print-x 1)    => 1
(print-x)      => error: too few arguments
(print-x 1 2)  => error: too many arguments

  Back to top


9.1.2  Optional Arguments


The Required Arguments are followed by the &optional arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an &optional argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to NIL.

It is also possible to provide the name of a 'supplied-p' variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the 'supplied-p' variable will be bound to  T  if a value was specified in the call and NIL if the default value was used.

  Back to top


9.1.3  Rest Argument


The Optional Arguments are followed by the &rest argument. The &rest argument gets bound to the remainder of the argument list after the required and &optional arguments have been removed.

Known Problems with the Rest Argument

A subtle problem arises if Optional Arguments are used together with a &rest argument:

(defun test (&optional opt &rest rest)
  (format t "opt = ~a, rest = ~a~%" opt rest))

(test 1)      => opt = 1, rest = NIL
(test 1 2)    => opt = 1, rest = (2)
(test 1 2 3)  => opt = 1, rest = (2 3)

Now the &optional argument is not optional anymore, there is no way to make the first argument appear in the &rest list and not in the &optional variable. This is not a XLISP bug, this is a general Lisp phenomenon. In Lisp it's not a good idea to use Optional Arguments together with a &rest argument.

If a &rest argument is used togethter with Keyword Arguments, then the keywords and their arguments appear in the list bound to the &rest argument. This is not neccessarily a XLISP bug, this also happens with other Lisps. In Lisp it's also not a good idea to use Keyword Arguments together with a &rest argument.

XLISP Bug: If the number of elements in a &rest list is odd, then &key variables have wrong values:

(defun test (&rest rest &key (key t))
  (format t "rest = ~a, key = ~a~%" rest key))

(test 1     :key 'a)  => rest = (1 :KEY A),     key = T  ; wrong KEY value
(test 1 2   :key 'a)  => rest = (1 2 :KEY A),   key = A  ; quirk, but correct KEY value
(test 1 2 3 :key 'a)) => rest = (1 2 3 :KEY A), key = T  ; again wrong KEY value

  Back to top


9.1.4  Keyword Arguments


The Rest Argument is followed by the &key arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol [a symbol that begins with a colon ':']. The value of the second expression is the value of the keyword argument.

Like &optional arguments, &key arguments can have initialization expressions and 'supplied-p' variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a colon ':' to the beginning of the keyword argument symbol is used.

In other words, if the keyword argument symbol is:

foo

the keyword will be:

:foo

  Back to top


9.1.5  Auxiliary Variables


The Keyword Arguments are followed by the &aux variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the &aux variables.

  Back to Top


9.2  Lambda List Syntax


Here is the complete syntax for lambda lists:

   (required-arg ...
      [&optional [optional-arg | (optional-arg [init-form [supplied-var]])] ... ]
      [&rest rest-arg]
      [&key [key-arg | ([key-arg | (keyword key-arg)] [init-form [supplied-var]]) ...] &allow-other-keys]
      [&aux [aux-var | (aux-var [init-form])] ... ])

where:

   required-arg  —  is a required argument symbol
   optional-arg  —  is an &optional argument symbol
   rest-arg  —  is the &rest argument symbol
   key-arg  —  is a &key argument symbol
   keyword  —  is a keyword symbol
   aux-var  —  is an auxiliary variable symbol
   init-form  —  is an initialization expression
   supplied-var  —  is a supplied-p variable symbol

  Back to top


Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference