This implementation is mostly compatible to the standard reference
Guy L. Steele Jr.: Common Lisp - The Language (1st ed.).
Digital Press 1984, 465 pages.
("CLtL1" for short)
and to the older parts of
Guy L. Steele Jr.: Common Lisp - The Language (2nd ed.).
Digital Press 1990, 1032 pages.
("CLtL2" for short) http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/cltl2.html
These notes document the differences of the CLISP implementation of Common Lisp to the standard CLtL1, and some implementation details. The differences between CLtL1 and CLtL2 are made up of X3J13 votes. CLISP's position with respect to these votes is listed in cltl2.txt.
sign | mantissa | exponent | comment | |
---|---|---|---|---|
short-float | 1 bit | 16+1 bits | 8 bits | |
single-float | 1 bit | 23+1 bits | 8 bits | CLISP uses IEEE format |
double-float | 1 bit | 52+1 bits | 11 bits | CLISP uses IEEE format |
long-float | 1 bit | >=64 bits | 32 bits |
The single and double float formats are those of the IEEE standard (1981), except that CLISP does not support features like +0, -0, +inf, -inf, gradual underflow, NaN, etc. (Common Lisp does not make use of these features.)
Long floats have variable mantissa length, which is a multiple of 16 (or 32,
depending on the word size of the processor). The default length used when
long floats are read is given by the place (long-float-digits)
. It can be
set by (setf (long-float-digits) nnn)
, where nnn is a positive integer.
(sqrt -9.0)
evaluates to the number #C(0 3.0)
, which has
a real part of exactly 0, not only 0.0 (which would mean "approximately 0").
The type specifier for this is (complex integer single-float)
, and
(complex type-of-real-part type-of-imaginary-part)
in general.
The type specifier (complex type)
is equivalent to (complex type type)
.
$0 | $1 | $2 | $3 | $4 | $5 | $6 | $7 | $8 | $9 | $A | $B | $C | $D | $E | $F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | ** | ** | ** | ** | ** | ** | ** | ** | ¶ | § | ||||||
$10 | ** | ** | ||||||||||||||
$20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
$30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
$40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
$50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
$60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
$70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
$80 | Ç | ü | é | â | ä | à | å | ç | ê | ë | è | ï | î | ì | Ä | Å |
$90 | É | æ | Æ | ô | ö | ò | û | ù | ÿ | Ö | Ü | ¢ | £ | ¥ | ||
$A0 | á | í | ó | ú | ñ | Ñ | ª | º | ¿ | ¬ | ½ | ¼ | ¡ | « | » | |
$B0 | ||||||||||||||||
$C0 | ||||||||||||||||
$D0 | ||||||||||||||||
$E0 | ß | µ | ||||||||||||||
$F0 | ± | ÷ | ° | · | ² |
$0 | $1 | $2 | $3 | $4 | $5 | $6 | $7 | $8 | $9 | $A | $B | $C | $D | $E | $F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
$10 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
$20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
$30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
$40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
$50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
$60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
$70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
$80 | ||||||||||||||||
$90 | ||||||||||||||||
$A0 | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ¬ | | ® | ¯ | |
$B0 | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | º | » | ¼ | ½ | ¾ | ¿ |
$C0 | À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï |
$D0 | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß |
$E0 | à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï |
$F0 | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
$0 | $1 | $2 | $3 | $4 | $5 | $6 | $7 | $8 | $9 | $A | $B | $C | $D | $E | $F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
$10 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
$20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
$30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
$40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
$50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
$60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
$70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
$80 | À | Á | Â | Ã | Ä | Å | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï | |
$90 | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | Ù | Ú | Û | Ü | Ý | Þ | µ | × | ÷ |
$A0 | © | ¡ | ¢ | £ | ¥ | § | ¤ | « | ||||||||
$B0 | ® | · | ¦ | ¶ | » | ¬ | ¿ | |||||||||
$C0 | ¹ | ´ | ¯ | ¨ | ² | ° | ¸ | ³ | ||||||||
$D0 | ± | ¼ | ½ | ¾ | à | á | â | ã | ä | å | ç | è | é | ê | ë | |
$E0 | ì | Æ | í | ª | î | ï | ð | ñ | Ø | º | ò | ó | ô | õ | ||
$F0 | ö | æ | ù | ú | û | ü | ý | ø | ß | þ | ÿ |
#\Space | $20 |
#\Newline | $0A |
#\Backspace | $08 |
#\Tab | $09 |
#\Linefeed | $0A |
#\Page | $0C |
#\Return | $0D |
#\Rubout | $08 |
#\Rubout | $7F |
#\Newline
is the delimiter between lines.
#\Newline
is converted to CR/LF. (This is the usual
convention on DOS.) For example, #\Return #\Newline
is written as CR/CR/LF.
#\Newline
, and CR not
followed by LF is read as #\Return
.
#\Null | $00 |
#\Bell | $07 |
#\Escape | $1B |
Additionally, the following syntax is defined for characters with code from $00 to $1F:
#\^@ | $00 |
#\^A .. #\^Z | $01 .. $1A |
#\^[ | $1B |
#\^\ | $1C |
#\^] | $1D |
#\^^ | $1E |
#\^_ | $1F |
See also sec. 22.1.4.
char-code-limit
= 256.
There are fonts 0 to 15, and char-font-limit
= 16. But the system itself
uses only font 0.
The following bits attributes are implemented: :control
, :meta
, :super
,
:hyper
. Therefore char-bits-limit
= 16.
(read-char *keyboard-input*)
.
broadcast-stream
, concatenated-stream
, echo-stream
,
synonym-stream
, string-stream
, file-stream
, two-way-stream
are implemented.
function
, compile
and the like are atoms. There
are built-in functions written in C, compiled functions (both of type
compiled-function
) and interpreted functions (of type function
).
The possible function names (CLtL1 p. 59) are symbols and lambda expressions.
#<type ...>
| all structures lacking a keyword constructor |
#<ARRAY type dimensions>
| all arrays except strings, if *print-array* = nil
|
#<SYSTEM-FUNCTION name>
| built-in function written in C |
#<ADD-ON-SYSTEM-FUNCTION name>
| other function written in C |
#<SPECIAL-FORM name>
| special form handler |
#<COMPILED-CLOSURE name>
| compiled function, if *print-closure* = nil
|
#<CLOSURE name ...>
| interpreted function |
#<FRAME-POINTER #x...>
| pointer to a stack frame |
#<DISABLED POINTER>
| frame pointer which has become invalid on
exit from the corresponding block or tagbody
|
#<...-STREAM ...>
| stream |
#<PACKAGE name>
| package |
#<HASH-TABLE #x...>
| hash table, if *print-array* = nil
|
#<READTABLE #x...>
| readtable |
#<SYMBOL-MACRO form>
| symbol-macro handler |
#<FOREIGN-POINTER #x...>
| foreign pointer
(Platform dependent: UNIX, Win32, Amiga platforms only.) |
#<FOREIGN-ADDRESS #x...>
| foreign address
(Platform dependent: UNIX, Win32 platforms only.) |
#<FOREIGN-VARIABLE name #x...>
| foreign variable
(Platform dependent: UNIX, Win32 platforms only.) |
#<FOREIGN-FUNCTION name #x...>
| foreign function
(Platform dependent: UNIX, Win32 platforms only.) |
#<UNBOUND>
| "value" of a symbol without value, "value" of an unsupplied optional or keyword argument |
#<SPECIAL REFERENCE>
| environment marker for variables declared special
|
#<DOT>
| internal read result for "."
|
#<END OF FILE>
| internal read result, when the end of file
is reached
|
#<READ-LABEL ...>
| intermediate read result for #n#
|
#<ADDRESS #x...>
| machine address, should not occur |
#<SYSTEM-POINTER #x...>
| should not occur |
number
is the disjoint union of the types real
and complex
. (CLtL
wording: "exhaustive partition")
real
is the disjoint union of the types rational
and float
.
rational
is the disjoint union of the types integer
and ratio
.
integer
is the disjoint union of the types fixnum
and bignum
.
float
is the disjoint union of the types short-float
, single-float
,
double-float
and long-float
.
(eql object)
denotes the singleton set {object}.
complex
type specifier is
(complex type-of-real-part type-of-imaginary-part)
.
The type specifier (complex type)
is equivalent to (complex type type)
.
(real low high)
denotes the real numbers between low
and high.
deftype
lambda lists are subject to destructuring (nested lambda lists are
allowed, as in defmacro
) and may contain a &whole
marker, but no
&environment
marker.
(type-expand-1 typespec)
: If typespec is a user-defined type, type-expand-1
will expand it once and return two values: the expansion and t
. If typespec
is not a user-defined type, then the two values typespec and nil
are returned.
(type-expand typespec)
: This is similar to (type-expand-1 typespec)
, but
repeatedly expands typespec until it is no longer a user-defined type. A second
value of t
or nil
is returned as for type-expand-1
, indicating whether the
original typespec was a user-defined type.
type-of
are:
cons
|
symbol null boolean
|
fixnum bignum ratio short-float single-float double-float long-float complex
|
character base-char
|
(array element-type dimensions) , (simple-array element-type dimensions)
|
(vector t size) , (simple-vector size)
|
(string size) , (simple-string size)
|
(base-string size) , (simple-base-string size)
|
(bit-vector size) , (simple-bit-vector size)
|
function compiled-function
|
stream file-stream synonym-stream broadcast-stream concatenated-stream
two-way-stream echo-stream string-stream
|
package hash-table readtable pathname logical-pathname random-state byte
|
load-time-eval symbol-macro foreign-variable foreign-function weak-pointer
|
read-label frame-pointer system-internal
|
address (should not occur)
|
any other symbol (structure types or CLOS classes) |
a class (CLOS classes without proper name) |
locally
, symbol-macrolet
, load-time-value
are implemented,
and the macros
psetq
, prog1
, prog2
, when
, unless
, cond
, case
, multiple-value-list
,
multiple-value-bind
, multiple-value-setq
, and
, or
are implemented as special forms.
Constants may not be bound dynamically or lexically.
lambda-list-keywords
=
(&optional &rest &key &allow-other-keys &aux &body &whole &environment)
lambda-parameters-limit
is 65536 on 16-bit processors, 4294967296 on 32-bit
processors.
defun
and defmacro
are allowed in non-toplevel positions.
As an example, consider the old (CLtL1) definition of gensym
:
(let ((gensym-prefix "G")
(gensym-count 1))
(defun gensym (&optional (x nil s))
(when s
(cond ((stringp x) (setq gensym-prefix x))
((integerp x)
(if (minusp x)
(error "~S: index ~S is negative" 'gensym x)
(setq gensym-count x)
))
(t (error "~S: argument ~S of wrong type" 'gensym x))
) )
(prog1
(make-symbol
(concatenate 'string
gensym-prefix
(write-to-string gensym-count :base 10 :radix nil)
) )
(incf gensym-count)
) ) )
(proclaim '(special var))
declarations may not be undone. The same holds
for defvar
, defparameter
and defconstant
declarations.
It is an error if a defconstant
variable is bound at the moment the
defconstant
is executed, but defconstant
does not check this.
Constants may not be bound dynamically or lexically.
eval-when
also accepts the situations (not eval)
and (not compile)
.
realp
returns t
is its argument is a real number, nil
otherwise.
compiled-function-p
returns t
on built-in functions written in C, compiled
functions and special form handlers. Therefore compiled-function
is not a
subtype of function
.
eq
compares characters and fixnums as eql
does. No unnecessary copies are
made of characters and numbers. Nevertheless, one should use eql
.
(let ((x y)) (eq x x))
always returns t
, regardless of y
.
and
and or
are implemented as special forms and, as such, rather efficient.
IMMUTABLE
.
(function symbol)
returns the local function definition established by flet
or labels
, if it exists, otherwise the global function definition.
The CLtL2 place (fdefinition function-name)
is implemented.
(special-form-p symbol)
returns nil
or t
. If it returns t
, then
(symbol-function symbol)
returns the (useless) special form handler.
psetq
is implemented as a special form and, as such, rather efficient.
(setf (symbol-function symbol) object)
requires object to be either a
function, a symbol-function
return value or a lambda expression. A lambda
expression is thereby immediately converted to a function.
setf
also accepts places yielding multiple values.
Additional places:
funcall
:
(setf (funcall #'symbol ...) object)
and
(setf (funcall 'symbol ...) object)
are equivalent to (setf (symbol ...) object)
.
get-dispatch-macro-character
:
(setf (get-dispatch-macro-character ...) ...)
performs a set-dispatch-macro-character
.
long-float-digits
:
(setf (long-float-digits) digits)
sets the default mantissa length of long
floats to digits bits.
values
:
(setf (values place1 ... placek) form)
is approximately equivalent to
(multiple-value-bind (dummy1 ... dummyk) form
(setf place1 dummy1 ... placek dummyk)
(values dummy1 ... dummyk)
)
Example:
(setf (values a b) (values b a))
interchanges the values of a
and b
.
values-list
:
(setf (values-list list) form)
is equivalent to
(values-list (setf list (multiple-value-list form)))
&key
markers in defsetf
lambda lists are supported, but the corresponding
keywords must appear literally in the program text.
(get-setf-method form &optional env)
and
(get-setf-method-multiple-value form &optional env)
receives as optional argument the environment necessary for macro expansions.
In define-setf-method
lambda lists, one can specify &environment
and a
variable, which will be bound to the environment. This environment should be
passed to all calls of get-setf-method
and get-setf-method-multiple-value
.
If this is done, even local macros will be interpreted as places correctly.
call-arguments-limit
is 65536 on 16-bit processors, 4294967296 on 32-bit
processors.
prog1
and prog2
are implemented as special forms and, as such, rather
efficient.
symbol-macrolet
is implemented.
The macro define-symbol-macro
establishes symbol macros with global scope
(as opposed to symbol macros defined with symbol-macrolet
, which have local
scope): (define-symbol-macro symbol expansion)
.
The function symbol-macro-expand
tests for a symbol macro: If symbol is
defined as symbol macro, (symbol-macro-expand symbol)
returns two values,
t
and the expansion, else it returns nil
.
Calling boundp
on a symbol defined as symbol macro returns t
.
Calling symbol-value
on a symbol defined as symbol macro returns the value
of the expansion. Calling set
on a symbol defined as symbol macro calls
setf
on the expansion.
Calling makunbound
on a symbol defined as symbol macro removes the symbol
macro definition.
macros3
:letf
and letf*
are like let
and let*
, resp., except that they
can bind places, even places with multiple values.
Example:
(letf (((values a b) form)) ...)
(multiple-value-bind (a b) form ...)
(letf (((first l) 7)) ...)
(let* ((#:g1 l) (#:g2 (first #:g1)))
(unwind-protect (progn (setf (first #:g1) 7) ...)
(setf (first #:g1) #:g2)
) )
when
, unless
, cond
, case
are implemented as special forms and, as such, rather
efficient.
mapcap
is like mapcan
, except that it concatenates the
resulting lists with append
instead of nconc
:
(mapcap fun x1 ... xn)
== (apply #'append (mapcar fun x1 ... xn))
The function maplap
is like mapcon
, except that it concatenates the
resulting lists with append
instead of nconc
:
(maplap fun x1 ... xn)
== (apply #'append (maplist fun x1 ... xn))
(Actually a bit more efficient that this would be.)
multiple-values-limit
= 128
multiple-value-list
, multiple-value-bind
, multiple-value-setq
are
implemented as special forms and, as such, rather efficient.
The macro nth-value
:
(nth-value n form)
returns the (n+1)st value (n>=0) of form.
destructuring-bind
is implemented. It does not perform full
error checking.
declaim
is implemented.
(type type var ...)
, (ftype type fun ...)
,
(function name arglist result-type)
, (optimize (quality value) ...)
are ignored by the interpreter and the compiler.
The CLtL2 declaration (optimize (debug ...))
is legal.
Additional declarations:
(ignorable var ...)
affects the variable binding for
the variable var. The compiler will not warn about the variable, regardless
whether it is used or not.
(compile)
has the effect that the current form is compiled
prior to execution.
Examples:
(locally (declare (compile)) form)
executes a compiled version of form.
(let ((x 0))
(flet ((inc () (declare (compile)) (incf x))
(dec () (decf x)))
(values #'inc #'dec)
) )
returns two functions. The first is compiled and increments x
, the second
is interpreted (slower) and decrements the same x
.
(the value-type form)
enforces a type check in
interpreted code. No type check is done in compiled code.
macros3
:ethe
:
(ethe value-type form)
enforces a type check in both interpreted and
compiled code.
SYSTEM
has the nicknames "SYS"
and, additionally, "COMPILER"
.
The CLtL2 packages
COMMON-LISP
with nickname "CL"
and
COMMON-LISP-USER
with nickname "CL-USER"
COMMON-LISP
exports only those symbols
from the ANSI CL standard that are actually implemented.
make-package
, the default value of the :use
argument is ("LISP" "CLOS")
.
The CLtL2 macro defpackage
is implemented.
make-package
and in-package
accept a keyword argument :case-sensitive
.
Similarly, defpackage
accepts an option :case-sensitive
. When its value is
non-nil
, the package will be case sensitive, i.e. the reader will not
case-convert symbol names before looking them up or creating them in this
package. The package names are still subject to (readtable-case *readtable*)
,
though.
require
receives as optional argument either a pathname or a
list of pathnames: files to be loaded if the required module is not already
in memory.
The default number of mantissa bits in long floats is given by the place
(long-float-digits)
.
Example: (setf (long-float-digits) 3322)
sets the default precision of long
floats to 1000 decimal digits.
eql
to 0
, the number is automatically
converted to a real number. (Cf. CLtL1 p. 195)
This has the advantage that (let ((x (sqrt -9.0))) (* x x))
- instead of evaluting to #C(-9.0 0.0)
, with x
= #C(0.0 3.0)
-
evaluates to #C(-9.0 0)
= -9.0
, with x
= #C(0 3.0)
.
*FLOATING-POINT-CONTAGION-ANSI*
. When it
is non-nil, contagion is done as per the ANSI CL standard:
short->single->double->long.
1.5
is actually 1.5+-0.05
. Consider adding
1.5
and 1.75
. ANSI requires that (+ 1.5
1.75)
return 3.25
, while traditional CLISP would
return 3.3
. The implied random variables are:
3.25+-0.005
and 3.3+-0.05
. Note that the
CLISP's way DOES lies about the mean: the mean IS
3.25
and nothing else, while the ANSI's way COULD be
lying about the deviation (accuracy): if the implied accuracy of
1.5 (0.05)
is its actual accuracy, then the accuracy of the
result cannot be smaller that that. Therefore, since CL has no way of
knowing the actual accuracy, ANSI CL (and all the other standard
engineering programming languages, like C, FORTRAN etc) decides that
keeping the accuracy correct is the business of the programmer, while
the language should preserve what it can - the precision.E(x^2)-E(x)^2
can be negative!) The user should not
mix floats of different precision (that's what
*WARN-ON-FLOATING-POINT-CONTAGION*
is for), but s/he should
not be penalized for this too harshly.When *FLOATING-POINT-CONTAGION-ANSI*
is nil, the
traditional CLISP method is used, namely:
The result of an arithmetic operation whose arguments are of different float types is rounded to the float format of the shortest (least precise) of the arguments. rational -> long float -> double float -> single float -> short float (in contrast to CLtL1 p. 195!)
1.0s0
and 1.0d0
, we should get 2.0s0
.
(- (+ 1.7 pi) pi)
should not return 1.700000726342836417234L0
,
it should return 1.7f0
(or 1.700001f0
if there were rounding errors).
If the variable
*warn-on-floating-point-contagion*
is
true, a warning is emitted for every coercion involving different
floating-point types.
When rational numbers are to be converted to floats (due to
float
, coerce
, sqrt
or a
transcendental function), the result type is given by the variable
*default-float-format*
.
The macro without-floating-point-underflow
:
(without-floating-point-underflow {form}*)
executes the forms, with errors of type floating-point-underflow
inhibited.
Floating point operations will silently return zero instead of signalling
an error of type floating-point-underflow
.
(lcm)
, called without arguments, returns 1
, which is the neutral element of
composition with lcm
.
(! n)
returns the factorial of n, n a nonnegative integer.
(exquo x y)
returns the quotient x/y of two integers x,y, and checks that it
is an integer. (This is more efficient than /
.)
(xgcd x1 ... xn)
returns the values g, c1, ..., cn, where
g is the greatest common divisor of the integers x1,...,xn,
and c1,...,cn are integer coefficients such that
g
= (gcd x1 ... xn)
= (+ (* c1 x1) ... (* cn xn))
(expt base exponent)
is not very precise if exponent has large absolute
value.
(log number base)
signals an error if base = 1.
pi
is a long float with the precision given by
(long-float-digits)
. When this precision is changed, the value of pi
is
automatically recomputed. Therefore pi
is a variable, not a constant.
float-radix
always returns 2
.
(float-digits number digits)
coerces number (a real number) to a floating
point number with at least digits mantissa digits. The following holds:
(>= (float-digits (float-digits number digits)) digits)
boole-clr | = | 0 |
boole-set | = | 15 |
boole-1 | = | 10 |
boole-2 | = | 12 |
boole-c1 | = | 5 |
boole-c2 | = | 3 |
boole-and | = | 8 |
boole-ior | = | 14 |
boole-xor | = | 6 |
boole-eqv | = | 9 |
boole-nand | = | 7 |
boole-nor | = | 1 |
boole-andc1 | = | 4 |
boole-andc2 | = | 2 |
boole-orc1 | = | 13 |
boole-orc2 | = | 11 |
most-positive-fixnum
= 224-1 = 16777215
most-negative-fixnum
= -224 = -16777216
Together with pi
, the other long float constants
most-positive-long-float
,
least-positive-long-float
, least-negative-long-float
,
most-negative-long-float
,
least-positive-normalized-long-float
, least-negative-normalized-long-float
,
long-float-epsilon
, long-float-negative-epsilon
are recomputed whenever (long-float-digits)
is changed. They are variables,
not constants.
char-code-limit
= 256
char-font-limit
= 16
char-bits-limit
= 16
The graphic characters have been described above.
The standard characters are #\Newline
and those graphic characters with a
code between 32 and 126 (inclusive).
The alphabetic characters are these characters:
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzand the international alphabetic characters from the character set:
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜßáíóúñѪºãõØøÀÃÕ etc.
The functions char-equal
, char-not-equal
, char-lessp
, char-greaterp
,
char-not-greaterp
, char-not-lessp
ignore bits and font attributes of their
arguments.
(code-char #x00)
= #\Null
(code-char #x01)
= #\Code1
(code-char #x02)
= #\Code2
(code-char #x03)
= #\Code3
(code-char #x04)
= #\Code4
(code-char #x05)
= #\Code5
(code-char #x06)
= #\Code6
(code-char #x07)
= #\Bell
= #\Bel
(code-char #x08)
= #\Backspace
= #\Bs
(code-char #x09)
= #\Tab
= #\Ht
(code-char #x0A)
= #\Newline
= #\Linefeed
= #\Lf
(code-char #x0B)
= #\Vt
(code-char #x0C)
= #\Page
= #\Ff
(code-char #x0D)
= #\Return
= #\Cr
(code-char #x0E)
= #\So
(code-char #x0F)
= #\Si
(code-char #x10)
= #\Code16
(code-char #x11)
= #\Code17
(code-char #x12)
= #\Code18
(code-char #x13)
= #\Code19
(code-char #x14)
= #\Code20
(code-char #x15)
= #\Code21
(code-char #x16)
= #\Code22
(code-char #x17)
= #\Code23
(code-char #x18)
= #\Code24
(code-char #x19)
= #\Code25
(code-char #x1A)
= #\Code26
(code-char #x1B)
= #\Escape
= #\Esc
(code-char #x1C)
= #\Code28
(code-char #x1D)
= #\Code29
(code-char #x1E)
= #\Code30
(code-char #x1F)
= #\Code31
(code-char #x20)
= #\Space
(code-char #x7F)
= #\Rubout
(code-char #x9B)
= #\Csi
(code-char #x00)
= #\Null
(code-char #x07)
= #\Bell
(code-char #x08)
= #\Backspace
= #\Rubout
(code-char #x09)
= #\Tab
(code-char #x0A)
= #\Newline
= #\Linefeed
(code-char #x0B)
= #\Code11
(code-char #x0C)
= #\Page
(code-char #x0D)
= #\Return
(code-char #x1A)
= #\Code26
(code-char #x1B)
= #\Escape
(code-char #x20)
= #\Space
(code-char #x00)
= #\Null
= #\Nul
(code-char #x01)
= #\Soh
(code-char #x02)
= #\Stx
(code-char #x03)
= #\Etx
(code-char #x04)
= #\Eot
(code-char #x05)
= #\Enq
(code-char #x06)
= #\Ack
(code-char #x07)
= #\Bell
= #\Bel
(code-char #x08)
= #\Backspace
= #\Bs
(code-char #x09)
= #\Tab
= #\Ht
(code-char #x0A)
= #\Newline
= #\Nl
= #\Linefeed
(code-char #x0B)
= #\Vt
(code-char #x0C)
= #\Page
= #\Np
(code-char #x0D)
= #\Return
= #\Cr
(code-char #x0E)
= #\So
(code-char #x0F)
= #\Si
(code-char #x10)
= #\Dle
(code-char #x11)
= #\Dc1
(code-char #x12)
= #\Dc2
(code-char #x13)
= #\Dc3
(code-char #x14)
= #\Dc4
(code-char #x15)
= #\Nak
(code-char #x16)
= #\Syn
(code-char #x17)
= #\Etb
(code-char #x18)
= #\Can
(code-char #x19)
= #\Em
(code-char #x1A)
= #\Sub
(code-char #x1B)
= #\Escape
= #\Esc
(code-char #x1C)
= #\Fs
(code-char #x1D)
= #\Gs
(code-char #x1E)
= #\Rs
(code-char #x1F)
= #\Us
(code-char #x20)
= #\Space
= #\Sp
(code-char #x7F)
= #\Rubout
= #\Delete
= #\Del
char-control-bit | = 1 |
char-meta-bit | = 2 |
char-super-bit | = 4 |
char-hyper-bit | = 8 |
complement
is implemented.
nreverse
is always eq
to the argument. nreverse
on a vector
swaps pairs of elements. nreverse
on a list swaps the first and the last
element and reverses the list chaining between them.
doseq
, analogous to dolist
, may be
used instead of map
:
(doseq (var seqform [resultform]) {declaration}* {tag|statement}* )
The CLtL2 function map-into
is implemented.
remove
, remove-if
, remove-if-not
, remove-duplicates
return their argument
unchanged, if no element has to be removed.
delete
, delete-if
, delete-if-not
, delete-duplicates
destructively modify
their argument: If the argument is a list, the cdr
parts are modified. If
the argument is a vector with fill pointer, the fill pointer is lowered and
the remaining elements are compacted below the new fill pointer.
sort
and stable-sort
have two additional keywords :start
and :end
:
(sort sequence predicate &key :key :start :end)
(stable-sort sequence predicate &key :key :start :end)
sort
and stable-sort
are identical. They implement the mergesort algorithm.
sublis
and nsublis
apply the :key
argument to the nodes of the cons tree and
not to the keys of the alist.
make-hash-table
has an additional keyword :initial-contents
:
(make-hash-table &key :test :initial-contents :size :rehash-size
:rehash-threshold)
The :initial-contents
argument is an alist that is used to initialize the
new hash table.
The :rehash-threshold
argument is ignored.
For iteration through a hash table, a macro dohash
, analogous to dolist
, can
be used instead of maphash
:
(dohash (key-var value-var hash-table-form [resultform])
{declaration}* {tag|statement}*
)
make-array
can return specialized arrays for the element types
(unsigned-byte 2)
, (unsigned-byte 4)
, (unsigned-byte 8)
, (unsigned-byte 16)
,
(unsigned-byte 32)
and of course bit
and character
.
array-rank-limit
is either 65536 or 4294967296.
array-dimension-limit
= 224 = 16777216
array-total-size-limit
= 224 = 16777216
adjust-array
) in such a way that the other array points into void space.
This is not checked at the time adjust-array
is called!
char<=
. Therefore diphtongs do
not obey the usual national rules. Example: "o"
< "oe"
< "z"
< "ö"
.
:print-function
option should contain a lambda expression
(lambda (structure stream depth) (declare (ignore depth)) ...)
This lambda expression names a function whose task is to output the external
representation of structure onto the stream. This may be done by outputting
text onto the stream using write-char
, write-string
, write
, prin1
, princ
,
print
, pprint
, format
and the like. The following rules must be obeyed:
*print-escape*
must be respected.
*print-pretty*
should not and cannot be respected, since the
pretty-print mechanism is not accessible from outside.
*print-circle*
need not to be respected. This is managed by
the system. (But the print-circle mechanism handles only those objects that
are (direct or indirect) components of structure.)
*print-level*
is respected by
write
, prin1
, princ
, print
, pprint
, format ~A
, format ~S
, format ~W
and
format ~D,~B,~O,~X,~R,~F,~E,~G,~$
with not-numerical arguments.
Therefore the print-level mechanism works automatically if only these
functions are used for outputting objects and if they are not called on
objects with nesting level > 1. (The print-level mechanism does not
recognize how many parentheses you have output. It only counts how many
times it was called recursively.)
*print-length*
must be respected, especially if you are
outputting an arbitrary number of components.
*print-readably*
must be respected. Remember that the values
of *print-escape*
, *print-level*
, *print-length*
don't matter if
*print-readably*
is true.
The value of *print-readably*
is respected by print-unreadable-object
,
write
, prin1
, princ
, print
, pprint
, format ~A
, format ~S
, format ~W
and
format ~D,~B,~O,~X,~R,~F,~E,~G,~$
with not-numerical arguments.
Therefore *print-readably*
will be respected automatically if only these
functions are used for outputting objects.
*print-base*
, *print-radix*
,
*print-case*
, *print-gensym*
, *print-array*
, *print-closure*
, *print-rpars*
,
*print-indent-lists*
.
The :inherit
option is exactly like :include
except that it doesn't create
new accessors for the inherited slots.
(the-environment)
returns the current lexical
environment. This works only in interpreted code and is not compilable!
(eval-env form [env])
evaluates a form in a given lexical environment, just
if the form had been part of the program text that environment came from.
NO_READLINE
.*terminal-io*
uses the GNU readline library. Arrow keys can be
used to move within the input history. The Tab key completes the symbol's
name that is being typed.
See readline.dvi for a complete description of the key bindings.
The GNU readline library is not used if standard input and standard output do
not both refer to the same terminal.
*terminal-io*
is not the only stream that communicates directly with the
user: During execution of the body of a (with-keyboard . body)
form,
*keyboard-input*
is the stream that reads the keystrokes from the keyboard.
It returns every keystroke in detail, as character with the following bits:
hyper
char-code
#\F1
, ..., F10 -> #\F10
, F11 -> #\F11
, F12 -> #\F12
,
Insert -> #\Insert
, Delete -> #\Delete
,
Home -> #\Home
, End -> #\End
, PgUp -> #\PgUp
, PgDn -> #\PgDn
,
Arrow keys -> #\Up
, #\Down
, #\Left
, #\Right
.
#\F1
, ..., F10 -> #\F10
, F11 -> #\F11
, F12 -> #\F12
,
Insert -> #\Insert
, Delete -> #\Delete
, Center -> #\Center
,
Home -> #\Home
, End -> #\End
, PgUp -> #\PgUp
, PgDn -> #\PgDn
,
Arrow keys -> #\Up
, #\Down
, #\Left
, #\Right
.
#\F1
, ..., F9 -> #\F9
, F10 -> #\F10
,
Help -> #\Help
,
Arrow keys -> #\Up
, #\Down
, #\Left
, #\Right
.
super
control
meta
(with-keyboard . body)
form, no input from *terminal-io*
or any synonymous stream should be requested.
with-output-to-printer
:(with-output-to-printer (var) {declaration}* {form}*)
binds the variable var to an output stream that sends its output to the
printer.
(make-pipe-input-stream command [:element-type])
returns an input stream that will supply the
output from the execution of the given operating system command.
Possible :element-type
values are types equivalent to character
or
(unsigned-byte n)
, (signed-byte n)
, where n is a multiple of 8.
See also (shell command)
.
(make-pipe-output-stream command [:element-type])
returns an output stream that will pass its
output as input to the execution of the given operating system command.
Possible :element-type
values are types equivalent to character
or
(unsigned-byte n)
, (signed-byte n)
, where n is a multiple of 8.
See also (shell command)
.
(make-pipe-io-stream command [:element-type])
returns three values. The first value is a
bidirectional stream that will simultaneously pass its output as input to
the execution of the given operating system command and supply the output
from this command as input. The second and third value will be the input
stream and the output stream that make up the I/O stream, respectively.
Note that they must be closed individually.
Possible :element-type
values are types equivalent to character
or
(unsigned-byte n)
, (signed-byte n)
, where n is a multiple of 8.
Warning: Improper use of this function can lead to deadlocks. You use it at
your own risk!
A deadlock occurs if the command and your program either both try to read
from each other at the same time or both try to write to each other at
the same time. To avoid deadlocks, it is recommended that you fix a protocol
between the command and your program and avoid any hidden buffering: Use
read-char
, read-char-no-hang
, listen
instead of read-line
and read
on the
input side, and complete every output operation by a finish-output
. The same
cautions must apply to the called command as well.
See also (shell command)
.
(make-generic-stream controller)
(generic-stream-controller stream)
make-generic-stream
.(generic-stream-p stream)
t
if it is,
nil
otherwise.generic-stream-xyz
corresponds to the Common Lisp function xyz
. They all
take a controller and some number of arguments.
(generic-stream-read-char controller)
nil
at end of file.
Takes one argument, the controller object.
(generic-stream-peek-char controller)
nil
at end of file. A second value
indicates whether the side effects associated with consuming the
character were executed: t
means that a full read-char
was done,
nil
means that no side effects were done.
Takes one argument, the controller object.
(generic-stream-read-byte controller)
nil
at end of file.
Takes one argument, the controller object.
(generic-stream-listen controller)
This generic function is used to query the stream's input status.
The possible return values are the same as for the
sys::real-listen
function.
:eof
:input-available
:wait
(generic-stream-write-char controller ch)
(generic-stream-write-byte controller by)
(generic-stream-write-string controller string start len)
(controller string start len)
,
this function shall write
(subseq (the string string) start (+ start len))
First argument is the controller object.
(generic-stream-clear-input controller)
(generic-stream-clear-output controller)
(generic-stream-finish-output controller)
(generic-stream-force-output controller)
(generic-stream-close controller)
open-stream-p
is implemented.
stream-element-type
is setf
able. The element type of streams created by the
functions make-pipe-input-stream
, make-pipe-output-stream
, make-pipe-io-stream
,
socket-accept
, socket-connect
can be modified, if both the old and the new
element type are equivalent to character
or (unsigned-byte n)
, (signed-byte n)
,
where n is a positive multiple of 8.
close
ignores its :abort
argument.
The CLtL2 functions broadcast-stream-streams
, concatenated-stream-streams
,
echo-stream-input-stream
, echo-stream-output-stream
, synonym-stream-symbol
,
two-way-stream-input-stream
, two-way-stream-output-stream
are implemented.
When a token with package markers is read, then (CLtL1 p. 343/344) no
checking is done whether the package part and the symbol-name part do not
have number syntax. (What's the purpose of this check?) So we consider
tokens like USER::
or :1
or LISP::4711
or 21:3
as symbols.
(eval ``(,#'(lambda () ',a) ,#'(lambda () ',b)))
=(eval `(list #'(lambda () ',a) #'(lambda () ',b)))
=(eval (list 'list (list 'function (list 'lambda nil (list 'quote a))) (list 'function (list 'lambda nil (list 'quote b))) ) )
Multiple backquote combinations like ,,@
or ,@,@
are not implemented. Their
use would be confusing anyway.
#\
allows inputting characters of arbitrary code: #\Code231
yields the
character (code-char 231.)
.
Additional read dispatch macros:
#Y
is used to read compiled functions.
#"
is used to read pathnames:
#"test.lsp"
is the value of (pathname "test.lsp")
#"A:\\programs\\test.lsp"
#"\\.test.lsp"
readtable-case
is implemented. When the value of
(readtable-case readtable)
is :invert
, it applies to the package name and
the symbol name of a symbol separately (not to the entire token at once).
An alternative to the use of readtable-case
is the use of the
:case-sensitive
option to make-package
, in-package
and defpackage
.
sys::write-float
, floating point numbers are output in radix 2.
If *print-readably*
is true, *read-default-float-format*
has no influence on
the way floating point numbers are printed.
Pathnames are printed as follows: If *print-escape*
is nil
, only the
namestring is printed; otherwise it is printed with #P""
syntax, as per
ANSI CL <PRINT-READABLY-BEHAVIOR:CLARIFY>. But, if *print-readably*
is true,
we are in trouble as #P""
is ambiguous (which is verboten when
*print-readably*
is true), while being mandated by the ANSI. Therefore, in
this case, we print it like this:
#-CLISP #P"..." #+CLISP #S(PATHNAME ...)
*print-case*
controls the output not only of symbols, but also of characters
and some #<...>
objects.
*print-pretty*
is initially = nil
but set to t
in config.lsp
. This makes
screen output prettier.
*print-pretty*
is initially = nil
but set to t
in config.lsp
. This makes
unbuffered screen output much faster.
*print-array*
is initially = t
.
An additional variable *print-closure*
controls whether compiled and
interpreted functions (closures) are output in detailed form. If
*print-closure*
/= nil
, compiled closures are output in #Y
syntax the reader
understands. *print-closure*
is initially = nil
.
An additional variable *print-rpars*
controls the output of right (closing)
parentheses. If *print-rpars*
/= nil
, closing parentheses which don't fit
onto the same line as the the corresponding opening parenthesis are output
just below their corresponding opening parenthesis, in the same column.
*print-rpars*
is initially = t
.
An additional variable *print-indent-lists*
controls the indentation of lists
that span more than one line. It specifies by how many characters items
within the list will be indented relative to the beginning of the list.
*print-indent-lists*
is initially = 2
.
The CLtL2 macro with-standard-io-syntax
is implemented.
read-char-sequence
performs multiple read-char
operations:
(read-char-sequence sequence stream [:start] [:end])
fills the
subsequence of sequence specified by :start
and :end
with characters
consecutively read from stream. It returns the index of the first element
of sequence that was not updated (= end or < end if the stream reached its
end).
This function is especially efficient if sequence is a string and stream is
a file stream with element type character
or string-char
, a pipe stream or
a string input stream.
(system::real-listen stream)
sys::real-listen
is a variant of the standard
listen
function, which returns more detailed information
about the stream's input status. The return value is one of:
:eof
:input-available
:wait
The return values are the same as for the
generic-stream-listen
method, so this function is a good fit to define some generic streams
based upon other CLISP streams.
read-byte-sequence
performs multiple read-byte
operations:
(read-byte-sequence sequence stream [:start] [:end])
fills the
subsequence of sequence specified by :start
and :end
with integers
consecutively read from stream. It returns the index of the first element
of sequence that was not updated (= end or < end if the stream reached its
end).
This function is especially efficient if sequence is a
(vector (unsigned-byte 8))
and stream is a file stream with element type
(unsigned-byte 8)
or a pipe stream.
write
and write-to-string
have an additional keyword :closure
that can be used to bind *print-closure*
.
The CLtL2 macro print-unreadable-object
is implemented.
The function write-char-sequence
performs multiple write-char
operations:
(write-char-sequence sequence stream [:start] [:end])
outputs the characters
of the subsequence of sequence specified by :start
and :end
to stream.
It returns sequence.
This function is especially efficient if sequence is a string and stream is
a file stream with element type character
or string-char
or a pipe stream.
write-byte-sequence
performs multiple write-byte
operations:
(write-byte-sequence sequence stream [:start] [:end])
outputs the integers
of the subsequence of sequence specified by :start
and :end
to stream.
It returns sequence.
This function is especially efficient if sequence is a
(vector (unsigned-byte 8))
and stream is a file stream with element type
(unsigned-byte 8)
or a pipe stream.
format
option ~W
is analogous to ~A
and ~S
, but avoids binding of
*print-escape*
. (format stream "~W" object)
is equivalent to
(write object :stream stream)
.
The format
option ~!
is analogous to ~/
,
but avoids putting a function name into a string.
(format stream "~!" function object)
is equivalent to
(funcall function stream colon-modifier-p atsign-modifier-p object)
.
format ~R
and format ~:R
can output only integers in the range |n| < 1066.
The output is in English, according to the American conventions, and these
conventions are identical to the British conventions only in the range
|n| < 109.
format ~:@C
does not output the character itself, only the instruction how
to type the character.
For format ~E
and format ~G
, the value of *read-default-float-format*
doesn't
matter if *print-readably*
is true.
format ~T
can determine the current column of any stream.
#"FOO/BAR"
denotes the file BAR
in the directory FOO
, while
#"FOO/BAR/"
denotes the subdirectory BAR
of the directory FOO
.
#"FOO\\BAR"
denotes the file BAR
in the directory FOO
, while
#"FOO\\BAR\\"
denotes the subdirectory BAR
of the directory FOO
.
#"FOO.BAR"
denotes the file FOO
in the directory BAR
, while
#"FOO.BAR."
denotes the subdirectory BAR
of the directory FOO
.
directory
, dir
, cd
, make-dir
,
delete-dir
.
The minimum filename syntax that may be used portably is:
"xxx" | for a file with name xxx, |
"xxx.yy" | for a file with name xxx and type yy, |
".yy" | for a pathname with type yy and no name specified. |
#\_
.
Other properties of pathname syntax vary between operating systems.
host
nil
device
nil
or :wild
or "A"
|...|"Z"
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
| (subdir . subdirs)
:current
(means "."
) or
:parent
(means ".."
) or
:wild-inferiors
(means "..."
, all subdirectories) or
(name . type)
:wild
or a simple string with 8 characters maximum
:wild
or a simple string with 3 characters maximum
name
nil
or :wild
or a simple string with 8 characters maximum
type
nil
or :wild
or a simple string with 3 characters maximum
version
nil
(may also be specified as :wild
or :newest
)
When a pathname is to be fully specified (no wildcards), that means that
no :wild
, :wild-inferiors
is allowed, and name = nil
may not be allowed either.
External notation: | A:\sub1.typ\sub2.typ\name.typ
|
using defaults: | \sub1.typ\sub2.typ\name.typ
|
or | name.typ
|
or | *:\sub1.typ\*.*\name.*
|
or similar. |
Instead of '\'
one may use '/'
, as usual for DOS calls.
host
nil
device
nil
or a simple string
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
| (subdir . subdirs)
:wild-inferiors
(means "**"
or "..."
, all subdirectories) or
:parent
(means "/"
instead of "subdir/"
) or
?
and *
name
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
type
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
version
nil
(may also be specified as :wild
or :newest
)
Constraint: startpoint = :relative
only if device = nil
. If the device is
specified, the pathname must be absolute!
A filename from AMIGAOS is split into name and type according to the following rule:
'.'
in the filename, then the name is everything, type = nil
;
'.'
, then name is the part before and type the part after
the last dot.
Case is ignored in the strings on comparison. No case conversions are performed.
When a pathname is to be fully specified (no wildcards), that means that
no :wild
, :wild-inferiors
is allowed, no wildcard characters are allowed in
the strings, and name = nil
may not be allowed either.
External notation: | dev:sub1.typ/sub2.typ/name.typ
|
using defaults: | sub1.typ/sub2.typ/name.typ
|
or | name.typ
|
or | sub1.typ/**/sub3.typ/x*.lsp
|
or similar. |
Formal specification of the external notation:
Examples:
String | Device | Directory | our pathname |
---|---|---|---|
'c:foo' | 'C' | device->foo | "c" (:absolute "foo")
|
'c:foo/' | 'C' | device->foo | "c" (:absolute "foo")
|
'c:foo/bar' | 'C' | device->foo ->bar | "c" (:absolute "foo" "bar")
|
'c:/foo' | 'C' | device->up->foo | "c" (:absolute :parent "foo")
|
'c:' | 'C' | device | "c" (:absolute)
|
':foo' | current | device->root->foo | nil (:absolute "foo")
|
'foo' | current | device->foo | nil (:relative "foo")
|
'/foo' | current | device->up->foo | nil (:relative :parent "foo")
|
'//foo/bar' | current | device->up->up->foo ->bar | nil (:relative :parent :parent "foo" "bar")
|
'' | current | device | nil (:relative)
|
Appending a '/'
to a path string that is non-empty and does not end with ':'
or '/'
does not change its meaning. This '/'
must be appended before another
non-empty component can be appended.
But appending a '/'
to a path string that is empty or ends with ':'
or '/'
means going up to the parent directory!
We interpret any path string that is empty or ends with ':'
or '/'
as
pathname of a directory (with name = nil
and type = nil
).
host
nil
device
nil
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
| (subdir . subdirs)
:wild-inferiors
(means "**"
or "..."
, all subdirectories) or
?
and *
name
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
type
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
version
nil
(may also be specified as :wild
or :newest
)
A UNIX filename is split into name and type according to the following rule:
'.'
in the filename, then the name is everything, type = nil
;
'.'
, then name is the part before and type the part after
the last dot.
When a pathname is to be fully specified (no wildcards), that means that
no :wild
, :wild-inferiors
is allowed, no wildcard characters are allowed in
the strings, and name = nil
may not be allowed either.
External notation: | server:sub1.typ/sub2.typ/name.typ
|
using defaults: | sub1.typ/sub2.typ/name.typ
|
or | name.typ
|
or | sub1.typ/**/sub3.typ/x*.lsp
|
or similar. |
host
nil
device
nil
or :wild
or "A"
|...|"Z"
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
| (subdir . subdirs)
:wild-inferiors
(means "**"
or "..."
, all subdirectories) or
?
and *
name
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
type
nil
or
simple string, may contain wildcard characters ?
and *
(may also be specified as :wild
)
version
nil
(may also be specified as :wild
or :newest
)
An OS/2 filename is split into name and type according to the following rule:
'.'
in the filename, then the name is everything, type = nil
;
'.'
, then name is the part before and type the part after
the last dot.
When a pathname is to be fully specified (no wildcards), that means that
no :wild
, :wild-inferiors
is allowed, no wildcard characters are allowed in
the strings, and name = nil
may not be allowed either.
External notation: | A:\sub1.typ\sub2.typ\name.typ
|
using defaults: | \sub1.typ\sub2.typ\name.typ
|
or | name.typ
|
or | *:\sub1.typ\**\sub3.typ\x*.lsp
|
or similar. |
Instead of '\' one may use '/', as usual for DOS calls.
'*'
matches any sequence of characters, '?'
matches
any one character.
parse-namestring
. To get a pathname whose type contains a dot or whose
name contains a dot and whose type is nil
, make-pathname
must be used.
Example: (make-pathname :name ".profile")
.
A module called FileSwitch is at the centre of all filing system operation in RISC OS. FileSwitch provides a common core of functions used by all filing systems. It only provides the parts of these services that are device independent. The device dependant services that control the hardware are provided by separate modules, which are the actual filing systems. FileSwitch keeps track of active filing systems and switches betwen them as necessary.
One of the filing system modules that RISC OS provides is FileCore. It takes the normal calls that FileSwitch sends to a filing system module, and converts them to a simpler set of calls to modules that control the hardware. Unlike FileSwitch it creates a fresh instantiation of itself for each module that it supports. Using FileCore to build filing system modules imposes a more rigid structure on it, as more of the filing system is predefined.
As well as standard filing systems, FileSwitch supports image filing systems. These provide facilities for RISC OS to handle media in foreign formats, and to support `image files' (or partitions) in those formats. Rather than accessing the hardware directly they rely on standard RISC OS filing systems to do so. DOSFS is an example of an image filing system used to handle DOS format discs.
$.Documents.Memos |
%.cc |
-net-$.SystemMesg |
adfs:%.aasm |
net#MJHardy::disc1.mike |
#MJHardy::disc1.mike |
-net#MJHardy-:disc1.mike |
-#MJHardy-:disc1.mike |
File$Path | for read operations |
Run$Path | for execute operations |
*Set Source$Path adfs:$.src.,adfs:$.public.src. |
NOTE: Path variables are not implemented in this version of CLISP. A workaround for this is to use "<Foo$Path>" instead of "Foo:" until they are made available.
'$' -> | :absolute :root
|
'&' -> | :absolute :home
|
'@' -> | :absolute :current
|
'%' -> | :absolute :library
|
'\' -> | :absolute :previous
|
else | :relative
|
'^' -> | :parent
|
String | Hostname | Device | Directory | Name | Type |
---|---|---|---|---|---|
-net-$.SystemMesg | "net" | nil | (:absolute :root) | "SystemMesg" | nil
|
net#MJHardy::disc1.mike | "net#MJHardy" | "disc1" | (:absolute :root) | "mike" | nil
|
#MJHardy::disc1.mike | "#MJHardy" | "disc1" | (:absolute :root) | "mike" | nil
|
-net#MJHardy-:disc1.mike | "net#MJHardy" | "disc1" | (:absolute :root) | "mike" | nil
|
-#MJHardy-:disc1.mike | "#MJHardy" | "disc1" | (:absolute :root) | "mike" | nil
|
@.foo | nil | nil | (:absolute :current) | "foo" | nil
|
foo | nil | nil | (:relative) | "foo" | nil
|
^. | nil | nil | (:relative :parent) | nil | nil
|
@.^. | nil | nil | (:absolute :current :parent) | nil | nil
|
foo.bar | nil | nil | (:relative) | "foo" | "bar"
|
foo.bar.baz | nil | nil | (:relative "foo") | "bar" | "baz"
|
foo.bar. | nil | nil | (:relative "foo" "bar") | nil | nil
|
foo.@. | illegal |
Hostname | Device | Directory | Name | Type | RISCOS String |
---|---|---|---|---|---|
"net" | "disc1" | (:absolute :root) | "foo" | nil | "net::disc1.$.foo"
|
"net#MJ" | "disc1" | (:absolute :root "foo") | "bar" | "baz" | "net#MJ::disc1.$.foo.baz.bar"
|
"adfs" | "4" | (:absolute :root "foo" "bar") | nil | nil | "adfs::4.$.foo.bar"
|
nil | "disc1" | (:absolute :root "foo") | "bar" | nil | ":disc1.$.foo.bar"
|
nil | "disc1" | (:absolute :current) | nil | nil | illegal here |
nil | "disc1" | (:relative) | nil | nil | ":disc1."
|
nil | "disc1" | nil | nil | nil | ":disc1."
|
nil | nil | (:absolute :root) | "foo" | nil | "$.foo"
|
nil | nil | (:absolute :current) | "foo" | nil | "@.foo"
|
nil | nil | (:relative) | "foo" | "bar" | "bar.foo"
|
nil | nil | (:relative "foo") | "bar" | "baz" | "foo.baz.bar"
|
nil | nil | (:absolute :library) | "bar" | nil | "%.bar"
|
nil | nil | (:absolute :library "foo") | "bar" | nil | "%.foo.bar"
|
nil | nil | (:relative) | "foo" | "bar" | "bar.foo"
|
nil | nil | (:relative "foo") | "bar" | nil | "foo.bar"
|
nil | nil | (:relative "foo") | nil | "bar" | illegal here |
That is, the RISCOS string is the flattenation-concatenation of
(append
(if (null hostname) "" (append hostname ":"))
(if (null device) "" (append ":" device "."))
(case (pop directory)
(:absolute (case (pop directory)
(:root "$.")
(:home "&.")
(:current "@.")
(:library "%.")
(:previous "\\.")
) )
(:relative "")
)
(mapcar (lambda (subdir) (append subdir ".")) directory)
(if (null name)
(if (null type) "" (error "type with name illegal here"))
(if (null type)
name
(append type "." name)
) ) )
host
nil
device
nil
directory
(Startpoint . Subdirs)
where
:relative
| :absolute
anchor
:root
| :home
| :current
| :library
| :previous
()
| (subdir . Subdirs)
:parent
or
?
,#
and *
name
nil
or
simple string, may contain wildcard characters ?
,#
and *
(may also be specified as :wild
)
type
nil
or
simple string, may contain wildcard characters ?
,#
and *
(may also be specified as :wild
)
version
nil
(may also be specified as :wild
or :newest
)
Constraint: startpoint /= :absolute :root
only if device = nil
. If the device
is specified, the pathname must be :absolute :root
.
The wildcard characters: '*'
matches any sequence of characters, '#'
or '?'
matches any one character.
Due to the name/type swapping rule, there are pathnames that can't result
from parse-namestring
. To get a pathname whose type is nil
, make-pathname
must be used.
Example: (make-pathname :directory "!Clisp." :name "README")
.
parse-namestring
and namestring
),
of course without spaces, [,],{,}:
[ [drivespec] : ] | a letter '*' |'A' |...|'Z' |'a' |...|'z'
|
{ name [. type] \ } | each one a subdirectory, '\' may be replaced by '/'
|
[ name [. type] ] | filename with type (extension) |
Name and type may be character sequences of any length (consisting of
alphanumeric characters and '-'
, '_'
). They are shortened to 8 resp. 3
characters and converted to upper case. A single '*'
is allowed for :wild
.
[ / ] | / denotes absolute pathnames |
{ name / } | each one a subdirectory |
[ name [. type] ] | filename with type (extension) |
Name and type may be character sequences of any length (consisting of
printing ASCII characters, except '/'
).
[ [drivespec] : ] | a letter '*'|'A'|...|'Z'|'a'|...|'z' |
{ name [. type] \ } | each one a subdirectory, '\' may be replaced by '/' |
[ name [. type] ] | filename with type (extension) |
Name and type may be character sequences of any length (consisting of
printing ASCII characters, except '/'
, '\'
, ':'
).
namestring
has an optional flag argument: (namestring pathname t)
returns an
external notation suitable for passing to the operating system or other
programs.
user-homedir-pathname
is not implemented.
(defun user-homedir-pathname (&optional host)
(declare (ignore host))
(or (system::getenv "HOME") "\\")
)
wild-pathname-p
, pathname-match-p
and translate-pathname
are implemented.
pathname-match-p
does not interpret missing components as wild.
translate-pathname
has two additional keywords:
(translate-pathname source from-wildname to-wildname &key :all :merge)
If :all
is specified and non-nil
, a list of all resulting pathnames,
corresponding to all matches of (pathname-match-p source from-wildname)
,
is returned. If :merge
is specified and nil
, unspecified pieces of to-pathname
are not replaced by corresponding pieces of source.
logical-pathname
, translate-logical-pathname
,
logical-pathname-translations
, (setf logical-pathname-translations)
,
load-logical-pathname-translations
, compile-file-pathname
are implemented.
When the argument of the function translate-logical-pathname
is a string, it
is interpreted as a logical pathname string.
rename-file
always returns a non-logical pathname as its first value.
(parse-namestring string [host [defaults]])
returns a logical pathname only
if host is a logical host or host is nil
and defaults is a logical pathname.
To construct a logical pathname from a string, the function logical-pathname
can be used.
(merge-pathnames string [defaults])
returns a logical pathname only if
defaults is a logical pathname. To construct a logical pathname from a string,
the function logical-pathname
can be used.
open
cannot handle files of size >= 4 GB.
The file streams returned by open
are buffered for regular files and (on Unix)
block-devices, and unbuffered for special files.
probe-file
can not be used to check whether a directory exists. Use the
function probe-directory
or the function directory
for this purpose.
file-author
always returns nil
.
file-position
works on any buffered file stream. When a Newline is output to
resp. input from a file stream, its file position is increased by 2 since
Newline is encoded as CR/LF in the file.
load
has two additional keywords :echo
and :compiling
.
(load filename &key :verbose :print :echo :if-does-not-exist :compiling)
:verbose t
load
to emit a short message that a file is being loaded.
The default is *load-verbose*
, which is initially = t
.
:print t
load
to print the value of each form.
The default is *load-print*
, which is initially = nil
.
:echo t
*standard-output*
(normally to the screen). Should there be an error in the file,
you can see at one glance where it is.
The default is *load-echo*
, which is initially = nil
.
:compiling t
compile-file
-
not written to a file.
The default is *load-compiling*
, which is initially = nil
.
The CLtL2 variables *load-pathname*
and *load-truename*
are implemented.
The variable *load-paths*
contains a list of directories where program files
are searched - additionally to the specified or current directory - by load
,
require
, compile-file
.
(probe-directory pathname)
tests whether
pathname exists and is a directory. It will, unlike
probe-file
or truename
, not signal an error if
the parent directory of pathname doesn't exist.
The ANSI CL function ensure-directories-exist
is implemented.
(directory [pathname [:full] [:circle]])
can run in two modes:
:full
argument
is /= nil
, this contains additional information: for each matching file
you get a list of at least four elements
(file-pathname file-truename file-write-date-as-decoded-time file-length)
.
:circle
argument is /= nil
, the function avoids endless loops that
may result from symbolic links.
(dir [pathname])
is like directory
, but displays the pathnames instead of
returning them. (dir)
shows the contents of the current directory.
(cd [pathname])
manages the current directory.
(cd [pathname])
manages the current host, current device and the current directory.
(cd [pathname])
manages the current device and the current directory.
(cd pathname)
sets it, (cd)
returns it.
(default-directory)
is equivalent to (cd)
.
(setf (default-directory) pathname)
is equivalent to (cd pathname)
, except for
the return value.
(make-dir directory-pathname)
creates a new subdirectory.
(delete-dir directory-pathname)
removes an (empty) subdirectory.
(execute programfile arg1 arg2 ...)
executes an external program. Its name
is programfile. It is given the strings arg1, arg2, ... as arguments.
(execute command)
executes a given command using the operating system's shell.
(shell [command])
calls the operating system's shell.
(shell)
calls the shell for interactive use. (shell command)
calls the shell
only for execution of the one given command.
run-shell-command
and run-program
are a general interface to
shell
and the above:
(run-shell-command command [:input] [:output] [:if-output-exists])
runs a shell command.
(run-program program [:arguments] [:input] [:output] [:if-output-exists])
runs an external program.
SHELL
, which normally is /bin/sh
.
The command should be a ``simple command''; a
``command list'' should be enclosed in "{ ... ; }"
(for /bin/sh
) or "( ... )" (for /bin/csh
).
PATH
environment variable will be searched for it.
:arguments
argument :input
argument :terminal
(the standard input) or :stream
(a Lisp stream to be created) or a pathname (an
input file) or nil
(no input at all).
:output
argument :terminal
(the standard output) or :stream
(a Lisp stream to be created) or a pathname (an
output file) or nil
(ignore the output).
:if-output-exists
argument :output
file
already exists. The possible values are :overwrite
,
:append
, :error
, with the same meaning as for open
.
:stream
was specified for :input
or :output
, a Lisp stream is returned.
If :stream
was specified for :input
and :output
, three Lisp streams are
returned, as for the function make-pipe-io-stream
. This use of run-program
can cause deadlocks, see make-pipe-io-stream
.
help
command (or help key if there is one) lists the available
debugging commands.
compile
, compile-file
and disassemble
, also by the declaration (compile)
.
(compile-file input-file [:output-file] [:listing]
[:warnings] [:verbose] [:print])
compiles a file to bytecode.
:output-file
argument nil
or t
or a pathname/string/symbol
or an output-stream. The default is t
.
:listing
argument nil
or t
or a pathname/string/symbol
or an output-stream. The default is nil
.
:warnings
argument :verbose
argument :print
argument *compile-warnings*
, *compile-verbose*
, *compile-print*
provide
defaults for the :warnings
, :verbose
, :print
keyword arguments, respectively.
For each input file (default file type: #".lsp"
) the following files are
generated:
File | When | Default file type | Contents |
---|---|---|---|
output file | only if :output-file is not nil
| #".fas"
| can be loaded using the load function.
|
auxiliary output file | only if :output-file is not nil
| #".lib"
| used by compile-file when compiling
a require form referring to the input file.
|
listing file | only if :listing is not nil
| #".lis"
| disassembly of the output file. |
C output file | only if :output-file is not nil
| #".c"
| foreign function interface; this file is deleted if it is empty. |
The CLtL2 variables *compile-file-pathname*
and *compile-file-truename*
are
implemented.
The CLtL2 special form load-time-value
is implemented. (load-time-value form)
is like (quote #,form)
except that the former can be generated by macros.
disassemble
can disassemble to machine code, provided that GNU gdb is present.
In that case the argument may be a system-function
, a foreign-function
, a
special form indicator, a symbol denoting one of these, a number, or a string.
The CLtL2 function function-lambda-expression
is implemented.
(function-lambda-expression function)
returns information about the source
of an interpreted function: lambda-expression, lexical environment, name.
(TRACE fun ...)
makes the functions fun, ... traced. Syntax of fun:
Either a symbol:
symbol
or a list of a symbol and some keywords and arguments (which must come in
pairs!):
(symbol
[:suppress-if form] | no trace output as long as form is true |
[:step-if form] | invokes the stepper as soon as form is true |
[:pre form] | evaluates form before calling the function |
[:post form] | evaluates form after return from the function |
[:pre-break-if form] | goes into the break loop before calling the function if form is true |
[:post-break-if form] | goes into the break loop after return from the function if form is true |
[:pre-print form] | prints the values of form before calling the function |
[:post-print form] | prints the values of form after return from the function |
[:print form] | prints the values of form both before calling and after return from the function |
)
the function itself | as *trace-function* ,
|
the arguments to the function | as *trace-args* ,
|
the function/macro call as form | as *trace-form* ,
|
after return from the function: the list of return values from the function call | as *trace-values* ,
|
return
.
trace
and untrace
are also applicable to functions (setf symbol)
and to macros,
but not to locally defined functions and macros.
The macro space
is like the macro time
: (space form)
evaluates the form, and,
as a side effect, outputs information about the memory allocations caused by
this evaluation.
The function inspect
is not implemented.
The function room
returns two values: the number of bytes currently occupied
by Lisp objects, and the number of bytes that can be allocated before the next
regular garbage collection occurs.
The function ed
calls the external editor specified by the variable *editor*
(see config.lsp
).
editor
:ed
behaves like this only if the variable *use-ed*
is nil
.
Otherwise ed
uses a screen editor with multiple windows.
The function uncompile
does the converse of compile
: (uncompile function-name)
reverts an interpreted function that has been entered or loaded in the same
session and then compiled back to its interpreted form.
*default-time-zone*
contains the default time zone used by
encode-universal-time
and decode-universal-time
. It is initially set to -1
(which means 1 hour east of Greenwich, i.e. Mid European Time).
The timezone in a decoded time must not necessarily be an integer, but (as
float or rational number) it should be a multiple of 1/4
.
internal-time-units-per-second
= 100.
internal-time-units-per-second
= 50.
internal-time-units-per-second
= 1000000.
internal-time-units-per-second
= 10000000.
short-site-name
, long-site-name
should be defined in a site-specific config.lsp
file.
machine-type
, machine-version
, machine-instance
and
short-site-name
, long-site-name
should be defined by every user in his
site-specific config.lsp
file.
The variable *features*
initially contains the symbols
:CLISP | this implementation |
:COMMON-LISP
| |
:CLTL2
| |
:INTERPRETER
| |
:COMPILER
| |
:LOGICAL-PATHNAMES
| |
:FFI | if a foreign function interface is supported (Platform dependent: many UNIX, Win32 platforms only) |
:GETTEXT | if internationalization using the GNU gettext package is supported (Platform dependent: most UNIX platforms only) |
:LOOP
| |
:CLOS
| |
:AMIGA | if hardware = Amiga and operating system = Exec/AmigaDOS |
:DOS | if hardware = PC (clone) and operating system = DOS |
:OS/2 | if hardware = PC (clone) and operating system = OS/2 |
:WIN32 | if hardware = PC (clone) and operating system = Win32 (Windows NT or Windows 95) |
:PC386 | if hardware = PC (clone) with a 386/486/586/686 |
:UNIX | if operating system = Unix (yes, in this case the hardware is irrelevant!) |
loop
and loop-finish
are implemented.
formatter
is implemented.
"CLOS"
and thus normally
visible in all user packages. If you don't want them (for example, if you
want to use PCL instead of CLOS), do (unuse-package "CLOS")
.
slot-value
, slot-boundp
, slot-makunbound
, slot-exists-p
,
find-class
, (setf find-class)
, class-of
, call-next-method
, next-method-p
,
class-name
, (setf class-name)
, no-applicable-method
, no-next-method
,
find-method
, add-method
, remove-method
, compute-applicable-methods
,
method-qualifiers
, function-keywords
, slot-missing
, slot-unbound
,
print-object
, describe-object
, make-instance
, initialize-instance
,
reinitialize-instance
, shared-initialize
,
with-slots
, with-accessors
, defclass
, defmethod
, defgeneric
,
generic-function
, generic-flet
, generic-labels
,
standard-class
, structure-class
, built-in-class
, standard-object
,
standard-generic-function
, standard-method
and all predefined classes,
standard
defclass
: It is required that the superclasses of a class be defined before
the defclass
form for the class is evaluated.
defclass
supports the option :metaclass structure-class
. This option is
necessary in order to define a subclass of a defstruct
-defined structure type
using defclass
instead of defstruct
.
The real
type is added to the predefined classes listed in table 28-1.
Only standard
method combination is implemented.
When call-next-method
is called with arguments, the rule that the ordered
set of applicable methods must be the same as for the original arguments
is enforced by the implementation only in interpreted code.
call-next-method
and next-method-p
are local macros, not local functions.
Use #'(lambda () (call-next-method))
instead of #'call-next-method
if you
really need it as a function.
There is a generic function no-primary-method
(analogous to
no-applicable-method
) which is called when a generic function of the class
standard-generic-function
is invoked and no primary method on that generic
function is applicable.
generic-flet
and generic-labels
are implemented as macros, not as special
forms.
The function ensure-generic-function
is not implemented.
add-method
can put methods into other generic functions than the one the method
came from.
print-object
and describe-object
are only called on objects of type
standard-object
.
describe-object
should not call describe
recursively as this would produce
more information than is likely to be useful to a human reader.
documentation
still has the CLtL1 implementation.
User-defined method combination is not supported.
The sections 28.1.7.3., 28.1.7.4., the macros define-method-combination
,
call-method
and the functions invalid-method-error
, method-combination-error
,
method-qualifiers
are not implemented.
The special form with-added-methods
is not implemented.
Redefining classes is not supported.
The sections 28.1.10., 28.1.10.1., 28.1.10.2., 28.1.10.3., 28.1.10.4. and the
function update-instance-for-redefined-class
are not implemented.
Changing the class of a given instance is not supported.
The sections 28.1.11., 28.1.11.1., 28.1.11.2., 28.1.11.3. and the functions
change-class
, update-instance-for-different-class
, make-instances-obsolete
are
not implemented.
signal
is
simple-condition
, not simple-error
.
(muffle-cerrors {form}*)
executes the forms. When a continuable
error occurs, no message is printed. Instead, the continue
restart is invoked.
The macro (appease-cerrors {form}*)
executes the forms. When a continuable
error occurs, the error is printed as a warning and the continue
restart is
invoked.
The macro (exit-on-error {form}*)
executes the forms. When a non-continuable
error or a Ctrl-C interrupt occurs, the error is printed and CLISP terminates
with error status.
restart-case
clauses the argument list can also be specified after the
keyword/value pairs instead of before them. The syntax therefore is
(restart-case form {restart-clause}*)
with
restart-clause ::= | (restart-name arglist {keyword value}* {form}*)
|
| (restart-name {keyword value}* arglist {form}*)
|
The macro with-restarts
is like restart-case
, except that the forms are
specified after the restart clauses instead of before them, and the
restarts created are not implicitly associated to any condition.
(with-restarts (
{restart-clause}*)
{form}*)
is therefore equivalent to (restart-case (progn
{form}*)
{restart-clause}*)
.
compute-restarts
and find-restart
behave as specified in ANSI CL: If the
optional condition argument is not nil
, only restarts associated with that
condition and restarts associated to no condition at all are considered.
Therefore the effect of associating a restart to a condition is not to
activate it, but to hide it from other conditions. This makes the syntax
dependent implicit association performed by restart-case
nearly obsolete.
warn
is simple-warning
,
not simple-error
.
(saveinitmem [filename [:quiet] [:init-function]])
saves the
running CLISP's memory to a file. The filename defaults to "lispinit.mem"
.
If the :quiet
argument is not nil
, the startup banner and the good-bye
message will be suppressed. The :init-function
argument specifies a function
that will be executed at startup of the saved image.
(exit [errorp])
, (quit [errorp])
and (bye [errorp])
- all synonymous - terminate CLISP. If errorp is not nil
, CLISP aborts with
error status, i.e. the environment is informed that the CLISP session didn't
succeed.
ENGLISH
or DEUTSCH
(i.e. german) or FRANCAIS
(i.e. french) or ESPAÑOL
(i.e.
spanish). More languages can be defined through the macro deflanguage
:
(deflanguage lang)
For such an additional language to take effect, you must install the
corresponding message catalog, or translate the messages yourself, by use
of GNU gettext and Emacs po-mode.
The macros ENGLISH
, DEUTSCH
, FRANCAIS
produce strings that depends on the
language:
(ENGLISH english-string DEUTSCH deutsch-string FRANCAIS francais-string)
- and all permutations of this - evaluates all of english-string,
deutsch-string, francais-string in no particular order and returns the
evaluation result corresponding to the user language, be it among these
three or not.
This works only for strings. For arbitrary language-dependent Lisp objects,
you define one through the macro definternational
:
(definternational symbol [(t default-language)])
,
and add language-dependent values through the macro deflocalized
:
(deflocalized symbol language value-form)
(One such form for each language. Languages without an assigned value will
be treated like the default-language.) You can then access the localized value
through the function call
(localized symbol [language])
.
(make-weak-pointer value)
returns a fresh weak pointer referring to value.
(weak-pointer-p object)
returns true if the object is of type weak-pointer
.
(weak-pointer-value weak-pointer)
returns two values: The original value and
t
, if the value has not yet been garbage collected, else nil
and nil
.
(finalize object function)
has the effect that when the specified
object is being garbage collected, (funcall function object)
will be executed.
Calling (finalize object function guardian)
has a similar effect, but only
as long as the "guardian" has not been garbage collected: When object is
being garbage collected, (funcall function object guardian)
will be executed.
If the guardian is garbage collected before object is, nothing happens.
Note: The time when "object is being garbage collected" is not defined deterministically. (Actually, it possibly never occurs.) It denotes a moment at which no references to object exist from other Lisp objects. When the function is called, object (and possibly guardian) enter the "arena of live Lisp objects" again.
No finalization request will be executed more than once.
sys::*prompt*
controls the appearance of the
prompt. When its value is a function, it is called and it's value is
printed with princ
. Otherwise, the value itself is printed
with princ
. The default value of
sys::*prompt*
prints
"package[nn]> " where package is
the shortest (nick)name of the current package *package*
if
it is the same as it was in the beginning or if it doesn't contain
symbol t
(it is assumed that in the latter case you would
want to keep in mind that your current package is something weird); and
nn is the ordinal number of the current prompt (hopefully, it
will remain finite). To help you in constructing your own fancy
prompts, 2 functions are provided: sys::prompt-new-package
,
returning *package*
or nil
if the current
package is the same as it was initially; and
sys::package-short-name
taking one argument, a package, and
returning its shortest name or nickname. Also, a variable
sys::*command-index*
contains the current prompt number, it
is your responsibility to increment it (you might also want to reset it).
invoke-debugger
, break
,
signal
, error
, cerror
, warn
. The stepper is invoked through the macro step
.
Debugger and stepper execute subordinate read
- eval
- print
loops (called
"break loops") which are analogous to the main read
- eval
- print
loop except
for the prompt and the set of available commands. Commands must be typed
literally, without surrounding quotes or white space.
Commands common to the main loop, the debugger and the stepper:
Help | prints a list of available commands. |
Commands common to the debugger and the stepper:
Abort | abort to the next most recent read - eval - print loop.
|
Unwind | abort to the next most recent read - eval - print loop.
|
The stack is organized into frames and other stack elements. Usually every
invocation of an interpreted function and every evaluation of an interpreted
form corresponds to one stack frame. Special forms such as let
, let*
,
unwind-protect
and catch
produce special kinds of stack frames.
In a break loop there is a current stack frame, which is initially the most
recent stack frame but can be moved using the debugger commands Up
and Down
.
Evaluation of forms in a break loop occurs in the lexical environment of the current stack frame but in the dynamic environment of the debugger's caller. This means that to inspect or modify a lexical variable all you have to do is to move to the current stack frame just below the frame that corresponds to the form or the function call that binds that variable.
There is a current "stack mode" which defines in how much detail the stack is shown by the stack related debugger commands.
Commands common to the debugger and the stepper:
Mode-1 | sets the current mode to 1: all the stack elements are considered. This mode is fine for debugging compiled functions. |
Mode-2 | sets the current mode to 2: all the frames are considered. |
Mode-3 | sets the current mode to 3: only lexical frames (frames that correspond to special forms that modify the lexical environment) are considered. |
Mode-4 | sets the current mode to 4 (the default): only eval and apply
frames are considered. Every evaluation of a form in the
interpreter corresponds to an EVAL frame.
|
Mode-5 | sets the current mode to 5: only apply frames are considered.
Every invocation of an interpreted function corresponds to one
apply frame.
|
Where | shows the current stack frame. |
Up | goes up one frame, i.e. to the caller if in mode-5 |
Down | does down one frame, i.e. to the callee if in mode-5 |
Top | goes to top frame, i.e. to the top-level form if in mode-4 |
Bottom | goes to bottom (most recent) frame, i.e. most probably to the form or function that caused the debugger to be entered. |
Backtrace | lists the stack in current mode, bottom frame first, top frame last. |
Backtrace-1 | lists the stack in mode 1. |
Backtrace-2 | lists the stack in mode 2. |
Backtrace-3 | lists the stack in mode 3. |
Backtrace-4 | lists the stack in mode 4. |
Backtrace-5 | lists the stack in mode 5. |
eval
or apply
frame, the following commands
are available as well:
Break+ | sets a breakpoint in the current frame. When the corresponding
form or function will be left, the debugger will be entered
again, with the variable *trace-values* containing a list of
its values.
|
Break- | removes a breakpoint from the current frame. |
Redo | re-evaluates the corresponding form or function call. This command can be used to restart parts of a computation without aborting it entirely. |
Return | leaves the current frame. You will be prompted for the return values. |
Commands specific to the debugger:
Continue | continues evaluation of the program. |
Commands specific to the stepper:
Step | step into a form: evaluate this form in single step mode |
Next | step over a form: evaluate this form at once |
Over | step over this level: evaluate at once up to the next return |
Continue | switch off single step mode, continue evaluation |
The stepper is usually used like this: If some form returns a strange value
or results in an error, call (step form)
and navigate using the commands
Step
and Next
until you reach the form you regard as responsible. If you
are too fast (execute Next
once and get the error), there is no way back; you
have to restart the entire stepper session. If you are too slow (stepped into
a function or a form which certainly is OK), a couple of Next
commands or one
Over
command will help.
(screen:make-window)
*terminal-io*
shouldn't be used for input or
output during this time. (Use with-keyboard
and *keyboard-input*
instead.)
(screen:with-window . body)
screen:*window*
to a window stream and executes body. The stream is
guaranteed to be closed when the body is left. During its execution,
*terminal-io*
shouldn't be used, as above.
(screen:window-size window-stream)
(screen:window-cursor-position window-stream)
(screen:set-window-cursor-position window-stream line column)
(screen:clear-window window-stream)
(screen:clear-window-to-eot window-stream)
(screen:clear-window-to-eol window-stream)
(screen:delete-window-line window-stream)
(screen:insert-window-line window-stream)
(screen:highlight-on window-stream)
(screen:highlight-off window-stream)
(screen:window-cursor-on window-stream)
(screen:window-cursor-off window-stream)
CLISP has a facility for adding external modules (written in C, for example).
It is invoked through clisp-link
.
A module is a piece of external code which defines extra Lisp objects, symbols
and functions. A module name must consist of the characters A-Z,a-z,_,0-9. The
module name "clisp"
is reserved. Normally a module name is derived from the
corresponding file name.
clisp-link
needs a directory containing:
modules.d
|
modules.c
|
clisp.h
|
clisp-link
expects to find these files in a subdirectory linkkit/
of the
current directory. This can be overridden by the environment variable
CLISP_LINKKIT
.
clisp-link
operates on CLISP linking sets and on module sets.
A linking set is a directory containing:
makevars
/bin/sh
commands, setting the variables
CC
CFLAGS
CLFLAGS
LIBS
X_LIBS
RANLIB
FILES
modules.h
FILES
listed in makevars
lisp.run
lispinit.mem
dir/lisp.run -M dir/lispinit.mem
".
A module set is a directory containing:
link.sh
/bin/sh
commands, which prepare the directory
before linking, and set the variables NEW_FILES
, NEW_LIBS
,
NEW_MODULES
, TO_LOAD
and optionally TO_PRELOAD
link.sh
.
link.sh
the module set directory is referred to as "$modulename"/
.
NEW_FILES
variable NEW_LIBS
variable NEW_MODULES
variable .c
file in the module set
defines a module of its own. The module name is derived from the file name.
TO_LOAD
variable lispinit.mem
belonging to a new linking set.
TO_PRELOAD
variable, if defined, lispinit.mem
file, before
building the lispinit.mem
belonging to a new linking set. This variable
is usually used for defining Lisp packages which must be present when
the new .c
files are initialized.
The command
"clisp-link create-module-set module-dir file1.c ...
"
creates a module set in module-dir which refers (via symbolic links) to
file1.c
etc. The files are expected to be modules of their own.
The command
"clisp-link add-module-set module-dir source-dir destination-dir
"
combines a linking set in source-dir and a module in module-dir to a new
linking set, in a directory destination-dir which is newly created.
The command
"clisp-link run source-dir module-dir ..."
runs the linking set in source-dir, with the module in module-dir loaded.
More than one module can be specified. If CLISP has been built with the
configuration option --with-dynamic-modules
, the loading will be performed
through dynamic loading. Otherwise -- this is much slower -- a temporary
linking set will be created and deleted afterwards. Note that dynamic loading
does not work on all operating systems, and that --with-dynamic-modules
precludes some efficiency optimizations which are on by default.
$ clisp-link create-module-set linux /somewhere/bindings/linux.c
Modify the newly created linux/link.sh
to add "-lm
" to the libraries:
NEW_LIBS="$file_list"
-->
NEW_LIBS="$file_list -lm"
Modify the newly created linux/link.sh
to load linux.fas
before saving
the memory image:
TO_LOAD=''
-->
TO_LOAD='/somewhere/bindings/linux.fas'
linux.lsp
, creating linux.c
:
$ clisp -c /somewhere/bindings/linux.lsp
$ clisp-link add-module-set linux base base+linux
$ base+linux/lisp.run -M base+linux/lispinit.mem
> (linux::stat "/tmp")
A foreign function description is written as a Lisp file,
and when compiled it produces a .c
file which is then compiled
by the C compiler and may be linked together with lisp.a
.
All symbols relating to the foreign function interface are exported from
the package FFI. To use them, (use-package "FFI")
.
Special FFI forms may appear anywhere in the Lisp file.
(def-c-type name c-type)
(def-c-var name {option}*)
option ::= | |
(:name c-name)
| |
| | (:type c-type)
|
| | (:read-only boolean)
|
| | (:alloc allocation)
|
(def-call-out name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
| | (:language language)
|
(def-call-in name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
| | (:language language)
|
(def-c-call-out name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
(def-c-call-in name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
(def-c-struct name (ident c-type)*)
(def-c-enum name {ident | (ident [value])}*)
(c-lines format-string {argument}*)
(element c-place {index}*)
(deref c-place)
(slot c-place slot-name)
(cast c-place c-type)
(typeof c-place)
(sizeof c-place)
, (sizeof c-type)
(bitsizeof c-place)
, (bitsizeof c-type)
(validp foreign-entity)
name is any Lisp symbol.
c-name is a string.
A c-type is either a predefined C type or the name of a type defined by
def-c-type
.
The simple C types are these:
Lisp name | Lisp equiv | C equiv | ILU equiv | Comment |
---|---|---|---|---|
nil | nil | void | as a result type only | |
boolean | boolean | int | BOOLEAN
| |
character | character | char | SHORT CHARACTER
| |
char | integer | signed char
| ||
uchar | integer | unsigned char
| ||
short | integer | short
| ||
ushort | integer | unsigned short
| ||
int | integer | int
| ||
uint | integer | unsigned int
| ||
long | integer | long
| ||
ulong | integer | unsigned long
| ||
uint8 | (unsigned-byte 8) | uint8 | BYTE
| |
sint8 | (signed-byte 8) | sint8
| ||
uint16 | (unsigned-byte 16) | uint16 | SHORT CARDINAL
| |
sint16 | (signed-byte 16) | sint16 | SHORT INTEGER
| |
uint32 | (unsigned-byte 32) | uint32 | CARDINAL
| |
sint32 | (signed-byte 32) | sint32 | INTEGER
| |
uint64 | (unsigned-byte 64) | uint64 | LONG CARDINAL | does not work on all platforms |
sint64 | (signed-byte 64) | sint64 | LONG INTEGER | does not work on all platforms |
single-float | single-float | float
| ||
double-float | double-float | double
|
The predefined C types are:
c-type ::= | |
simple-c-type | |
| | c-pointer
|
| | c-string
|
| | (c-struct class (ident c-type)*)
|
| | (c-union (ident c-type)*)
|
| | (c-array c-type dimensions)
dimensions ::= number | ({number}*)
|
| | (c-array-max c-type maxdimension)
maxdimension ::= number |
| | (c-function {option}*)
option ::= (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])
| (:language language)
|
| | (c-ptr c-type)
|
| | (c-ptr-null c-type)
|
| | (c-array-ptr c-type)
|
(def-c-type name c-type)
makes name a shortcut for c-type. Note that c-type may already refer
to name. Forward declarations of types are not possible, however.
The type c-pointer
corresponds to what C calls "void*
", an opaque pointer.
The type c-string
corresponds to what C calls "char*
", a zero-terminated
string. Its Lisp equivalent is a string, without the trailing zero character.
The type (c-struct class (ident1 type1) ... (identn typen))
is equivalent to
what C calls "struct { type1 ident1; ...; typen identn; }
". Its Lisp
equivalent is: if class is vector
, a simple-vector; if class is list
, a list;
if class is a symbol naming a structure or CLOS class: an instance of this
class, with slots of names ident1,...,identn.
The type (c-union (ident1 type1) ... (identn typen))
is equivalent to what C
calls "union { type1 ident1; ...; typen identn; }
". Conversion to and from
Lisp assumes that a value is to be viewed as being of type1.
The type (c-array type dim1 ... dimn)
is equivalent to what C calls
"type [dim1]...[dimn]
". Note that when an array is passed as an argument to
a function in C, it is actually passed as a pointer; you therefore have to
write (c-ptr (c-array ...))
for this argument's type.
The type (c-array-max type maxdim)
is equivalent to what C calls
"type [maxdim]
", an array containing up to maxdim elements. The array is
zero-terminated if it contains less than maxdim elements. Conversion from Lisp
of an array with more than maxdim elements silently ignores the superfluous
elements.
The type (c-ptr type)
is equivalent to what C calls "type *
": a pointer to
a single item of the given type.
The type (c-ptr-null type)
is also equivalent to what C calls "type *"
: a
pointer to a single item of the given type, with the exception that C NULL
corresponds to Lisp nil
.
The type (c-array-ptr type)
is equivalent to what C calls "type (*)[]
":
a pointer to a zero-terminated array of items of the given type.
The type (c-function (:return-type rtype) (:arguments (arg1 type1 ...) ...))
designates a C function that can be called according to the given prototype
(rtype (*) (type1, ...))
.
The language is either :C
(denotes K&R C) or :STDC
(denotes ANSI C) or
:STDC-STDCALL
(denotes ANSI C with stdcall calling convention). It
specifies whether the C function has been compiled by a K&R C compiler or by
an ANSI C compiler, and possibly the calling convention.
Conversion between C functions and Lisp functions is transparent.
(def-c-struct name (ident c-type)*)
defines name to be both a
defstruct
structure type and a foreign C type with the given slots.
(def-c-enum name {ident | (ident [value])}*)
defines idents as
constants, similarly to the C declaration enum { ident [= value], ... };
(c-lines format-string {argument}*)
outputs the string (format nil format-string {argument}*)
to the C output
file. This is a rarely needed low-level facility.
The form (sizeof c-type)
returns the size and alignment of a C type,
measured in bytes.
The form (bitsizeof c-type)
returns the size and alignment of a C type,
measured in bits.
The predicate (validp foreign-entity)
returns nil
if the foreign-entity
(e.g. the Lisp equivalent of a c-pointer
) refers to a pointer which is
invalid because it comes from a previous Lisp session. It returns t
if
foreign-entity can be used within the current Lisp process.
setq
,
just as normal variables can, except that the range of allowed values is
limited according to the variable's foreign type. Note that for a foreign
variable x the form (eql x x)
is not necessarily true, since every time x is
evaluated its foreign value is converted to a freshly created Lisp value.
(def-c-var name {option}*)
option ::= | |
(:name c-name)
| |
| | (:type c-type)
|
| | (:read-only boolean)
|
| | (:alloc allocation)
|
The :name
option specifies the name, as seen from C, as a string. If not
specified, it is derived from the print name of the Lisp name.
The :type
option specifies the variable's foreign type.
If the :read-only
option is specified and non-nil
, it will be impossible
to change the variable's value from within Lisp (using setq
or similar).
The :alloc
option can be either :none
or :malloc-free
and defaults to :none
.
If it is :malloc-free
, any values of type c-string
, (c-ptr ...)
,
(c-ptr-null ...)
, (c-array-ptr ...)
within the foreign value are assumed to
be pointers to malloc()
-allocated storage, and when setq
replaces an old
value by a new one, the old storage is freed using free()
and the new storage
allocated using malloc()
. If it is :none
, setq
assumes that the pointers
point to good storage (not NULL
!) and overwrites the old values by the new
ones. This is dangerous (just think of overwriting a string with a longer one
or storing some data in a NULL
pointer...) and deprecated.
def-c-var
defines a "place", i.e.
a form which can also be used as argument to setf
. (An "lvalue" in C
terminology.) The following operations are available on foreign places:
(element place index1 ... indexn)
Array element: If place is of foreign type (c-array c-type dim1 ... dimn)
and 0 <= index1 < dim1, ..., 0 <= indexn < dimn, this will be the place
corresponding to (aref place index1 ... indexn)
or place[index1]...[indexn]
.
It is a place of type c-type.
If place is of foreign type (c-array-max c-type dim)
and 0 <= index < dim,
this will be the place corresponding to (aref place index)
or place[index]
.
It is a place of type c-type.
(deref place)
Dereference pointer: If place is of foreign type (c-ptr c-type)
or
(c-ptr-null c-type)
, this will be the place the pointer points to. It is a
place of type c-type. For (c-ptr-null c-type)
, the place may not be NULL
.
(slot place slot-name)
Struct or union component: If place is of foreign type
(c-struct class ... (slot-name c-type) ...)
or of type
(c-union ... (slot-name c-type) ...)
, this will be of type c-type.
(cast place c-type)
Type change: A place denoting the same memory locations as the original place,
but of type c-type.
(typeof place)
returns the c-type corresponding to the place.
(sizeof place)
returns the size and alignment of the C type of place,
measured in bytes.
(bitsizeof place)
returns the size and alignment of the C type of place,
measured in bits.
def-call-out
or created via
def-call-in
) and anonymous foreign functions; they arise through conversion
of function pointers.
A "call-out" function is a foreign function called from Lisp: control flow temporarily leaves Lisp. A "call-in" function is a Lisp function called from the foreign language: control flow temporary enters Lisp.
(def-call-out name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
| | (:language language)
|
#'name
is
redirected to call the C function c-name.
def-c-call-out
is equivalent to def-call-out
with :language :c
.
(def-call-in name {option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
| | (:language language)
|
#'name
.
def-c-call-in
is equivalent to def-call-in
with :language :c
.
Values of simple-c-type, c-pointer
are passed on the stack, with dynamic
extent. The allocation is effectively ignored.
Values of type c-string
, (c-ptr
...)
, (c-ptr-null
...)
, (c-array-ptr
...)
need
storage. The allocation specifies the allocation policy:
allocation is :none | means that no storage is allocated. |
allocation is :alloca | means allocation of storage on the stack, which has dynamic extent. |
allocation is :malloc-free | means that storage will be allocated
via malloc() and freed via free() .
|
:none
for most
types, but :alloca
for c-string
and (c-ptr
...)
and (c-ptr-null
...)
and
(c-array-ptr
...)
and for :out
arguments. [Subject to change!]
The :malloc-free
policy provides the ability to pass arbitrarily nested
structs containing pointers pointing to structs ... within a single conversion.
:malloc-free
,
:alloca
,
:none
,
:malloc-free
,
:none
,
:malloc-free
,
:alloca
or :none
,
:malloc-free
,
:none
,
A function parameter's param-mode may be
:in
(means: read-only):
:out
(means: write-only):
:in-out
(means: read-write):
:out
" value is
returned as an additional multiple value.
:in
.
[Currently, only :in
is fully implemented. :out
works only with
allocation = :alloca
.]
:malloc-free
because there is no commonly
used malloc()/free()
library function.
The allocation may be followed by a register specification,
any of the symbols :d0
, :d1
, :d2
, :d3
, :d4
, :d5
, :d6
, :d7
, :a0
, :a1
, :a2
,
:a3
, :a4
, :a5
, :a6
, each representing one 680x0 register. This works only
for integral types: integers, pointers, c-string
, c-function
.
Passing c-struct
, c-union
, c-array
, c-array-max
values as arguments (not via
pointers) is only possible to the extent the C compiler supports it. Most C
compilers do it right, but some C compilers (such as gcc on hppa) have
problems with this.
struct foo {
int a;
struct foo * b[100];
};
corresponds to
(def-c-struct foo
(a int)
(b (c-array (c-ptr foo) 100))
)
The element access
struct foo f;
f.b[7].a
corresponds to
(declare (type foo f))
(foo-a (aref (foo-b f) 7)) or (slot-value (aref (slot-value f 'b) 7) 'a)
Ex. 2: Here is an example of an external C variable and some accesses:
struct bar {
short x, y;
char a, b;
int z;
struct bar * n;
};
extern struct bar * my_struct;
my_struct->x++;
my_struct->a = 5;
my_struct = my_struct->n;
corresponds to
(def-c-struct bar
(x short)
(y short)
(a char)
(b char) ; or (b character) if it represents a character, not a number
(z int)
(n (c-ptr bar))
)
(def-c-var my_struct (:type (c-ptr bar)))
(setq my_struct (let ((s my_struct)) (incf (slot-value s 'x)) s))
or (incf (slot my_struct 'x))
(setq my_struct (let ((s my_struct)) (setf (slot-value s 'a) 5) s))
or (setf (slot my_struct 'a) 5)
(setq my_struct (slot-value my_struct 'n))
or (setq my_struct (deref (slot my_struct 'n)))
Ex. 3: An example for calling an external function:
On ANSI C systems, <stdlib.h> contains the declarations
typedef struct {
int quot; /* Quotient */
int rem; /* Remainder */
} div_t;
extern div_t div (int numer, int denom);
This translates to
(def-c-struct div_t
(quot int)
(rem int)
)
(def-c-call-out div (:arguments (numer int) (denom int))
(:return-type div_t)
)
Sample call from within Lisp:
> (div 20 3)
#S(DIV :QUOT 6 :REM 2)
Ex. 4: Another example for calling an external function:
Suppose the following is defined in a file "cfun.c"
:
struct cfunr { int x; char *s; };
struct cfunr * cfun (i,s,r,a)
int i;
char *s;
struct cfunr * r;
int a[10];
{
int j;
struct cfunr * r2;
printf("i = %d\n", i);
printf("s = %s\n", s);
printf("r->x = %d\n", r->x);
printf("r->s = %s\n", r->s);
for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]);
r2 = (struct cfunr *) malloc (sizeof (struct cfunr));
r2->x = i+5;
r2->s = "A C string";
return r2;
}
It is possible to call this function from Lisp using the file "callcfun.lsp"
(don't call it "cfun.lsp"
- compile-file
would overwrite "cfun.c"
) whose
contents is:
(in-package "TEST-C-CALL" :use '("LISP" "FFI"))
(def-c-struct cfunr (x int) (s c-string))
(def-c-call-out cfun (:arguments (i int)
(s c-string)
(r (c-ptr cfunr) :in :alloca)
(a (c-ptr (c-array int 10)) :in :alloca)
)
(:return-type (c-ptr cfunr))
)
(defun call-cfun ()
(cfun 5 "A Lisp string" (make-cfunr :x 10 :s "Another Lisp string")
'#(0 1 2 3 4 5 6 7 8 9)
) )
Use the module facility:
$ clisp-link create-module-set cfun callcfun.c
$ cc -O -c cfun.c
$ cd cfun
$ ln -s ../cfun.o cfun.o
Add cfun.o to NEW_LIBS and NEW_FILES in link.sh.
$ cd ..
$ base/lisp.run -M base/lispinit.mem -c callcfun.lsp
$ clisp-link add-module-set cfun base base+cfun
$ base+cfun/lisp.run -M base+cfun/lispinit.mem -i callcfun
> (test-c-call::call-cfun)
i = 5
s = A Lisp string
r->x = 10
r->s = Another Lisp string
a[0] = 0.
a[1] = 1.
a[2] = 2.
a[3] = 3.
a[4] = 4.
a[5] = 5.
a[6] = 6.
a[7] = 7.
a[8] = 8.
a[9] = 9.
#S(TEST-C-CALL::CFUNR :X 10 :S "A C string")
>
$ rm -r base+cfun
Note that there is a memory leak here: The return value r2
of cfun()
is
malloc()
ed but never free()
d. Specifying
(:return-type (c-ptr cfunr) :malloc-free)
is not an alternative because this would also free(r2->x)
but r2->x
is a
pointer to static data.
Ex. 5: To sort an array of double-floats using the Lisp function sort
instead of the C library function qsort()
, one can use the following
interface code "sort1.c"
. The main problem is to pass a variable-sized array.
extern void lispsort_begin (int);
void* lispsort_function;
void lispsort_double (int n, double * array)
{
double * sorted_array;
int i;
lispsort_begin(n); /* store #'sort2 in lispsort_function */
sorted_array = ((double * (*) (double *)) lispsort_function) (array);
for (i = 0; i < n; i++) array[i] = sorted_array[i];
free(sorted_array);
}
This is accompanied by "sort2.lsp"
:
(use-package "FFI")
(def-call-in lispsort_begin (:arguments (n int))
(:return-type nil)
(:language :stdc)
)
(def-c-var lispsort_function (:type c-pointer))
(defun lispsort_begin (n)
(setf (cast lispsort_function
`(c-function
(:arguments (v (c-ptr (c-array double-float ,n))))
(:return-type (c-ptr (c-array double-float ,n))
:malloc-free
) )
)
#'sort2
) )
(defun sort2 (v)
(declare (type vector v))
(sort v #'<)
)
To test this, use the following test file "sorttest.lsp"
:
(def-call-out sort10
(:name "lispsort_double")
(:language :stdc)
(:arguments (n int)
(array (c-ptr (c-array double-float 10))
:in-out
) ) )
Now try
$ clisp-link create-module-set sort sort2.c sorttest.c
$ cc -O -c sort1.c
$ cd sort
$ ln -s ../sort1.o sort1.o
Add sort1.o to NEW_LIBS and NEW_FILES in link.sh.
$ cd ..
$ base/lisp.run -M base/lispinit.mem -c sort2.lsp sorttest.lsp
$ clisp-link add-module-set sort base base+sort
$ base+sort/lisp.run -M base+sort/lispinit.mem -i sort2 sorttest
> (sort10 10 '#(0.501d0 0.528d0 0.615d0 0.550d0 0.711d0
0.523d0 0.585d0 0.670d0 0.271d0 0.063d0))
#(0.063d0 0.271d0 0.501d0 0.523d0 0.528d0 0.55d0 0.585d0 0.615d0 0.67d0 0.711d0)
$ rm -r base+sort
AFFI
. To use them, (use-package "AFFI")
.
.fas
files without the need
to load function definition files at run-time and without external C or
linker support. Memory images can be created, provided that the function
libraries are opened at run-time.
Therefore, AFFI supports only primitive C types (integers 8, 16 and 32 bits wide, signed or unsigned, pointers) and defines no new types or classes. Foreign functions are not first-class objects (you can define a lambda yourself), name spaces are separate.
The AFFI does no tracking of resources. Use finalize
.
(declare-library-base keyword-base library-name)
(require-library-functions library-name [(:import {string-name}*))
(open-library base-symbol)
(clos-library base-symbol)
(with-open-library (base-symbol | library-name) {form}*)
(defflibfun function-name base-symbol offset mask result-type {argument-type}*)
(declare-library-function function-name library-name {option}*)
(flibcall function-name {argument}*)
(mlibcall function-name {argument}*)
(mem-read address result-type [offset])
(mem-write address type value [offset])
(mem-write-vector address vector [offset])
(nzero-pointer-p value)
Except for with-open-library
, declare-library-function
and mlibcall
,
all of the above are functions.
A library contains a collection of functions. The library is referred to by
a symbol referred as library-base at the AFFI level. This symbol is
created in the package AFFI
. The link between this symbol and the OS-level
library name is established by declare-library-base
. To avoid multiple
package conflicts, this and only this function requires the symbol-name to
be in the KEYWORD
package. The function returns the library-base.
A library may be opened by open-library
and closed by close-library
. An
opened library must be closed. with-open-library
is provided to
automatically close the library for you, thus it's much safer to use.
A function is contained in a library. Every function is referred to by a
symbol. A function is defined through defflibfun
or declare-library-function
by giving the function name, the library-base, an offset into the library, a
mask (or nil
) for register-based library calls, the result type and all
parameter-types. require-library-functions
loads the complete set of
functions defined in a library file. Symbols are created in the package AFFI
and imported into the current package.
flibcall
and mlibcall
call library functions. mlibcall
is a macro that does
a few cheks at macroexpansion time and allows the compiler to inline the
call, not requiring the foreign function to be defined again at load or
execution time. The use of this macro is advertised wherever possible.
mem-read
reads an arbitrary address (with offset for structure references)
and returns the given type.
mem-write
writes an arbitrary address. mem-write-vector
copies the content
of a Lisp string or unsigned-byte vector into memory.
nzero-pointer-p
tests for non-NULL
pointers in all recognized
representations (null
, unsigned-byte
and foreign-pointer
).
declare-library-base
ought to be wrapped in an eval-when (compile eval load)
form and come before any function is referenced, because the library base
symbol must be known.
open-library
tries to open the library referenced by the base symbol.
Therefore it must have been preceeded with declare-library-base
. The call
returns nil
on failure. open-library
calls nest. Every successful call must
be matched by close-library
. with-open-library
does this for you and also
allows you to specify the library by name, provided that its base has been
declared. It is recommended to use this macro and to reference the library
by name.
CLISP will not close libraries for you at program exit. [A previous version
did so but now AFFI is a module and there are no module exit functions.]
Programmers, watch affi::*libraries-alist*
.
AFFI name | Lisp equiv | C equiv | Comment |
---|---|---|---|
nil | nil | void | as a result type for functions only |
4 | (unsigned-byte 32) | unsigned long
| |
2 | (unsigned-byte 16) | unsigned short
| |
1 | (unsigned-byte 8) | unsigned char
| |
-4 | (signed-byte 32) | long
| |
-2 | (signed-byte 16) | short
| |
-1 | (signed-byte 8) | signed char
| |
0 | boolean | BOOL | as a result type for functions only |
* | opaque | void*
| |
:external | opaque | void*
| |
string | string or vector | char*
| |
:io | string or vector | char*
|
Objects of type string
are copied and passed NUL-terminated on the execution
stack. On return, a Lisp string is allocated and filled from the address
returned (unless NULL). Functions with :io
parameters are passed the address
of the Lisp string or unsigned byte vector. These are not NUL-terminated!
This is useful for functions like like read()
which do not need an array at
a constant address longer than the dynamic extent of the call (it is
dangerous to define callback functions with :io
(or string
) type
parameters). Arguments of type integer
and foreign-pointer
are always
acceptable where a string
or :io
type is specified.
To meet the design goals, predefined types and objects were used. As such,
pointers were represented as integers. Now that there is the foreign-pointer
type, both representations may be used on input. The pointer type should be
therefore considered as opaque. Use nzero-pointer-p
for NULL tests.
defflibfun
or
declare-library-function
. The former is closer to the low-level
implementation of the interface, the latter is closer to the other FFI.
defflibfun
requires the library base symbol and register mask to be
specified, declare-library-function
requires the library name and computes
the mask from the declaration of the arguments.
The value of mask is implementation-dependent. On the Amiga, it's an integer
whose hexadecimal value is the reverse of the function argument register
numbers, where d0 has number 1
and a6 number #xF
. A nil
mask is reserved for
stack-based calls (unimplemented).
The AFFI type 0
is only acceptable as a function result type and yields
either t
or nil
. The difference between *
and :external
is the following: *
uses integers, :external
uses foreign-pointer
as function result-type (except
from nil
for a NULL pointer) and refuses objects of type string
or unsigned
byte vector as input. Thus :external
provides some security on the input and
the ability to use finalize
for resource-tracking on the output side.
(declare-library-function name library-name {option}*)
option ::= | |
(:offset library-offset)
| |
| | (:arguments {(arg-name AFFI-type register)}*)
|
| | (:return-type AFFI-type)
|
register ::= | :d0 | :d1 | ... | :d7 | :a0 | ... | :a6
|
flibcall
and mlibcall
.
mlibcall
should be the preferred way of calling foreign functions (when they
are known at compile-time) as macroexpansion-time checks may be performed
and the call can be sort of inlined.
(mem-read address type offset)
can read 8, 16 and 32 bit signed or unsigned
integers (AFFI types -4
, -2
, -1
, 1
, 2
, 4
), a pointer (*
), a NUL-terminated
string (string
) or, if the type argument is of type string
or unsigned
byte vector, it can fill this vector. :external
is not an acceptable type as
no object can be created by using mem-read
.
(mem-write address type value [offset])
writes integers (AFFI type -4
, -2
,
-1
, 1
, 2
and 4
) or pointer values (type *
), but not vectors to the specified
memory address.
(mem-write-vector address vector [offset])
can write memory from the given
vector (of type string
or unsigned byte vector).
require-library-functions
will require
a file of name derived from the
library name and with type "affi"
. It may be used to import all names into
the current package or only a given subset identified by string names, using
the :import
keword (recommended use). Some definition files for standard
Amiga libraries are provided. See example 1 below.
As require-library-functions
loads a global file which you, the programmer,
may have not defined, you may consider declaring every function yourself to
be certain what the return and argument types are. See example 4 below.
The file read-fd.lsp
defines the function make-partial-fd-file
with which
the provided ".affi"
files have been prepared from the original Amiga FD
files (located in the directory FD:
). They must still be edited as the
function cannot know whether a function accepts a *
, :io
, string
or
:external
argument and because files in FD:
only contain a register
specification, not the width of integer arguments (-4
, -2
, -1
, 1
, 2
, or 4
).
eval-when
forms for declare-library-base
and
require-library-functions
and not using flibcall
, it is possible to write
code that only loads library function definition files at compile-time. See
example 1 below.
Do not rely on finalize
to free resources for you, as CLISP does not call
finalizers when it exits, use unwind-protect
.
affi1.lsp
) were
to change, the low-level part (affi.d
) should remain untouched as all it
knows are integers and foreign-pointers, no symbols. The difficulty is just
to get the library base value at run-time. Feel free to suggest enhancements
to this facility!
1. Using a predefined library function file
(use-package "AFFI")
;; SysBase is the conventional name for exec.library
;; It is only enforced by the file loaded by REQUIRE-LIBRARY-FUNCTIONS
(eval-when (compile eval load)
(declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
;; using only MLIBCALL allows not to load definitions at load-time
(eval-when (compile eval)
(require-library-functions "exec.library"
:import '("FindTask")))
(with-open-library ("exec.library")
(print (mlibcall FindTask 0)))
This file can be used in interpreted and compiled mode. Compiled, it will
have inlined the library function calls.
2. Using flibcall
(use-package "AFFI")
(eval-when (compile eval load)
(declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
;; The load situation permits the use of flibcall
(eval-when (eval compile load)
(require-library-functions "exec.library"))
(unless (open-library 'SysBase) (error "No library for SysBase"))
(flibcall (if t 'FindTask 'Debug) 0)
(close-library 'SysBase)
3. Be fully dynamic, defining library bases ourselves
(use-package "AFFI")
(eval-when (compile eval load)
(defvar mylib (declare-library-base :foobase "foo.library")))
(eval-when (eval compile load) ;eval allows mlibcall, load flibcall
(defflibfun 'foo1 mylib -30 '#xA '* 'string)
(defflibfun 'foo2 mylib -36 '#x21 0 * 4))
(defun foo (name)
(when (open-library mylib)
(list (mlibcall foo1 name) (flibcall 'foo2 name 123213))
(close-library mylib)))
4. Some sample function definitions
(defflibfun 'FindTask 'SysBase -294 #xA '* 'string)
(declare-library-function FindTask "exec.library"
(:offset -294)
(:return-type *)
(:arguments
(name string :A1)))
(declare-library-function NameFromLock "dos.library"
(:offset -402)
(:return-type 0)
(:arguments
(lock 4 :D1)
(buffer :io :D2)
(len 4 :D3)))
(eval-when (compile eval)
(defconstant GVF_LOCAL_ONLY (ash 1 9))
(defflibfun 'SetVar 'DosBase -900 #x5432 0 'string 'string -4 4))
(defun setvar (name value)
(with-open-library (DosBase)
;; length of -1 means find length of NUL-terminated-string
(mlibcall SetVar name value -1 GVF_LOCAL_ONLY)))
CLISP comes with a small yet extensible and powerful ARexx interface.
(rexx-do-command "return address()" :string t :result t)
tells you the
name of the CLISP ARexx port. The default extension for CLISP ARexx
scripts is "cl"
.
(REXX-DO-COMMAND command &key :string :result :token :io :host)
-> (RC &optional result)
, or nil
on failure
(REXX-RUN-COMMAND command &KEY :string :token)
-> t
, or nil
on failure
(REXX-SEND-COMMAND command &KEY :string :result :token :io :host)
-> arexx-msg-handle, or nil
on failure
(REXX-WAIT-SENT-COMMAND arexx-msg-handle)
-> (RC &optional result)
, or nil
on failure
(REXX-LOOP)
-> no return, use the exit-loop.cl
ARexx script to abort the loop
command may be a string denoting a command with optional arguments or a vector of strings thus denoting an ARexx function call. The first element in the vector is the function name, the others are the up to 15 arguments.
Messages may be sent to an arbitrary ARexx host, special cases are nil
(meaning "REXX"
, the default) and t
("AREXX"
for asynchronouns execution).
ARexx server mode: Like Ispell, Csh and SKsh, you can run it in server
mode by calling (rexx-loop)
. You can then only exit with the ARexx
exit-loop.cl
script.
Restrictions: Currently CLISP is not able to wait for input from several sources, e.g. both a console and ARexx, at the same time.
In CLISP 1994-01-07 or newer,
SYSTEM
package.
They operate on a VGA card.
Similar pixel graphics primitives can be used in the
xterm
package available on
ftp2.cons.org
.
This is the description of the PC/VGA graphics primitives:
(system::graph-init [width [height [colors]]])
((color-value color-keyword) ...)
which lists the available
colours and their numerical equivalents.
(system::graph-show)
(system::graph-clear [color])
(system::graph-dims)
(system::graph-dims)
returns the values w and h, then valid screen
coordinates are pairs (x,y) with 0 <= x < w and 0 <= y < h. x=0 denotes the
left edge, y=0 the top edge.
(system::graph-dot x y)
(system::graph-dot x y color)
(system::graph-box x1 y1 x2 y2 color)
(x1,y1) | (x2,y1) |
(x1,y2) | (x2,y2) |
(system::graph-line x1 y1 x2 y2 color)
(system::graph-text x y dir string color)
This specification is subject to change.
(socket-server [port-or-socket])
(socket-server-close socket-server)
(socket-server-port socket-server)
socket-server
.
(socket-wait socket-server [seconds [microseconds]])
socket-wait
blocks indefinitely.
(socket-accept socket-server [:element-type])
(socket-connect port [host] [:element-type])
(socket-stream-host socket-stream)
(socket-stream-port socket-stream)
socket-stream-host
returns nil
.
(socket-service-port "service-name")
(socket-stream-peer socket-stream)
(socket-stream-local socket-stream)
socket-stream-peer
- same information, host
name and port number, but for the local host.
On Unix, a script can be made executable by adding a first line of the form
#!interpreter [interpreter-args]
and chmod
ing the script to be executable. CLISP can be used as a script
interpreter under the following circumstances:
/usr/local/bin/clisp
, and if CLISP is actually installed elsewhere,
letting /usr/local/bin/clisp
be a symbolic link to the real CLISP.
clisp
is a shell script because a C compiler cannot be assumed to be installed
on this platform. If you have a C compiler installed, build CLISP from
source yourself; "make install
" will install clisp
as a real executable.
#!interpreter [interpreter-args]
"
is limited in length:
-Msomewhere.mem
" and "-C
") to clisp
, separate them by hard spaces
(ISO Latin-1 character 160) instead of normal spaces. (But the separator
between interpreter and interpreter-args must still be a normal
space!) CLISP will split the interpreter-args at hard spaces and at
normal spaces.
The script should contain Lisp forms, except in the #! line. The file
is normally loaded, through the function load
. Before it is loaded,
the variable *args*
is bound to a list of strings, representing the
arguments given to the Lisp script. *standard-input*
and *standard-output*
are bound, as usual, to the Unix standard input and output. *error-output*
is bound to the Unix error output. Continuable errors will be turned
to warnings. Non-continuable errors and Ctrl-C interrupts will terminate
the execution of the Lisp script with error status.
*debug-io*
and *error-output*
point to separate console windows
(thus keeping your standard console window clean from error messages)
you can use
(setq *error-output*
(setq *debug-io*
(open "CON:0/0/500/300/CLISP-Debugger/AUTO/CLOSE" :direction :io)
) )
at startup.
Bruno Haible | Michael Stoll | |||
17, rue Danton | Westerwaldweg 22 | |||
F - | 94270 Le Kremlin-Bicêtre | D - | 53424 Remagen-Oberwinter | |
France | Germany |
haible@clisp.cons.org
marcus@sysc.pdx.edu
Last modified: 13 December 1997.