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

- Arguments

- Required Arguments
- Optional Arguments
- Rest Argument
- Keyword Arguments
- Auxiliary Variables

- Lambda List Syntax

## 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:

- http://www.mv.com/ipusers/xlisper/

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.

  - If the symbol *tracenable* is true, a trace back is printed. The number of entries printed depends on the value of the symbol *tracelimit*. If this symbol is set to something other than a number, the entire trace back stack 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:

- If an error happened within the scope of an errset function, XLISP examines the value of the errset print flag. If this flag is true, the error message is printed. In case of an error, the errset function always returns NIL.

- If there is no surrounding errset function, XLISP prints the error message and returns to the top level.

Back to top

## 5 Data Types

There are several different data types available to XLISP programmers:

- nil - boolean false as well as the empty list
- array - including hash-tables
- character
- number

- fixnum - integer number
- flonum - floating point number

- cons - a non-empty list, where a list is of type cons or nil
- object
- stream

- file-stream - returned by open
- unnamed-stream - returned by make-string-input-stream

- string
- symbol - including keywords
- subr - built-in function
- fsubr - special form
- closure - user defined function
- file
- sound - a Nyquist sound

See also the type-of function.

Back to top

## 6 The Evaluator

The process of evaluation in XLISP:

- The following Lisp objects evaluate to themselves:

  - string
  - fixnum
  - character
  - flonum
  - object
  - array
  - stream
  - subr - built-in function
  - fsubr - special form
  - closure - user defined function

- Symbols act as variables and are evaluated by retrieving the value associated with their current binding.

- Lists are evaluated by examining the first element of the list and then taking one of the following actions:

- If it is a symbol, the functional binding of the symbol is retrieved.

- If it is a lambda expression, a closure is constructed for the function described by the lambda expression.

- If it is a subr [built-in function], fsubr [special form] or closure [user defined function], it stands for itself.

- Any other value is an error.

Then, the value produced by the previous step is examined:

- If it is a subr [built-in function] or closure [user defined function], the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments.

- If it is an fsubr [special form], the fsubr is called using the remaining list elements as arguments [unevaluated].

- If it is a macro, the macro is expanded using the remaining list elements as arguments [unevaluated]. The macro expansion is then evaluated in place of the original macro call.

Back to top

## 7 Lexical Conventions

The following conventions must be followed when entering XLISP programs:

- Comments in XLISP code begin with a semicolon character and continue to the end of the line.

- Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following:

`` | ( | - | opening parenthesis
`` | ) | - | closing parenthesis
`` | ' | - | single-quote
`` | ` | - | backquote
`` | , | - | comma
`` | " | - | double-quote
`` | ; | - | semicolon

- Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input.

- Integer literals consist of a sequence of digits optionally beginning with a '+' [plus] or '-' [minus]. The range of values an integer can represent is limited by the size of a C 'long' value on the machine on which XLISP is running. Also be aware that Nyquist doesn't check for CPU register overflow with integer numbers, so for example if you add 1 to the biggest Nyquist integer number, the result will be a negative number.

- Floating point literals consist of a sequence of digits optionally beginning with a '+' [plus] or '-' [minus] and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C 'float' [or 'double' on machines with 32 bit addresses] on the machine on which XLISP is running.

- Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the '\' [backslash] character is used to allow non-printable characters to be included. The codes recognized are:

`` | `\\` | - | the character '\' [backslash]
`` | `\n` | - | newline
`` | `\t` | - | tab
`` | `\r` | - | return
`` | `\f` | - | form feed
`` | `\nnn` | - | the character whose octal code is 'nnn'

An ASCII table is provided with this version of the XLISP manual with all octal, decimal and hexadecimal character values.

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