Version 2.0February 6, 1988
by
David Michael Betz
127 Taylor Road
Peterborough, NH 03458Copyright (c) 1988, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use
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.
If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] 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.
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.
When XLISP is running from a console, some control characters invoke operations:
When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way:
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 function
continue
, XLISP will continue from a correctable error. If
the user invokes the function 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.
If the symbol *breakenable*
is nil
, XLISP looks for a
surrounding errset function. If one is found, XLISP examines
the value of the print flag. If this flag is true, the error
message is printed. In any case, XLISP causes the errset
function call to return nil
.
If there is no surrounding errset function, XLISP prints the error message and returns to the top level.
There are several different data types available to XLISP programmers.
cons
cells, where a cons
cell is
a pair of references called the car
or head
and cdr
or
tail
.
The empty list is the null reference denoted by nil
.
(There is no
cons
cell.) A list of 1 element is a cons
cell
whose car
is the element and whose cdr
is a list of no elements,
i.e. nil
. A list of 2 elements is a cons
cell whose car
is the first element and whose cdr
is a list containing the second
element, and so on.The process of evaluation in XLISP:
The following conventions must be followed when entering XLISP programs:
Comments in XLISP code begin with a semi-colon 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:
( ) ' ` , " ;
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 +
or -
. The range of values an integer can
represent is limited by the size of a C long
on the machine on
which XLISP is running.
Floating point literals consist of a sequence of digits
optionally beginning with a +
or -
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
(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 “\
” character is used to
allow non-printable characters to be included. The codes
recognized are:
\\
means the character “\
”\n
means newline\t
means tab\r
means return\f
means form feed\nnn
means the character whose octal code is nnn
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:CONSTITUENT
– Indicating a symbol constituent:WHITE-SPACE
– Indicating a whitespace character(:TMACRO . fun)
– Terminating readmacro(:NMACRO . fun)
– Non-terminating readmacro:SESCAPE
– Single escape character ('\'):MESCAPE
– Multiple escape character ('|')
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:
'
<expr> == (quote
<expr>)
#'
<expr> == (function
<expr>)
#(
<expr>...)
== an array of the specified expressions#x
<hdigits> == a hexadecimal number (0-9,A-F)#o
<odigits> == an octal number (0-7)#b
<bdigits> == a binary number (0-1)#\
<char> == literal of type character#\Newline
== newline character#\Space
== space character#\Tab
== tab character#|
... |#
== a comment#:
<symbol> == an uninterned symbol`
<expr> == (backquote
<expr>)
,
<expr> == (comma
<expr>)
,@
<expr> == (comma-at
<expr>)
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. There are four different types of arguments.
The lambda list starts with required arguments. Required arguments must be specified in every call to the function.
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.
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.
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
“:
”). 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 “:
” 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
.
The &key
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.
Here is the complete syntax for lambda lists:
(rarg...
[&optional
[oarg | (oarg [init [svar]])]...]
[&rest
rarg]
[&key
[karg | ([karg | (key karg)] [init [svar]])]...
&allow
-other-keys]
[&aux
[aux | (aux [init])]...])where:
rarg is a required argument symbol
oarg is an&optional
argument symbol
rarg is the&rest
argument symbol
karg is a&key
argument symbol
key is a keyword symbol
aux is an auxiliary variable symbol
init is an initialization expression
svar is a supplied-p variable symbol
Definitions:
Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message.
You can send a message to an object using the send
function.
This function takes the object as its first argument, the
message selector as its second argument (which must be a symbol)
and the message arguments as its remaining arguments.
The send
function determines the class of the receiving object
and attempts to find a method corresponding to the message
selector in the set of messages defined for that class. If the
message is not found in the object's class and the class has a
super-class, the search continues by looking at the messages
defined for the super-class. This process continues from one
super-class to the next until a method for the message is found.
If no method is found, an error occurs.
When a method is found, the evaluator binds the receiving object
to the symbol self
and evaluates the method using the
remaining elements of the original list as arguments to the
method. These arguments are always evaluated prior to being
bound to their corresponding formal arguments. The result of
evaluating the method becomes the result of the expression.
Within the body of a method, a message can be sent to the current
object by calling the (send self ...)
. The method lookup
starts with the object's class regardless of the class containing
the current method.
Sometimes it is desirable to invoke a general method in a superclass
even when it is overridden by a more specific method in a subclass.
This can be accomplished by calling send-super
, which begins
the method lookup in the superclass of the class defining the current
method rather than in the class of the current object.
The send-super
function takes a selector as its first argument
(which must be a symbol) and the message arguments as its remaining
arguments. Notice that send-super
can only be sent from within
a method, and the target of the message is always the current object
(self
). (send-super ...)
is similar to
(send self ...)
except that method lookup begins in the
superclass of the class containing the current method
rather than the class of the current object.
Object
– the top of the class hierarchy.
Messages:
:class
– return the class of an object
:isa
class – test if object inherits from class
t
if object is an instance of class or a subclass of class, otherwise nil
:isnew
– the default object initialization routine
Class
– class of all object classes (including itself)
Messages:
:isnew
ivars [cvars [super]] – initialize a new class
:answer
msg fargs code – add a message to a class
When a new instance of a class is created by sending the message
:new
to an existing class, the message :isnew
followed by
whatever parameters were passed to the :new
message is sent to
the newly created object.
When a new class is created by sending the :new
message to the
object Class
, an optional parameter may be specified
indicating the superclass of the new class. If this parameter
is omitted, the new class will be a subclass of Object
. A
class inherits all instance variables, class variables, and
methods from its super-class.
The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval
is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval
in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global *profile*
variable. These functions in turn have *profile*
properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile*
list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the profile
function. Unfortunately, methods cannot be profiled with this facility.
self
- the current object (within a method context)*obarray*
- the object hash table*standard-input*
- the standard input stream*standard-output*
- the standard output stream*error-output*
- the error output stream*trace-output*
- the trace output stream*debug-io*
- the debug i/o stream*breakenable*
- flag controlling entering break loop on errors*tracelist*
- list of names of functions to trace*tracenable*
- enable trace back printout on errors*tracelimit*
- number of levels of trace back information*evalhook*
- user substitute for the evaluator function*applyhook*
- (not yet implemented)*readtable*
- the current readtable*unbound*
- indicator for unbound symbols*gc-flag*
- controls the printing of gc messages*gc-hook*
- function to call after garbage collection*integer-format*
- format for printing integers (“%d” or “%ld”)*float-format*
- format for printing floats (“%g”)*print-case*
- symbol output case (:upcase or :downcase)
There are several symbols maintained by the read/eval/print
loop. The symbols +
, ++
, and +++
are bound to the most
recent three input expressions. The symbols *
, **
and ***
are bound to the most recent three results. The symbol -
is
bound to the expression currently being evaluated. It becomes
the value of +
at the end of the evaluation.
Evaluation Functions
apply(fun, args)
[SAL](apply fun args)
[LISP] – apply a function to a list of argumentsfuncall(fun, arg...)
[SAL](funcall fun arg...)
[LISP] – call a function with argumentsquote(expr)
[SAL](quote expr)
[LISP] – return an expression unevaluated(function expr)
[LISP] – get the#function
.backquote(expr)
[SAL](backquote expr)
[LISP] – fill in a templatelambda(args, expr...)
[SAL](lambda args expr...)
[LISP] – make a function closureget-lambda-expression(closure)
[SAL](get-lambda-expression closure)
[LISP] – get the lambda expressionmacroexpand(form)
[SAL](macroexpand form)
[LISP] – recursively expand macro callsmacroexpand-1(form)
[SAL](macroexpand-1 form)
[LISP] – expand a macro call(set sym expr)
[LISP] – set the value of a symbol. Note that in SAL, the function can be accessed as #set
.setq([sym, expr]...)
[SAL](setq [sym expr]...)
[LISP] – set the value of a symbol. Note that in SAL, the set
command is normally used.psetq([sym, expr]...)
[SAL](psetq [sym expr]...)
[LISP] – parallel version of setqsetf([place, expr]...)
[SAL](setf [place expr]...)
[LISP] – set the value of a field(defun sym fargs expr...)
[LISP] – define a function(defmacro sym fargs expr...)
[LISP] – define a macrogensym([tag])
[SAL](gensym [tag])
[LISP] – generate a symbolintern(pname)
[SAL](intern pname)
[LISP] – make an interned symbolmake-symbol(pname)
[SAL](make-symbol pname)
[LISP] – make an uninterned symbolsymbol-name(sym)
[SAL](symbol-name sym)
[LISP] – get the print name of a symbolsymbol-value(sym)
[SAL](symbol-value sym)
[LISP] – get the value of a symbolsymbol-function(sym)
[SAL](symbol-function sym)
[LISP] – get the functional value of a symbolsymbol-plist(sym)
[SAL](symbol-plist sym)
[LISP] – get the property list of a symbolhash(sym, n)
[SAL](hash sym n)
[LISP] – compute the hash index for a symbolnil
putprop(sym, val, prop)
[SAL](putprop sym val prop)
[LISP] – put a property onto a property listremprop(sym, prop)
[SAL](remprop sym prop)
[LISP] – remove a propertynil
make-array(size)
[SAL](make-array size)
[LISP] – make a new arrayvector(expr...)
[SAL](vector expr...)
[LISP] – make an initialized vectorcdr(expr)
[SAL](cdr expr)
[LISP] – return the cdr of a list nodecxxr(expr)
[SAL](cxxr expr)
[LISP] – all cxxr combinationscxxxr(expr)
[SAL](cxxxr expr)
[LISP] – all cxxxr combinationscxxxxr(expr)
[SAL](cxxxxr expr)
[LISP] – all cxxxxr combinationsfirst(expr)
[SAL](first expr)
[LISP] – a synonym for carsecond(expr)
[SAL](second expr)
[LISP] – a synonym for cadrthird(expr)
[SAL](third expr)
[LISP] – a synonym for caddrfourth(expr)
[SAL](fourth expr)
[LISP] – a synonym for cadddrrest(expr)
[SAL](rest expr)
[LISP] – a synonym for cdrcons(expr1, expr2)
[SAL](cons expr1 expr2)
[LISP] – construct a new list nodelist(expr...)
[SAL](list expr...)
[LISP] – create a list of valuesappend(expr...)
[SAL](append expr...)
[LISP] – append listsreverse(expr)
[SAL](reverse expr)
[LISP] – reverse a listlast(list)
[SAL](last list)
[LISP] – return the last list node of a listmember(expr, list, test: test, test-not: test-not)
[SAL](member expr list &key :test :test-not)
[LISP] – find an expression in a listassoc(expr, alist, test: test, test-not: test-not)
[SAL](assoc expr alist &key :test :test-not)
[LISP] – find an expression in an a-listnil
remove(expr, list, test: test, test-not: test-not)
[SAL](remove expr list &key :test :test-not)
[LISP] – remove elements from a listremove-if(test, list)
[SAL](remove-if test list)
[LISP] – remove elements that pass testremove-if-not(test, list)
[SAL](remove-if-not test list)
[LISP] – remove elements that fail testlength(expr)
[SAL](length expr)
[LISP] – find the length of a list, vector or stringnth(n, list)
[SAL](nth n list)
[LISP] – return the nth element of a listnil
if the list isn't that longnthcdr(n, list)
[SAL](nthcdr n list)
[LISP] – return the nth cdr of a listnil
if the list isn't that longmapc(fcn, list1, list...)
[SAL](mapc fcn list1 list...)
[LISP] – apply function to successive carsmapcar(fcn, list1, list...)
[SAL](mapcar fcn list1 list...)
[LISP] – apply function to successive carsmapl(fcn, list1, list...)
[SAL](mapl fcn list1 list...)
[LISP] – apply function to successive cdrsmaplist(fcn, list1, list...)
[SAL](maplist fcn list1 list...)
[LISP] – apply function to successive cdrssubst(to, from, expr, test: test, test-not: test-not)
[SAL](subst to from expr &key :test :test-not)
[LISP] – substitute expressionssublis(alist, expr, test: test, test-not: test-not)
[SAL](sublis alist expr &key :test :test-not)
[LISP] – substitute with an a-listrplacd(list, expr)
[SAL](rplacd list expr)
[LISP] – replace the cdr of a list nodenconc(list...)
[SAL](nconc list...)
[LISP] – destructively concatenate listsdelete(expr, list, test: test, test-not: test-not)
[SAL](delete expr list &key :test :test-not)
[LISP] – delete elements from a listdelete-if(test, list)
[SAL](delete-if test list)
[LISP] – delete elements that pass testdelete-if-not(test, list)
[SAL](delete-if-not) test list)
[LISP] – delete elements that fail testsort(list, test)
[SAL](sort list test)
[LISP] – sort a listt
if the value is an atom, nil
otherwisesymbolp(expr)
[SAL](symbolp expr)
[LISP] – is this a symbol?t
if the expression is a symbol, nil
otherwisenumberp(expr)
[SAL](numberp expr)
[LISP] – is this a number?t
if the expression is a number, nil
otherwisenull(expr)
[SAL](null expr)
[LISP] – is this an empty list?t
if the list is empty, nil
otherwisenot(expr)
[SAL](not expr)
[LISP] – is this false?t
if the value is nil
, nil
otherwiselistp(expr)
[SAL](listp expr)
[LISP] – is this a list?t
if the value is a cons or nil
, nil
otherwiseendp(list)
[SAL](endp list)
[LISP] – is this the end of a listt
if the value is nil
, nil
otherwiseconsp(expr)
[SAL](consp expr)
[LISP] – is this a non-empty list?t
if the value is a cons, nil
otherwiseintegerp(expr)
[SAL](integerp expr)
[LISP] – is this an integer?t
if the value is an integer, nil
otherwisefloatp(expr)
[SAL](floatp expr)
[LISP] – is this a float?t
if the value is a float, nil
otherwisestringp(expr)
[SAL](stringp expr)
[LISP] – is this a string?t
if the value is a string, nil
otherwisecharacterp(expr)
[SAL](characterp expr)
[LISP] – is this a character?t
if the value is a character, nil
otherwisearrayp(expr)
[SAL](arrayp expr)
[LISP] – is this an array?t
if the value is an array, nil
otherwisestreamp(expr)
[SAL](streamp expr)
[LISP] – is this a stream?t
if the value is a stream, nil
otherwiseobjectp(expr)
[SAL](objectp expr)
[LISP] – is this an object?t
if the value is an object, nil
otherwisefilep(expr)
[SAL](filep expr)
[LISP] – is this a file? t
if the value is an object, nil
otherwiseboundp(sym)
[SAL](boundp sym)
[LISP] – is a value bound to this symbol?t
if a value is bound to the symbol, nil
otherwisefboundp(sym)
[SAL](fboundp sym)
[LISP] – is a functional value bound to this symbol?t
if a functional value is bound to the symbol,nil
otherwiseminusp(expr)
[SAL](minusp expr)
[LISP] – is this number negative?t
if the number is negative, nil
otherwisezerop(expr)
[SAL](zerop expr)
[LISP] – is this number zero?t
if the number is zero, nil
otherwiseplusp(expr)
[SAL](plusp expr)
[LISP] – is this number positive?t
if the number is positive, nil
otherwiseevenp(expr)
[SAL](evenp expr)
[LISP] – is this integer even?t
if the integer is even, nil
otherwiseoddp(expr)
[SAL](oddp expr)
[LISP] – is this integer odd?t
if the integer is odd, nil
otherwiseeq(expr1, expr2)
[SAL](eq expr1 expr2)
[LISP] – are the expressions identical (pointer equality)? Numbers and strings are generally not eq
, e.g. (eq 256 256)
, (eq 1.0 1.0)
, and (eq "a" "a")
are false.t
if they are equal, nil
otherwiseeql(expr1, expr2)
[SAL](eql expr1 expr2)
[LISP] – are the expressions of equal value? (eql
tests for identical objects (pointer equality) except for numbers. Two numbers can be eql
even if they are stored in different locations. However, a FIXNUM is never eql
to a FLONUM, i.e. (eql 1 1.0)
is false.)t
if they are equal, nil
otherwiseequal(expr1, expr2)
[SAL](equal expr1 expr2)
[LISP] – are the expressions equal? Arrays are not equal
unless they are the same array (pointer equality), but numbers and strings are compared by value, and lists are tested recursively for equal
content. A FIXNUM is never equal
to a FLONUM.t
if they are equal, nil
otherwisenil
nil
and(expr...)
[SAL](and expr...)
[LISP] – the logical and of a list of expressionsnil
if any expression evaluates to nil
,nil
)or(expr...)
[SAL](or expr...)
[LISP] – the logical or of a list of expressionsnil
if all expressions evaluate to nil
,nil
expressionnil
)(if texpr expr1 [expr2])
[LISP] – evaluate expressions conditionally. nil
nil
(default is nil
)#?(test, iftrue-expression, iffalse-expression)
, but #if
may be used instead of #?
. Either form may omit the third argument, which defaults to nil
.when(texpr, expr...)
[SAL](when texpr expr...)
[LISP] – evaluate only when a condition is truenil
nil
unless(texpr, expr...)
[SAL](unless texpr expr...)
[LISP] – evaluate only when a condition is falsenil
nil
(case expr case...)
[LISP] – select by case
(let (binding...) expr...)
[LISP] – create local bindings(let* (binding...) expr...)
[LISP] – let with sequential bindingnil
)(flet (binding...) expr...)
[LISP] – create local functions(labels (binding...) expr...)
[LISP] – flet with recursive functions(macrolet (binding...) expr...)
[LISP] – create local macroscatch(sym, expr...)
[SAL](catch sym expr...)
[LISP] – evaluate expressions and catch throwsthrow(sym [, expr])
[SAL](throw sym [expr])
[LISP] – throw to a catchnil
)unwind-protect(expr, cexpr...)
[SAL](unwind-protect expr cexpr...)
[LISP] – protect evaluation of an expression(do (binding...) (texpr rexpr...) expr...)
[LISP](do* (binding...) (texpr rexpr...) expr...)
[LISP]nil
)nil
)(dolist (sym expr [rexpr]) expr...)
[LISP] – loop through a list
nil
)(dotimes (sym expr [rexpr]) expr...)
[LISP] – loop from zero to n-1
nil
)(prog (binding...) expr...)
[LISP] – the program feature(prog* (binding...) expr...)
[LISP] – prog with sequential bindingnil
)nil
or the argument passed to the return functionblock(name, expr...)
[SAL](block name expr...)
[LISP] – named block(return [expr])
[LISP] – cause a prog construct to return a value
nil
)return-from(name [, value])
[SAL](return-from name [value])
[LISP] – return from a named blocknil
)tagbody(expr...)
[SAL](tagbody expr...)
[LISP] – block with labelsnil
go(sym)
[SAL](go sym)
[LISP] – go to a tag within a tagbody or prog(progv slist vlist expr...)
[LISP] – dynamically bind symbols
prog1(expr1, expr...)
[SAL](prog1 expr1 expr...)
[LISP] – execute expressions sequentiallyprog2(expr1, expr2, expr...)
[SAL](prog2 expr1 expr2 expr...)
[LISP] – execute expressions sequentiallyprogn(expr...)
[SAL](progn expr...)
[LISP] – execute expressions sequentiallynil
)untrace(sym)
[SAL](untrace sym)
[LISP] – remove a function from the trace listerror(emsg [, arg])
[SAL](error emsg [arg])
[LISP] – signal a non-correctable errorcerror(cmsg, emsg [, arg])
[SAL](cerror cmsg emsg [arg])
[LISP] – signal a correctable errornil
when continued from the break loopbreak([bmsg [, arg]])
[SAL](break [bmsg [arg]])
[LISP] – enter a break loop**break**
)nil
when continued from the break loop(clean-up)
[LISP] – clean-up after an error
(top-level)
[LISP] – clean-up after an error and return to the top level
(continue)
[LISP] – continue from a correctable error
(errset expr [pflag])
[LISP] – trap errors
nil
nil
on error(baktrace [n])
[LISP] – print n levels of trace back information
nil
(evalhook expr ehook ahook [env])
[LISP] – evaluate with hooks
*evalhook*
*applyhook*
nil
)profile(flag)
[SAL](profile flag)
[LISP] – turn profiling on or off.nil
turns profiling off, otherwise onfloat(expr)
[SAL](float expr)
[LISP] – converts an integer to a floating point number(+ expr...)
[LISP] – add a list of numbers
(- expr...)
[LISP] – subtract a list of numbers or negate a single number
(* expr...)
[LISP] – multiply a list of numbers
(/ expr...)
[LISP] – divide a list of numbers
(1+ expr)
[LISP] – add one to a number
(1- expr)
[LISP] – subtract one from a number
rem(expr...)
[SAL](rem expr...)
[LISP] – remainder of a list of numbersmin(expr...)
[SAL](min expr...)
[LISP] – the smallest of a list of numbersmax(expr...)
[SAL](max expr...)
[LISP] – the largest of a list of numbersabs(expr)
[SAL](abs expr)
[LISP] – the absolute value of a numbergcd(n1, n2...)
[SAL](gcd n1 n2...)
[LISP] – compute the greatest common divisorrandom(n)
[SAL](random n)
[LISP] – compute a random number between 0 and |n|-1 inclusive. If n is 0, return 0.rrandom()
[SAL](rrandom)
[LISP] – compute a random real number between 0 and 1 inclusiverandom-seed(n)
[SAL](random-seed n)
[LISP] – seed the random number generator with starting seed n. If random-seed
is not called, sranddev
or some other initialization method will be used by default.sin(expr)
[SAL](sin expr)
[LISP] – compute the sine of a numbercos(expr)
[SAL](cos expr)
[LISP] – compute the cosine of a numbertan(expr)
[SAL](tan expr)
[LISP] – compute the tangent of a numberatan(expr [, expr2])
[SAL](atan expr [expr2])
[LISP] – compute the arctangentexpt(x-expr, y-expr)
[SAL](expt x-expr y-expr)
[LISP] – compute x to the y powerexp(x-expr)
[SAL](exp x-expr)
[LISP] – compute e to the x powersqrt(expr)
[SAL](sqrt expr)
[LISP] – compute the square root of a number(< n1 n2...)
[LISP] – test for less than(<= n1 n2...)
[LISP] – test for less than or equal to(= n1 n2...)
[LISP] – test for equal to(/= n1 n2...)
[LISP] – test for not equal to(>= n1 n2...)
[LISP] – test for greater than or equal to(> n1 n2...)
[LISP] – test for greater thant
if all arguments are numbers and the results of comparing n1 with n2,logior(expr...)
[SAL](logior expr...)
[LISP] – the bitwise inclusive or of a list of numberslogxor(expr...)
[SAL](logxor expr...)
[LISP] – the bitwise exclusive or of a list of numberslognot(expr)
[SAL](lognot expr)
[LISP] – the bitwise not of a numberstring-search(pat, str, start: start, end: end)
[SAL](string-search pat str &key :start :end)
[LISP] – search for pattern in stringstring-trim(bag, str)
[SAL](string-trim bag str)
[LISP] – trim both ends of a stringstring-left-trim(bag, str)
[SAL](string-left-trim bag str)
[LISP] – trim the left end of a stringstring-right-trim(bag, str)
[SAL](string-right-trim bag str)
[LISP] – trim the right end of a stringstring-upcase(str, start: start, end: end)
[SAL](string-upcase str &key :start :end)
[LISP] – convert to uppercasestring-downcase(str, start: start, end: end)
[SAL](string-downcase str &key :start :end)
[LISP] – convert to lowercasenstring-upcase(str, start: start, end: end)
[SAL](nstring-upcase str &key :start :end)
[LISP] – convert to uppercasenstring-downcase(str, start: start, end: end)
[SAL](nstring-downcase str &key :start :end)
[LISP] – convert to lowercasestrcat(expr...)
[SAL](strcat expr...)
[LISP] – concatenate stringssubseq(string, start [, end])
[SAL](subseq string start [end])
[LISP] – extract a substringstring<(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string< str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string<=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string<= str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string= str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string/=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string/= str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string>=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string>= str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string>(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string> str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]t
if predicate is true, nil
otherwisestring-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-lessp str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string-not-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-not-greaterp str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string-equal(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-equal str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string-not-equal(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-not-equal str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string-not-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-not-lessp str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]string-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2)
[SAL](string-greaterp str1 str2 &key :start1 :end1 :start2 :end2)
[LISP]t
if predicate is true, nil
otherwiseupper-case-p(chr)
[SAL](upper-case-p chr)
[LISP] – is this an upper case character?t
if the character is upper case, nil
otherwiselower-case-p(chr)
[SAL](lower-case-p chr)
[LISP] – is this a lower case character?t
if the character is lower case, nil
otherwiseboth-case-p(chr)
[SAL](both-case-p chr)
[LISP] – is this an alphabetic (either case) character?t
if the character is alphabetic, nil
otherwisedigit-char-p(chr)
[SAL](digit-char-p chr)
[LISP] – is this a digit character?nil
otherwisechar-code(chr)
[SAL](char-code chr)
[LISP] – get the ascii code of a charactercode-char(code)
[SAL](code-char code)
[LISP] – get the character with a specified ascii codenil
char-upcase(chr)
[SAL](char-upcase chr)
[LISP] – convert a character to upper casechar-downcase(chr)
[SAL](char-downcase chr)
[LISP] – convert a character to lower casedigit-char(n)
[SAL](digit-char n)
[LISP] – convert a digit weight to a digitnil
char-int(chr)
[SAL](char-int chr)
[LISP] – convert a character to an integerint-char(int)
[SAL](int-char int)
[LISP] – convert an integer to a characterchar<(chr1, chr2...)
[SAL](char< chr1 chr2...)
[LISP]char<=(chr1, chr2...)
[SAL](char<= chr1 chr2...)
[LISP]char=(chr1, chr2...)
[SAL](char= chr1 chr2...)
[LISP]char/=(chr1, chr2...)
[SAL](char/= chr1 chr2...)
[LISP]char>=(chr1, chr2...)
[SAL](char>= chr1 chr2...)
[LISP]char>(chr1, chr2...)
[SAL](char> chr1 chr2...)
[LISP]t
if predicate is true, nil
otherwisechar-lessp(chr1, chr2...)
[SAL](char-lessp chr1 chr2...)
[LISP]char-not-greaterp(chr1, chr2...)
[SAL](char-not-greaterp chr1 chr2...)
[LISP]char-equal(chr1, chr2...)
[SAL](char-equal chr1 chr2...)
[LISP]char-not-equal(chr1, chr2...)
[SAL](char-not-equal chr1 chr2...)
[LISP]char-not-lessp(chr1, chr2...)
[SAL](char-not-lessp chr1 chr2...)
[LISP]char-greaterp(chr1, chr2...)
[SAL](char-greaterp chr1 chr2...)
[LISP]t
if predicate is true, nil
otherwisenil
)nil
)(print expr [stream])
[LISP] – print an expression on a new line
(display
label expr...)
[LISP]
– print expressions and their values
(display-on)
[LISP]
– enable display macro
(display-off)
[LISP]
– disable display macro
prin1(expr [, stream])
[SAL](prin1 expr [stream])
[LISP] – print an expressionprinc(expr [, stream])
[SAL](princ expr [stream])
[LISP] – print an expression without quotingpprint(expr [, stream])
[SAL](pprint expr [stream])
[LISP] – pretty print an expressionterpri([stream])
[SAL](terpri [stream])
[LISP] – terminate the current print linenil
flatsize(expr)
[SAL](flatsize expr)
[LISP] – length of printed representation using prin1flatc(expr)
[SAL](flatc expr)
[LISP] – length of printed representation using princnil
, nil
otherwise~A
– print next argument using princ
~S
– print next argument using prin1
~%
– start a new line
~~
– print a tilde character
~
<newline> – ignore this one newline and white space on the
next line up to the first non-white-space character or newline. This
allows strings to continue across multiple lines
Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with open-binary
on non-unix systems.
open-binary(fname, direction: direction)
[SAL](open-binary fname &key :direction)
[LISP] – open a binary file streamclose(stream)
[SAL](close stream)
[LISP] – close a file streamnil
setdir(path [, verbose])
[SAL](setdir path [verbose])
[LISP] – set current directorynil
if an error occurslistdir(path)
[SAL](listdir path)
[LISP] – get a directory listingget-temp-path()
[SAL](get-temp-path)
[LISP] – get a path where a temporary file can be created. Under Windows, this is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice c:\windows\
.get-user()
[SAL](get-user)
[LISP] – get the user ID. In Unix systems (including OS X and Linux), this is the value of the USER environment variable. In Windows, this is currently just “nyquist”, which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory.find-in-xlisp-path(filename)
[SAL](find-in-xlisp-path filename)
[LISP] – search the XLISP search path (e.g. XLISPPATH
from the environment) for filename. If filename is not found as is, and there is no file extension, append ".lsp
" to filename and search again. The current directory is not searched.read-char([stream])
[SAL](read-char [stream])
[LISP] – read a character from a streampeek-char([flag [, stream]])
[SAL](peek-char [flag [stream]])
[LISP] – peek at the next characternil
)write-char(ch [, stream])
[SAL](write-char ch [stream])
[LISP] – write a character to a streamread-int([stream [, length]])
[SAL](read-int [stream [length]])
[LISP] – read a binary integer from a streamwrite-int(ch [, stream [, length]])
[SAL](write-int ch [stream [length]])
[LISP] – write a binary integer to a streamread-float([stream [, length]])
[SAL](read-float [stream [length]])
[LISP] – read a binary floating-point number from a streamwrite-float(ch [, stream [, length]])
[SAL](write-float ch [stream [length]])
[LISP] – write a binary floating-point number to a streamread-line([stream])
[SAL](read-line [stream])
[LISP] – read a line from a streamread-byte([stream])
[SAL](read-byte [stream])
[LISP] – read a byte from a streamwrite-byte(byte [, stream])
[SAL](write-byte byte [stream])
[LISP] – write a byte to a stream These functions operate on unnamed streams. An unnamed output
stream collects characters sent to it when it is used as the
destination of any output function. The functions
get-output-stream-string
and get-output-stream-list
return a string or a list of characters.
An unnamed input stream is setup with the
make-string-input-stream
function and returns each character of the string when
it is used as the source of any input function.
make-string-input-stream(str [, start [, end]])
[SAL](make-string-input-stream str [start [end]])
[LISP]make-string-output-stream(stream)
[SAL](make-string-output-stream)
[LISP]get-output-stream-string(stream)
[SAL](get-output-stream-string stream)
[LISP]get-output-stream-list(stream)
[SAL](get-output-stream-list stream)
[LISP]Note: the load
function first tries to load a file from the current directory. A .lsp
extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.)
*float-format*
in Section Symbols.)get-run-time()
[SAL](get-run-time)
[LISP] – get the run time based on number of Lisp expression evaluations. Typically, a computer will use one unit of run time in about 10ms, but this can vary either way and depends on CPU speed.get-env(name)
[SAL](get-env name)
[LISP] – get from an environment variablenil
if variable does not exist(load fname &key :verbose :print)
[LISP] – load a source file
nil
)save(fname)
[SAL](save fname)
[LISP] – save workspace to a filet
if workspace was written, nil
otherwiserestore(fname)
[SAL](restore fname)
[LISP] – restore workspace from a filenil
on failure, otherwise never returnsdribble([fname])
[SAL](dribble [fname])
[LISP] – create a file with a transcript of a sessiont
if the transcript is opened, nil
if it is closedgc()
[SAL](gc)
[LISP] – force garbage collectionnil
expand(num)
[SAL](expand num)
[LISP] – expand memory by adding segmentsalloc(num)
[SAL](alloc num)
[LISP] – change number of nodes to allocate in each segmentinfo()
[SAL](info)
[LISP] – show information about memory usage.nil
room()
[SAL](room)
[LISP] – show memory allocation statisticsnil
type-of(expr)
[SAL](type-of expr)
[LISP] – returns the type of the expressionnil
if the value is nil
otherwise one of the symbols:peek(addrs)
[SAL](peek addrs)
[LISP] – peek at a location in memorypoke(addrs, value)
[SAL](poke addrs value)
[LISP] – poke a value into memorybigendianp()
[SAL](bigendianp)
[LISP] – is this a big-endian machine?address-of(expr)
[SAL](address-of expr)
[LISP] – get the address of an xlisp nodeexit()
[SAL](exit)
[LISP] –exit
issetup-console()
[SAL](setup-console)
[LISP] – set default console attributessetup-console
in system.lsp
. In Nyquist, you can avoid this behavior by setting *setup-console*
to NIL in your init.lsp
file. If setup-console
is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.echoenabled(flag)
[SAL](echoenabled flag)
[LISP] – turn console input echoing on or offTo open a file for input, use the open
function with the keyword
argument :direction
set to :input
. To open a file for output,
use the open
function with the keyword argument :direction
set
to :output
. The open
function takes a single required argument which
is the name of the file to be opened. This name can be in the form of a
string or a symbol. The open
function returns an object of type
FILE-STREAM
if it succeeds in opening the specified file. It returns the
value nil
if it fails. In order to manipulate the file, it is
necessary to save the value returned by the open
function. This is
usually done by assigning it to a variable with the setq
special form or by
binding it using let
or let*
. Here is an example:
(setq fp (open "init.lsp" :direction :input))
Evaluating this expression will result in the file init.lsp
being opened. The file object that will be returned by the open
function will be assigned to the variable fp
.
It is now possible to use the file for input. To read an
expression from the file, just supply the value of the fp
variable as the optional stream argument to read
.
(read fp)
Evaluating this expression will result in reading the first
expression from the file init.lsp
. The expression will be
returned as the result of the read
function. More expressions
can be read from the file using further calls to the read
function. When there are no more expressions to read, the read
function will return nil
(or whatever value was supplied as the
second argument to read
).
Once you are done reading from the file, you should close it. To close the file, use the following expression:
(close fp)
Evaluating this expression will cause the file to be closed.
Writing to a file is pretty much the same as reading from one.
You need to open the file first. This time you should use the
open
function to indicate that you will do output to the file.
For example:
(setq fp (open "test.dat" :direction :output))
Evaluating this expression will open the file test.dat
for
output. If the file already exists, its current contents will
be discarded. If it doesn't already exist, it will be created.
In any case, a FILE-STREAM
object will be returned by the OPEN
function. This file object will be assigned to the fp
variable.
It is now possible to write to this file by supplying the value
of the fp
variable as the optional stream parameter in the print
function.
(print "Hello there" fp)
Evaluating this expression will result in the string “Hello
there” being written to the file test.dat
. More data can be
written to the file using the same technique.
Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file.
(close fp)
Evaluating this expression will close the output file and make it permanent.
This example shows how to open a file, read each Lisp expression
from the file and print it. It demonstrates the use of files
and the use of the optional stream argument to the read
function.
(do* ((fp (open "test.dat" :direction :input)) (ex (read fp) (read fp))) ((null ex) nil) (print ex))