The Jisp engine provides a miniature Lisp implementation using a Java applet or a command-line application. You can see Jisp running in a Java applet near the bottom of this page.
Jisp is intended to provide a subset of Common Lisp but I'm not too sure how precisely this is achieved. The program uses language features and classes from JDK1.1 and doesn't work with older compilers or runtime systems. Comments welcome. And yes it is a mildly silly name for a program, though I gather a good one for a village in Holland.
Jisp is Copyright 1998 Richard W.E. Furse. All rights reserved.
Links to this page and applet are welcome, but please let me know. Please do not make modifications to Jisp without checking with me first. I'd probably be fairly open with the code anyway as most of it was written over a weekend. And I will not be held responsible for loss or damage resulting from use of this software. It's only a toy, there's nothing deliberately wrong with it, but you never know. If you don't like this caveat, don't use the software.
Jisp is a simple Lisp interpreter written in Java. I'm vaguely curious about compiler techniques and this would provide a good vehicle.
Jisp is `light-weight' (45k at last count) and has an open design. It could be useful for teaching, particularly with web-based CBT systems.
The following constructs can be used with the system. I'm afraid I assume here that readers know their way around Lisp so I'm not giving detailed descriptions.
foo
).nil
is the empty list and is used to indicate
`false'. May also be written as ()
.-124587126
). T
is used
to indicate `true' when returning a result from a boolean
function.(atom <object>)
Returns true (T) if the
object is an atom (an atom as defined above, T or nil). Returns false
(nil) otherwise.(null <object>)
Returns true (T) if the
object is null (i.e. nil as defined above). Returns false (nil)
otherwise.(numberp <object>)
Returns true (T) if
the object is a number. Returns false (nil) otherwise.A cons is a pairing of objects, known as car and cdr.
A list is a collection of `cons' statements chained together using `cdr' and terminated with a nil.
(car <cons expression>)
Returns the
first (car) part of the cons.(cdr <cons expression>)
Returns the
second (cdr) part of the cons.(cons <object> <object>)
This can be used to construct a `cons' of objects. This can be used to
form lists.(<object> <object> ...
This declares a list. When evaluated the first item in the list will
be applied as a function to the remaining objects in the list.(list <object> <object>
...)
Makes a list of objects without evaluating them.Maths functions operate using the Java arbitrary precision maths library. Floating-point numbers and fractions are not supported at this time.
(+ <number> <number> ...)
Adds the numbers together.(- <number> <number> ...)
Subtracts the numbers from each other, starting from the left.(* <number> <number> ...)
Multiplies the numbers together.(- <number> <number> ...)
Divides the numbers into each other, starting from the left.(and <object> <object>
...)
Returns true (T) if no object passed to it is false
(i.e. nil). Returns false (nil) otherwise.(cond (<condition> <expression>)
(<condition> <expression>) ...)
Evaluates each condition in turn until one evaluates to true (i.e. not
nil) the corresponding expression is then evaluated and returned. If
no condition is true then nil is returned.(eq <object> <object>
...)
Checks if all the objects provided are equal (after
evaluation). If so then returns true (T), if not returns false
(nil). Items must be of the same type to be equal. Atoms are equal to
one another if they have the same label, numbers are equal if they
have the same value, T is considered equal to itself and nil is
considered equal to itself.(if <condition> <expression1>
<expression2>)
Evaluates the condition. If the
condition is true (i.e. not nil) then expression1 is evaluated and
returned. Otherwise expression2 is evaluated and returned.(not <object>)
Returns true (T) if the
object passed to it is false (i.e. nil). Returns false (nil)
otherwise.(or <object> <object>
...)
Returns true (T) if any object passed to it is not false
(i.e. not nil). Returns false (nil) otherwise.A list in Jisp is evaluated by evaluating all elements within the
list and then applying the first item to the others as a
function. Note that although there are many constructs of form
(...)
, many are not function applications.
A typical function application is (+ 1 2)
. Here the
atom `+' is evaluated to the addition function. Numbers are already
evaluated so nothing happens to these. The addition function is then
applied to 1 and 2, returning 3.
If we have defined a function addone
which adds one to
a number, then the call (addone (+ 1 1))
would first
evaluate the atom `addone' to return the function itself and then
evaluate the (+ 1 1)
expression to produce 2. The addone
function code will then be applied to 2 to produce 3. That was a poor
explanation: for a better one see any good book on Common Lisp.
(eval <object>)
Evaluate an
object. Normally used in conjunction with quote.(defun <function name> (<formal
parameter> <formal parameter> ...)
<function body>)
Constructs a lambda expression
using the formal parameter list of atoms and the function body. This
lambda expression is bound globally to the function name provided and
returned. In other words, defun defines a function with a particular
name. The function has a body which takes different values depending
on the actual parameters passed to the function when it is
called. These actual parameters are bound to the symbols of the formal
parameters. For instance, if we define (defun addone (x) (+ x
1))
and then evaluate (addone 2)
, Jisp will bind 2
to x, evaluate further and return the value 3. See the scope section
for a Jisp warning however.(lambda (<formal parameter> <formal
parameter> ...) <function body>)
Constructs a lambda expression using the formal parameter list of
atoms and the function body. This is similar to defun above, but the
function is not bound globaly. A simple example of an application of
a lambda function would be ((lambda (x) (+ x 1)) 2)
This
constructs a function that adds one to a number and then applies this
function to 2, returning 3. Lambda has the significant advantage that
variables are bound to it at the time lambda is used, thus if y is 4,
then (lambda (x) (+ x y))
will declare a function that
will thereafter add 4 to things, even if y changes value. I'm a big
fan of lambda and the Lambda calculus. See the scope section for a
Jisp warning however.(quote <object>)
or
'<object>
. Delays the evaluation of an
object. Evaluating the quote construct returns the object held within
it, not an evaluation of the object. Normally used in conjunction with
eval, or with atoms, when the symbol (or label) itself is wanted
rather than its bound value.The scope is a binding of atom symbols to Jisp objects. It has a `memory' so that values can be bound `locally' to a symbol and then unbound in a way that does not lose any previous value. Scope also supports `global' bindings. The global binding only provides the value for a symbol when no local binding is present. No memory is kept of previous global bindings.
Scopes are Serializable in Java terms, meaning that it will be easy to read and write the contents of a scope (including function definitions etc) from and to disc.
Bindings happen under the following conditions:
(let ((<atom> <expression>)
(<atom> <expression>) ...)
body)
Evaluates each expression in turn and binds it
locally to the symbol of the corresponding atom. Finally the body is
evaluated in the new scope (i.e. with the listed atoms bound to their
new values). Once the body has been evaluated, the scope returns to
its previous state.The current implementation has behaviour that I'm not 100% sure about: when declaring a function using defun or using let and lambda, it is possible to declare recursive functions. Within this recursive function, the reference back to the function itself will remain an atom rather than a reference to the function itself. For most purposes this is irrelevant as the atom will be evaluated to produce the function later. However there are possible problems if the symbol in use is redefined, as a call to the old function will call the new function after one iteration.
To avoid this problem, do not redefine named functions at runtime unless you're going to be extremely careful.
Jisp can be run on the command line using java
Jisp.Prompt
. Run on its own this will provide a conventional
read-eval-print loop to the user. This program has two optional
parameters, input file and output file. Thus java Jisp.Prompt
in.jisp
will run the Jisp script in.jisp and output
results to the screen. java Jisp.Prompt in.jisp out.txt
will route the output to file.
The applet should be visible at the end of this section. Click on the bottom box and you should be able to enter items to evaluated. This program has a somewhat ropey approach to working out when you want to evaluate the string in the box--essentially the system will attempt to evaluate the string any time you press enter and there is an equal number of open and close brackets in the box. Still, it's only intended as a toy for the moment.
The Jisp applet accepts a `context' parameter from the HTML page describing it: this page invokes the applet which may contain a number of Jisp expressions to be evaluated before the user prompt becomes active. This page enclosing the applet loads it using the following form:
<APPLET CODE="Jisp.JispApplet" ARCHIVE="Jisp.jar" WIDTH=600 HEIGHT=500>
<PARAM name="context" value="
(defun factorial (n) (if (eq n 0) 1 (* n (factorial (- n 1)))))
(defun church3 (f) (lambda (x) (f (f (f x)))))
">
</APPLET>
The applet presented on this page is available as a `jar' archive as well as ordinary class files. Running on older browsers the class will be picked up without use of the ARCHIVE parameter. This is slower and requires the program to be stored twice on the server.
You may have some problems running this applet though I don't know why. It runs fine in my Internet Explorer 4 browser and the HotJava browser provided with Sun's JavaPC demo package, but seems to have trouble with Internet Explorer 3 and my (old) version of appletviewer. I thought this might be due to private inner classes, but I've given them all package visibility and the problem remains. Two problems manifest themselves: the first is an access violation. The second occurs when the applet appears to be working but then refuses to evaluate expressions when enter is pressed. If you've got this far however, then it will be possible to run the program using the Jisp Prompt (above).
The author