ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 11.0

## 1.0 Introduction

Java in Lisp (jil) is a language for writing programs to run on the Java Virtual Machine (jvm). It uses a syntax familiar to Lisp programmers. jil programs can be generated by Lisp programs. This allows a Lisp program to migrate functionality over to a jvm.

## Loading the jil module

When you use jil, first load the jil module into Lisp by evaluating:

    (require :jil)

## 2.0 Lexical items

Java is a case sensitive language and thus jil is as well. Jil can only be loaded and run in an Allegro Common Lisp in modern mode (also known as :case-sensitive-lower mode). See case.html.

All jil source is read into the package `javatools.jil.source` (with a nickname `jvs`). This page uses only one package: the `common-lisp-user` package.

When a jil program is read, the normal Lisp reader does the work, thus everything must be valid Lisp syntax. This also means that normal Lisp reader macros are in effect (e.g. #x3ff4 or #.(+ 234 4) will work). Also the comment characters are semicolon and #| followed by |#.

At present jil is strictly an ASCII system -- it does not permit Unicode characters outside the 8-bit Ascii range to be expressed.

Identifiers in Java are more restricted than they are in Lisp. A Java identifier begins with a letter and contains letters or numbers. The underscore and dollar sign characters are considered letters. The jil programmer would be advised to follow that restriction on naming identifiers, although the only restriction jil places on identifiers is that they cannot contain a period.

## 3.0 Types

In jil all values have a type. Types are denoted by the following expressions (note again that symbols mentioned are in the jvs package or inherited from the common-lisp package).

### Primitive Types

- `byte`
- `char`
- `short`
- `int`
- `long`
- `float`
- `double`
- `boolean`
- `void`

### Reference types

- `<em>Classname</em>`

### Array types

- `(array type)` [same as `(array type *)`]
- `(array type *)`
- `(array type * ...)`

## 4.0 Files

A file containing jil code should contain zero or more import forms, an optional package form, a def-java-class form followed by a sequence of zero or more def-java-method forms. def-java-macro forms can be placed anywhere in the file.

The name of the file should be foo.jil where 'foo' is the name of the class defined in the file.

## 5.0 def-java-class

In jil, as in java, everything is class-centric. You define a class and then methods that are associated with that class. This is also how you define interfaces, which for the purposes of this function are so similar to classes, that we'll just use the term class to refer to classes and interfaces.

We give the general description of def-java-class forms and then some specific examples. But def-java-class is not a defined operator. You cannot evaluate these for at a Lisp prompt. Instead, they should be in a file which you then compile with jcomp-file. See the example in Test suite example and TicTacToe example below.

The symbol name def-java-class is also defined in the `net.jlinker` package described jlinker.html. That use, which does define an operator, has no relation to the jil module.

The form of a def-java-class is

    (def-java-class class-name (superclass superinterface ...)
          flag ...
          (field-desc ...)
          [:methods (name (arg1 ..) expr) ...]
          [:classes (name (superclass ...) [flag ...] (field-desc ...)) ... ]
    )

The class-name is an identifier (which is a Lisp symbol). You can use a fully qualified name such as `com.franz.jkf.myclass`, but you're more likely to want to set the package to "com.franz.jkf" and just use the class-name myclass in the def-java-class form. Every class you define will have one superclass and zero or more superinterfaces. If no superclass is given, then the superclass used is java.lang.Object.

flags are used to specify attributes of the class. Flags are also used to specify attributes of fields in a class and attributes of methods. The table below describes all of the flags and which flags can be used to describe classes, fields and methods:

Flag |  |  |
:abstract | class |  | method
:final | class | field | method
:interface | class |  |
:native |  |  | method
:private |  | field | method
:protected |  | field | method
:public | class | field | method
:static | Inner class only | field | method
:synchronized |  |  | method
:transient |  | field |
:volatile |  | field |

Following the zero or more flags is a list of field descriptions. The format of a field-desc is a list beginning with the field name followed optionally by a sequence of keyword value pairs.

    (field-name :type type  :initform expression :flags (flag1 ....))

The initform expression, if given, will be evaluated inside the default constructor for this class.

The table above shows the flag values valid inside this field description.

It is possible to list some of the methods of the class in the def-java-class form by putting them after a :methods specifier. This is normally not done for top level classes but it is necessary to use this syntax when defining methods for inner classes.

It is possible to define inner classes by specifying class descriptions after the :classes keyword.

Here are some sample class definitions:

    (def-java-class htest ()
        ; simple one slot public class
        :public
        ((x :type int))

       )

    (def-java-class zip (nil intx inty)
        ; interface with one slot (which must be static in an interface).
        ; by specifying nil for the superclass, we get
        ; the default (java.lang.Object)
        :public :interface
        ((teeth :type int :initform 20 :flags (:static)))
        :methods
        (brush () :void)  ; normal method
        (teeth-count () :int )

       )

## 6.0 def-java-method

This form is used to create a method that is associated with the class being defined in the same file.

    (def-java-method method-name ((arg1 type)... (argn type)) return-type
            flag ...
            <strong>[</strong>(:throws exception-class ...)<strong>]</strong>
            expr ....
    )

The set of allowable flags is given in the table above.

The body of a method is a sequence of expressions. The allowable expressions are described below. While java is a statement based language, jil is, like Lisp, an expression based language. In jil every expression returns zero or one value. The value of the last expression in the body of a method is the value returned by the method.

## 7.0 Special Symbols

A few symbols have special meaning inside a jil method.

- null - This corresponds to the java null value which is the universal reference pointer that points to no object.
- nil - This corresponds to the java false value.
- t - This corresponds to the java true value.

## 8.0 Special Forms

The special forms in Jil are:

- progn
- block
- return-from
- ref
- if
- and
- or
- handler-case
- unwind-protect
- throw
- let
- setq
- <, <=, =, >=, >
- +, *, /, -
- <<
- >>
- >>>
- logand, logior, logxor
- instanceof

### progn

    (progn expr ...)

Evaluate each expression in sequence and return the value of the last one

### block

    (block tagname expr ....)

Like progn except that this sets up a tag for use by return-from.

### return-from

    (return-from name [result])

Like return, jumps out of a block named name, returning result if supplied or `nil`.

### ref

    (ref expr slotname1 [ ... slotnameN ])

    (ref classname static-slotname [ slotname1 ... slotnameN ])

    (ref package1 ... packageN classname static-slotname [ slotname1 ... slotnameN ] )

The ref form is used to

- navigate through a sequence of objects in order to return a slot value.
- retrieve a static slot of a class and then navigate through that value.
- name a method to be called

A shorthand for this form can be used in many cases. In jil the expression `foo.bar.baz` is converted into `(ref foo bar baz)` by jil compiler. This dot convention only works when in Java you have a sequence of symbols separated by dots. For example there is no way to use the dot convention to write `(ref (myfun x) slot)`.

### if

    (if expr true-expr [ false-expr ] )

This is just like the Common Lisp if special form. In Java conditionals only test boolean values. This is not the case in jil which is more like Lisp in this regard. In jil the following values are considered true:

- the true boolean object
- a non-zero number
- a non-null instance
- an array of anything

The following things are considered false:

- the false boolean object
- a zero number
- the null instance
- a conditional expression where the predicate isn't satisfied and there is no else clause.

### and

    (and expr ....)

This is like the Common Lisp and form except that the result is always the boolean true or false value. It never returns the last value of the form.

### or

    (or expr ...)

This is like the Common Lisp or form except that the result is always the boolean true or false value. It never returns the value of any subexpression in the form.

### handler-case

    (handler-case hexpr (exception-class (var) expr ...) ...)

This is how the Java try...except is expressed in jil. While hexpr is evaluated, if an exception is raised that is a subclass of one of the exception-classes given in this form, then that exception object is bound to the var and the control continues in the body of the exception handler.

### unwind-protect

    (unwind-protect protected-expr expr1 .... exprN)

This is how the java try...finally is expressed in jil. While protected-expr is evaluated a condition handler is setup so that any attempt to throw control out of the protected-expr will result in control going instead to expr1 and the following forms. If all the forms up to and including exprN evaluate, then the throw that caused control to reach expr is continued.

### throw

    (throw expr)

The expr should evaluate to an object that is a subclass of java.lang.Exception. The program resumes execution at the innermost handler for the exception being thrown.

### let

    (let ((var <strong>[</strong> initform <strong>[</strong> type <strong>]]</strong>) ....) expr ...)

A set of local variables are bound during the evaluation of a sequence of expressions. If the initform is not given then it is assumed to be 0 (zero). If the type is not given, then it is assumed to be the type of the initform. In this case the type of a number is the most restrictive type that describes it.

### setq

    (setq place expr ... ...)

Like the Common Lisp setf this stores values not only in local variables but in slots of objects (described by ref expressions). The value of the setq expression is the value of the last expression stored.

### <, <=, =, >=, >

    (<  expr1 expr2 ...)
    (<= expr1 expr2 ...)
    (=  expr1 expr2 ...)
    (>= expr1 expr2 ...)
    (>  expr1 expr2 ...)

These are a mixture of the Common Lisp functions by the same names and the and special form. They compute a relation between numbers yet short circuit evaluation as soon as they determine that the answer is false. The return value is the boolean value true or false.

### +, *, /, -

    (+ [ expr ... ])
    (* [ expr ... ])
    (/ [ expr ... ])
    (- [ expr ... ])

These take zero or more arguments and compute the appropriate function over the argument values. The exprs are only evaluated as needed before the function is applied to them. This means that an arithmetic exception may be signaled before all of the arguments have been evaluated.

### <<

    (<< value shiftamount)

shift the value left by the given shift amount. The value should be a type that can be widened to an int or a long. The result of the shift will either be an int or a long depending on the type of the value. The low bits of the shiftamount are used to determine the number of places left the value is shifted. If an int will be shifted then the shiftamount is anded with #x1f and that value is the shift amount. If value is a long then the shiftamount is anded with #x3f. The resulting shift amount is thus always a non-negative number.

### >>

    (>> value shiftamount)

shift the value right by the given shiftamount, copying the sign bit into vacated bits. This is an arithmetic shift. See the description for << to see how the shiftamount value is modified before it is used

### >>>

    (>>> value shiftamount)

shift the value right by the given shiftamount, copying zero into vacated bits. This is a logical shift. See the description for << to see how the shiftamount value is modified before it is used.

### logand, logior, logxor

    (logand expr ...)
    (logior expr ...)
    (logxor expr ...)

perform the bitwise operation on the expressions (which must be of type int or long)

### instanceof

    (instanceof expr type)

returns true if the object that is the value of the expr is an instance of the named type. The expression expr must return a reference to an object, not a primitive type such as int. The type is not quoted.

Thus, `(instanceof x String)` tests if `x` points to a `String` object.

## 9.0 Functions

The functions, not and new.

### not

and

    (not expr)

Compute the boolean value that is the inverse of the given value, where the description of what is considered true and false is described with the if special form.

### new

    (new type expr ...)

Allocate a new object of the given type and call its constructor passing the value of the exprs as arguments.

The type is normally a symbol. It can also be an anonymous type description.

The form of an anonymous type description is

    (:class superclass (superinterface ...) [flag ...] (field-desc
    ...) [:methods method-desc] [:classes class-desc])

Essentially it looks just like a def-java-class form except that instead of naming the class you name the class and/or interfaces that the class inherits from. If the anonymous class is to inherit from only an interface and no class then that interface should be put in the superclass spot, i.e. `(:class superint () .....)`.

## 10.0 macros

Users can add macros to the jil compiler with def-java-macro. The macros cond, if*, and s+ are already defined:

### cond

    (cond  (pred-expr value-expr1 ... value-exprN) ... <strong>[</strong>(t value-expr1 .. value-exprN) <strong>]</strong>)

This is very close to the Common Lisp cond form except that one type of clause is not permitted: that is the clause where the value of the predicate is the value returned (if it is true).

### if*

    (if* pred then expr1 ... exprN <strong> [ </strong>elseif pred then expr1 .... exprN <strong>]</strong> ... <strong>[ </strong>else expr1 .... exprN <strong>] </strong>)

The if* macro from Allegro Common Lisp. This is designed to do the work of the Common Lisp if, when and unless forms and offer greater program readability.

### s+

    (s+ expr1 expr2 ... exprN)

In Java the + operator is overloaded to do string concatenation. We chose not to do this in JiL. Instead we offer the s+ macro that generates code just like the Java compiler when it determines that + must do string concatenation. Each expression can return any type of value and as long as there is an appropriate append method in the class java.lang.StringBuffer that accepts that type of value.

## 11.0 package

A jil source file can contain a package form

    (package packagename)

This form should appear before the class and any methods are defined. It specifies the package prefix for the class. Failure to include a package form in a file sets the package prefix to the empty string.

## 12.0 import

The import form specifies a class or set of classes which should be capable of being referenced without the full package qualification. There can be zero or more import forms in a jil source file.

    (import classname)
    (import packagename.*)

The first form imports just the single class, the second imports all classes in the given package (but not subpackages of the given package).

Just as in Java, there is an implicit import done of `java.lang.*` before a jil file is compiled.

## 13.0 def-java-macro

This defines a macro for use in compiling jil expressions only. The form is identical to Lisp's defmacro:

    (def-java-macro name (arg ...)  expr ...)

## 14.0 Using the jil compiler

First you must install a Java Software Development Toolkit or Java Runtime on your machine. Jil needs access to the jar file of standard Java classfiles (which define such classes as java.lang.Object). You tell jil where to find the java classfiles either by giving a non-`nil` value to *jil-classpath* or by setting the CLASSPATH environment variable. Newer java development toolkits don't require you to set CLASSPATH for doing Java development since they compute the class path based on where the java component being run is located in the filesystem. This will not work for jil programming. You need to specify a CLASSPATH or a value for *jil-classpath*.

The *jil-classpath* variable is designed to allow you to easily switch between different sets of java classfiles. If you will use only one set, you should specify a value for CLASSPATH and leave (or make) the value of *jil-classpath* `nil`.

Next you place the files comprising the jil compiler on your machine, and we suggest that they be in the jil subdirectory of the main directory in which you intend to work. Start lisp and evaluate

    (require :jil)

The jil compiler will be loaded into Lisp. Functions and variables are named by symbols in the `javatools.jil` package.

The function jcomp-file will compile a jil sourcefile into a classfile. A source file can contain multiple class definitions. The def-java-method's that follow a def-java-class are associated with that class. The output of jcomp-file is one or more class files. The names of the class files are the names of the classes defined, with the extension or type .class. Inner and anonymous classes are given names generated by the jil compiler and are written out one per file as well.

The toplevel forms permitted in a file processed by jil are:

- progn -- the arguments to the progn are treated like toplevel forms (this is mainly useful as a return from a macro)
- package
- import
- def-java-class
- def-java-method
- def-java-macro
- static -- the arguments are forms to be evaluated when the class file is loaded in.
- <anything that macro expands (via def-java-macro macros) to one of the above forms>

## 15.0 Test suite example

To run the examples, you must have a Java Software Development Toolkit or Java Runtime installed on your machine (as said in Using the jil compiler).

The jil distribution includes the jil test harness `tester.jil` and the the jil test suite `jiltest.jil`. In order to compile the test suite to a java class file start lisp and change to the directory that contains the `jil` directory as a subdirectory and do the following:

    cl-user(1): <strong>(require :jil)</strong>
    ; Fast loading /usr/local/acl/code/jil.fasl
    cl-user(2): <strong>(use-package :javatools.jil)</strong>
    t

    ;; First we must compile the test harness into a class file
    ;; since the jiltest.jil file imports it

    cl-user(3): (jcomp-file "jil/tester")

    -- Constructor building
    Class: "tester"

    -- Method compilation
    Class: "tester"
    Compiling check(int long long)void
    Compiling check(int int int)void
    Compiling check(int float float)void
    Compiling check(int double double)void
    Compiling <init>()void
    Compiling <clinit>()void
    Class: "tester"
    Writing file "jil/tester.class"
    nil

    ;; now we compile the test suite itself

    cl-user(4): (jcomp-file "jil/jiltest")

    -- Constructor building
    Class: "mactest1"
    Class: "mactest2"
    Class: "superguy"
    Class: "subguy"
    Class: "innertestfoo"
    Class: "innertestfoo$innera"
    Class: "innertestfoo$innera$ultraina"
    Class: "innertestfoo$innerb"
    Class: "innertestfoo$barintf"
    Class: "jiltest"
    Class: "blartly"

    -- Method compilation
    Class: "mactest1"
    Compiling <init>()void
    Class: "mactest2"
    Compiling <init>()void
    Class: "superguy"
    Compiling testfcn()int
    Compiling testdowncast()int
    Compiling <init>()void
    Class: "subguy"
    Compiling testfcn()int
    Compiling overloading-2()void
    Compiling randomstuff()void
    Compiling test_widen()superguy
    Compiling <init>()void
    Compiling <clinit>()void
    Class: "innertestfoo"
    Compiling <init>()void
    Compiling test_inner()void
    Compiling sum(int int)int
    Compiling diff(int int)int
    Compiling <init>(innertestfoo)void
    Compiling clonetest()void
    Class: "innertestfoo$innera"
    Compiling <init>(innertestfoo)void
    Class: "innertestfoo$innera$ultraina"
    Compiling <init>(innertestfoo$innera)void
    Class: "innertestfoo$innerb"
    Compiling <init>(innertestfoo)void
    Class: "innertestfoo$barintf"
    Class: "jiltest"
    Compiling simplemath()void
    Compiling promotions()void
    Compiling relopstarget(int int int)void
    Compiling relopscc(int int int)void
    Compiling relopstarget(float float float)void
    Compiling relopstarget(double float double)void
    Compiling andornot(int double)void
    Compiling setqs()void
    Compiling lets()void
    Compiling doexcept()int
    Compiling doexcept2()int
    Compiling excepts()void
    Compiling dofinally()int
    Compiling arraystuff()void
    Compiling methodfun(int)void
    Compiling overloading()void
    Compiling thetests()void
    Compiling shifttests()void
    Compiling logtests()void
    Compiling emptytests()void
    Compiling miscstuff(String)void
    Compiling main((array String))void
    Compiling <init>()void
    Class: "blartly"
    Compiling snort(int)void
    Compiling <init>()void
    Class: "mactest1"
    Writing file "jil/mactest1.class"
    Class: "mactest2"
    Writing file "jil/mactest2.class"
    Class: "superguy"
    Writing file "jil/superguy.class"
    Class: "subguy"
    Writing file "jil/subguy.class"
    Class: "innertestfoo"
    Writing file "jil/innertestfoo.class"
    Class: "innertestfoo$innera"
    Writing file "jil/innertestfoo$innera.class"
    Class: "innertestfoo$innera$ultraina"
    Writing file "jil/innertestfoo$innera$ultraina.class"
    Class: "innertestfoo$innerb"
    Writing file "jil/innertestfoo$innerb.class"
    Class: "innertestfoo$barintf"
    Writing file "jil/innertestfoo$barintf.class"
    Class: "jiltest"
    Writing file "jil/jiltest.class"
    Class: "blartly"
    Writing file "jil/blartly.class"
    Class: "innertestfoo$1"
    Writing file "jil/innertestfoo$1.class"
    nil
    cl-user(5)

The result of these two calls to jcomp-file are a number of class files, once for each class defined in the files (including anonymous classes). To run the test suite start a shell (or Command Prompt on Windows) and change to the jil directory. Then run the Java vm as shown below. Each test suite entry that works will print an Ok message. If it fails a message stating what was expected and returned will be printed. There should be no errors in the test suite (although errors were reported by older and buggier Java virtual machines).

    % java jiltest
    Ok 1
    Ok 2
    Ok 3
    Ok 4
    Ok 5
    Ok 6
    Ok 7
    Ok 8
    Ok 9
    Ok 10
    Ok 11
    Ok 12
    Ok 100
    Ok 101
    Ok 102
    Ok 103
    Ok 104
    Ok 105
    Ok 106
    Ok 107
    Ok 108
    Ok 200
    Ok 201
    Ok 202
    Ok 203
    Ok 204
    Ok 205
    Ok 205
    Ok 206
    Ok 207
    Ok 208
    Ok 209
    Ok 210
    Ok 211
    Ok 212
    Ok 213
    Ok 214
    Ok 215
    Ok 216
    Ok 217
    Ok 218
    Ok 219
    Ok 220
    Ok 300
    Ok 301
    Ok 302
    Ok 303
    Ok 303
    Ok 304
    Ok 305
    Ok 306
    Ok 307
    Ok 308
    Ok 400
    Ok 401
    Ok 402
    Ok 403
    Ok 404
    Ok 405
    Ok 405
    Ok 406
    Ok 407
    Ok 408
    Ok 409
    Ok 410
    Ok 411
    Ok 412
    Ok 413
    Ok 414
    Ok 415
    Ok 416
    Ok 417
    Ok 418
    Ok 419
    Ok 420
    Ok 500
    Ok 501
    Ok 502
    Ok 503
    Ok 504
    Ok 505
    Ok 505
    Ok 506
    Ok 507
    Ok 508
    Ok 509
    Ok 510
    Ok 511
    Ok 512
    Ok 513
    Ok 514
    Ok 515
    Ok 516
    Ok 517
    Ok 518
    Ok 519
    Ok 520
    Ok 600
    Ok 601
    Ok 602
    Ok 602
    Ok 603
    Ok 604
    Ok 700
    Ok 701
    Ok 702
    Ok 703
    Ok 704
    Ok 705
    Ok 706
    Ok 707
    Ok 708
    Ok 709
    Ok 800
    Ok 801
    Ok 802
    Ok 803
    Ok 900
    Ok 901
    Ok 1000
    Ok 1001
    Ok 1100
    Ok 1101
    Ok 1102
    Ok 1103
    Ok 1104
    Ok 1105
    Ok 1106
    Ok 1107
    Ok 1108
    Ok 1109
    Ok 1110
    Ok 1111
    Ok 1113
    Ok 1114
    Ok 1115
    Ok 1116
    Ok 1117
    Ok 1118
    Ok 1119
    Ok 1120
    Ok 1121
    Ok 1122
    Ok 1123
    Ok 1124
    Ok 1125
    Ok 1126
    Ok 1127
    Ok 1300
    Ok 1301
    Ok 1302
    Ok 1303
    Ok 1304
    Ok 1305
    Ok 1306
    Ok 1307
    Ok 1308
    Ok 1309
    Ok 1200
    Ok 1201
    Ok 1400
    Ok 1401
    Ok 1500
    Ok 1501
    Ok 1502
    Ok 1504
    Ok 1505
    Ok 1506
    Ok 1507
    Ok 1508
    Ok 1509
    Ok 1510
    Ok 1511
    Ok 1512
    Ok 1513
    Ok 1514
    Ok 1515
    Ok 1515
    Ok 1516
    Ok 1517
    Ok 1600
    Ok 1601
    Ok 1602
    Ok 1603
    Ok 1604
    Ok 1604
    Ok 1605
    Ok 1700
    Ok 1701
    Ok 1702
    Ok 1703
    Ok 1704
    Ok 1705
    Ok 1801
    Ok 1802
    Ok 1803
    Ok 1804
    Ok 1805
    Ok 1806
    Ok 1807
    Ok 1808
    Ok 1809
    Ok 1810
    Ok 1811
    Ok 1812
    Ok 1900
    Ok 1901
    Ok 1902
    Ok 1903
    Ok 1904
    Ok 1905
    %

## 16.0 TicTacToe example

To run the examples, you must have a Java Software Development Toolkit or Java Runtime installed on your machine (as said in Using the jil compiler).

This example shows how an applet is converted from Java syntax to jil syntax. The Java source for the applet can be found in the Java SDK if you have that installed on your machine.

The jil version of the TicTacToe program is in TicTac.jil. Assuming that the current directory is the one that contains the jil/ subdirectory, you compile the applet as follows:

    cl-user(1): (require :jil)
    ; Fast loading /usr/local/acl/code/jil.fasl
    cl-user(2): (javatools.jil:jcomp-file "jil/TicTac")

    -- Constructor building
    Class: "TicTac"

    -- Method compilation
    Class: "TicTac"
    Compiling isWon(int)void
    Compiling bestMove(int int)int
    Compiling yourMove(int)boolean
    Compiling myMove()boolean
    Compiling status()int
    Compiling init()void
    Compiling destroy()void
    Compiling paint(Graphics)void
    Compiling mouseReleased(MouseEvent)void
    Compiling mousePressed(MouseEvent)void
    Compiling mouseClicked(MouseEvent)void
    Compiling mouseEntered(MouseEvent)void
    Compiling mouseExited(MouseEvent)void
    Compiling getAppletInfo()String
    Compiling <init>()void
    Compiling <clinit>()void
    Class: "TicTac"
    Writing file "jil/TicTac.class"
    nil
    cl-user(3):

To run the demo start up a web browser viewing the file TicTac.html in the jil directory. That will cause the TicTac.class file to be loaded into the browser and started. Then start clicking on free squares to make a move.

Copyright (c) Franz Inc. Lafayette, CA., USA. All rights reserved.

ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 11.0