		     SCADALisp, Shareware Release
		    Cogent Real-Time Systems Inc.
			  September 20, 1995

Table of Contents
=================

1.  The LISP Language
    1.1  The Beginning
    1.2  Why LISP?
    1.3  LISP as an Embedded Language
    1.4  LISP as an Object Language
    1.5  Intertask Cooperation using LISP
    1.6  Graphical User Interface Services Using LISP
    1.7  Performance Anxiety
    1.8  Program Complexity
    2.  The SCADALisp Language
    2.1  Adherence to Standards
    2.2  Extensions to Most LISP Implementations
	 2.2.1  Syntax Extensions
	 2.2.1  Object Oriented Programming



1.  The LISP Language
=====================

1.1  The Beginning
==================

LISP is a programming language invented in the late 1950s primarily
for the purpose of study in artificial intelligence.  Its name is an
acronym which stands for LISt Processing.  One of the reasons for
LISP's longevity is the (surprisingly rare) identity of code and data.
An LISP data item can be interpreted as a piece of LISP code, allowing
programs to build up and pass around pieces of code as data values.
Hence the applicability of LISP in artificial intelligence.

1.2  Why LISP?
==============

The code-as-data identity in LISP has now shown itself to be
exceptionally valuable in event driven systems where a user generally
wishes to attach an arbitrary piece of code to any event, without
regard to how that event is delivered.  This has been used with
tremendous success in programs like AutoCAD and Emacs, treating mouse
actions and keystrokes as events.

Powerful window systems such as Photon and X-Windows use callback
functions when an event occurs.  It is a great benefit to a programmer
to be able to attach an arbitrary piece of code to a callback.
C-Language interfaces for systems such as these require functions with
pre-defined arguments to be compiled into the code, limiting the
run-time extensibility of the resulting program.  Partial success has
been achieved in the X-Windows environment where TCL/TK has been used
to create user interfaces primarily for existing character-based
compiled programs.  TCL represents all code as character strings,
which means that a string can be constructed which represents a valid
statement in the language.  Such strings must be parsed and
interpreted as they are encountered at runtime, making TCL a very slow
and cumbersome language for many operations.  The popularity of TCL/TK
nevertheless demonstrates the widespread need for this type of system.
LISP represents the answer to TCL's limitations, providing
pre-compilation even of code-as-data items, and complete uniformity in
the representation of callback functions and regular program code.
SCADALisp in particular is heavily optimized for speed, making its
performance comparable to compiled LISP implementations such as GNU's
GCL.

1.3  LISP as an Embedded Language
=================================

The trend in all types of commercial programs has been toward embedded
languages of one sort or another.  Graphical interaface tools such as
HyperCard and Toolbook were seen as great leaps forward due to their
use of an embedded language with special-purpose features to provide
previously unimagined verstility.  AutoCAD shipped with AutoLisp,
making it the clear winner in customizability, and the undisputed
leader in PC-based CAD packages.  Microsoft Word and Excel now embed
Visual Basic, allowing the user to define complex macros which include
support for a wide variety of windowing widgets.  There is not a
single commercial modem communication package available for the PC
which does not contain a script language.  It is doubtful whether
serious entries into many of these product areas would sell without an
embedded script language.

LISP provides a demonstrated ability as an embedded language in any of
the applications listed above.  It is so powerful and flexible that
the GNU project has now officially adopted Scheme, a dialect of LISP,
as its universal embeddable script language.

SCADALisp has been successfully embedded into an event-driven remote
modem communication package for process control, and into a graphical
shoot-em-up adventure game soon to be released by ID Software
(unfortunately, for business reasons, SCADALisp was replaced by a
slower and less complete LISP interpreter).

1.4  LISP as an Object Language
===============================

Many people don't like LISP.  Even to experienced (non-LISP)
programmers, it looks like a tangled mess of brackets with the
occasional word thrown in, in the unsuccessful attempt to keep the
brackets from getting too close together.  This initial visual lack of
appeal, combined with the paradigm shift from procedural to functional
languages make many people reticent to learn LISP.  This is not an
insurmountable problem.

When LISP interpreters read a line of code, they translate this into
an internal "pre-compiled" representation which consists of a prefix
notation evaluation tree, or a postfix notation evaluation stack.
This is typical of how multi-platform compilers generate intermediate
code before generating assembler or machine language files.  This
similarity is sufficiently obvious to compiler designers that GNU's
GCC compiler uses LISP syntax in its machine definition files which
inform the compiler of the intermediate code-to-machine code mappings
for different platforms.

In the case of compilers for languages such as C, Pascal, FORTRAN,
etc., the compiler may generate an internal representation which is
very similar to the internal representation in a LISP system.  The
implication of this is that procedural languages can be pre-compiled
into LISP code.  An extremely fast and powerful embedded script
language can be created with any procedural front end using a LISP
engine as the the underlying execution mechanism.  A user of such a
system may never know that the language engine is LISP, yet reap all
of the benefits of the engine, such as garbage collection, data
abstraction, and in the case of SCADALisp, object oriented
programming.

The SLANG language is one such implementation of a YACC grammar using
the SCADALisp engine as the execution mechanism.  It provides a
procedural language which will be largely familiar to C progammers,
and easily understood by programmers of FORTRAN, BASIC and Pascal.  It
inherits the data abstraction, data types, garbage collection and
dynamic scoping of SCADALisp with no loss in speed or versatility.

1.5  Intertask Cooperation using LISP
=====================================

As mentioned earlier, many programs use an embedded script language to
provide extensibility and customization.  Invariably these languages
are particular to the application, containing special constructs
designed to make scripts relevant to the program easier to write.
This generally means that a word processor cannot talk to a
spreadsheet which cannot talk to a communications package which cannot
talk to a database....  There are sometimes compelling reasons why a
spreadsheet needs a different language from a word processor.  By
using the same LISP execution engine for both programs, application
specific script languages can be embedded into any user program, while
still allowing these programs to communicate with one another using
the underlying LISP language.  This provides a level of cooperation
not found even in systems such as OLE or CORBA.  Historically the only
system to attempt this level of interaction is REXX, though even here
user programs generally provide only the simplest of parsers.

SCADALisp is constructed as an embeddable API library, with hooks to
allow any YACC grammar to be used in conjunction with the normal LISP
grammar.  Window system calls and QNX interprocess communication
services are built into the language, allowing any program to
immediately implement a full-featured script language and
communication facility.

1.6  Graphical User Interface Services Using LISP
=================================================

Many applications require a graphical user interface as a
semi-independent facility, where any program can transmit a simple
request to the GUI screen to change values, colors, etc.  A user
interface built in LISP, combined with the intertask cooperation
mentioned above, provides a means for any program to send a simple
text command to a LISP user interface to alter the screen in ways
limited only by the GUI implementation.  In a matter of moments a
program can take advantage of the native GUI without the overhead
imposed by linking to the GUI API.  This type of architecture is
particularly inviting in multi-tasking environments such as QNX.

SCADALisp has been used in process control applications to provide
user interface features to control systems where off-the-shelf
interface products could not provide the level of connectivity and
functionality required.

1.7  Performance Anxiety
========================

The single most daunting argument against LISP is its comparitive lack
of performance.  When LISP was introduced in the late 1950s, computers
were running an kiloHertz clocks.  Every cycle counted, and every byte
of memory was worth an ounce of gold.  While the rest of the world was
writing assmbler programs, John McCarthy (the inventor of LISP) was
writing interpreted LISP programs.  Any speed and memory comparisons
between the two were very unflattering to LISP.  As speed and memory
costs have dropped over the years, these perceptions of LISP have
remained.  This has been helped along by the LISP community itself,
who has created LISP standards, the Common LISP standard in
particular, which define such a huge and complex feature set that in
fact the resource requirements of LISP interpreters have been able to
consistently meet or exceed the abilities of the computers they were
running on.  It is not uncommon for a Common LISP implementation to
consume six megabytes of memory before the user program is even
loaded.

The situation outlined above is not necessary.  LISP is in fact a
syntactically trivial language, requiring very few parsing rules and a
relatively simple evaluator.  A quick and richly-featured LISP
implementation need not have ridiculous resource requirements.
A SCADALisp executable with over 400 built-in functions, including
object oriented extensions and interprocess communication, consumes
less than 140 KBytes on disk, and less than 300 KBytes of RAM at
runtime.  This is more than an order of magnitude less than typical
LISP systems, and far less than many commercial language packages that
provide only a fraction of the features.  The addition of window
system support naturally increases resource requirements, but still
not anywhere near what people have traditionally expected.

As computer speeds have increased, better operating systems and GUI
environments have become a reality.  GUI environments in particular
have been very greedy of CPU cycles and memory.  In fact, the CPU time
spent updating a screen in a process control GUI application far
outweighs the CPU time spent in language execution.  Tests with
SCADALisp in both QNX Windows and Photon have demonstrated that in a
control GUI application the GUI API consumes between 65% and 80% of
the time consumed by the application.  This does not include the
graphics drivers and GUI server, which can only increase these
numbers.

The only conclusion that can be reached from the above observations is
that interpreted languages no longer represent a CPU bottleneck in
graphical environments.  Even if the speed of the interpreter were 10
times slower than equivalent compiled code, a switch to compiled code
in these environments (a factor of 10 difference in execution of
non-GUI portions of the application) would provide at most an overall
application performance improvement of between 18% and 32%.  (For
those who are interested, this is similar to the sad mathematical
facts which have stopped fine-grained multiprocessing from ever
gaining wide popularity).  If certain functions absoultely must run
quickly (for example, image procesing functions), they can be written
in C or assembly and encapulated into LISP functions.

This is not to say that all applications will fare as well in
comparisons between interpreted and compiled languages.  There are
cases where a LISP program may be 2 or possibly 3 orders or magnitude
slower than a C program.  These would be applications such as
performing a convolution on an image, where register optimization can
be heavily used and single machine instruction operations are common.
Other applications, such as symbolic processing and some kinds of data
manipulation may be relatively comparable in speed between the two
systems (no more than a factor of 2 or 3 difference in favour of
compiled code).  In such an instance, though, the development cost of
the compiled application may be higher by 1 or 2 orders of magnitude.

1.8  Program Complexity
=======================

"Simple things should be simple.  Difficult things should be
possible."  We don't know where this quote comes from, but we didn't
make it up.  This is the hallmark of any good computer program.  If it
is hard to do a simple thing, it is poorly designed.  If it is
impossible to do a difficult thing, it is under-powered.  The C
language got this half right.  Difficult things are possible.  Anybody
who has tried to read in a list of words from a file, store them in
memory, sort them, and process them in sorted order (a relatively
simple task to describe), knows the annoyance of memory management,
resizing arrays, maintaining counters and pointers, and trying to work
out exactly how many levels of dereference we need for a qsort call.
In LISP, this is quite literally 15 lines of code.  Many applications
involving flow of control and the majority of data manipulation tasks
can be handled with far less effort and development time in LISP.
This, combined with interactive coding and debugging, makes LISP a far
better development environment for a wide range of tasks.  This is
particularly true for one-time code, which is typical of custom
control applications.

Having said this, there are still occasions when LISP, or any
interpreted language saves nothing.  There is no silver bullet.  There
are simply different tools for different jobs, and there are plenty of
jobs where SCADALisp does it better.  We would be the first people
kicking and screaming if anybody tried to take away our C compiler.
SCADALisp is written in C after all.  Good luck trying to write a C
compiler in LISP.

2.  The SCADALisp Language
==========================

2.1  Adherence to Standards
===========================

SCADALisp does not adhere to the Common LISP standard.  As discussed
above, this would pretty much guarantee a 2 to 6 megabyte executable
and somewhat sluggish performance.  SCADALisp introduces a number of
features which are not available in Common LISP implementations, such
as the real-time timers, which have a modifying effect on how some
things were implemented.  Wherever reasonable, SCADALisp functions
will do the same thing as Common LISP functions of the same name.
SCADALisp uses dynamic variable scoping whereas Common LISP
implementations now use lexical scoping.  There are arguments for and
against both.  Dynamic scoping runs faster as in interpreter, but is
harder to compile.  In any case, a good book on any implementation of
LISP can be very valuable in understanding SCADALisp.  The
similarities among implementations are greater than the differences.

2.2  Extensions to Most LISP Implementations
============================================

2.2.1  Syntax Extensions
========================

SCADALisp extends the LISP syntax to include literal arrays and
literal class instances.

A literal array is a list of elements surrounded by square brackets
instead of round brackets.  For example:
	'(1 2 3 4 5)
is a literal list.  We must quote it in order to stop the evaluator
from treating it as a function call.  Similarly,
	[1 2 3 4 5]
is a literal array.  This does not need to be quoted, as the LISP
evaluator does know what to do with an array, and so simply returns
it without processing.

A literal class instance consists of a class name plus a set of dotted
pairs of the form (instance-var . value), all within curly braces.
For example:
	{PhPoint (x . 10) (y . 50)}
defines a PhPoint at 10,50.  A literal instance does not have to be
quoted, as the evaluator will perform no special action.

Note that for both literal arrays and literal instances the evaluator
treats the object as a simple identity.  One effect of this is that it
is not possible to compute a value in a literal object.  For example:
	{PhPoint (x . (+ 5 6)) (y . (cos angle))}
will not create a point at 11,0.6754 but rather it will create the
LISP object:
	{PhPoint (x + 5 6) (y cos angle)}
which may or may not be what was expected.  To create an array with
computed contents, use the (array...) function.  To create an instance
with computed instance variables, you must use the (new <class>)
function and then individually set each instance variable.  A literal
instance will be constructed at read time.  Unlike most LISP code, the
class must exist when the object is read, rather than when its
containing function is executed.

Literal objects are embedded into your code.  They behave in much the
same manner as static local variables in C.  When you alter a literal
object, you are effectively changing your code.  This may have an
undesirable impact, unless your intention was to have a static object.
For example:

    lisp> (defun zero () {PhPoint (x . 0) (y . 0)})
    t
    lisp> (setq x (zero))
    {PhPoint (x . 0) (y . 0)}
    lisp> (-> x x 7)
    7
    lisp> x
    {PhPoint (x . 7) (y . 0)}
    lisp> (zero)
    {PhPoint (x . 7) (y . 0)}
    lisp>

2.2.1  Object Oriented Programming
==================================

SCADALisp implements a single inheritance object class mechanism.
This provides a means to define complex data types with named instance
variables, along with the methods to manipulate these types.  In order
to maintain the LISP syntax with object oriented extensions, it is
necessary to treat access to instance variables as functions rather
than syntactic constructs.

To create a new class:

(defclass name parent-class class-variables instance-variables)
	- The class name can be any symbol, not quoted.
	- The parent class is any class definition, or nil.
	- The class variables are not used in this implementation and
	  should be nil.
	- The instance variables are a list of (name value) pairs
	  containing the name of an instance variable followed by its
	  default value.  If there is no default value, then the
	  parentheses can be dropped and the name supplied by itself.
	  The instance variable list is not quoted.

To create a new method for a class:
	  
(defmethod class name arguments code)
	- The class can be any class definition.
	- The method name can be any symbol.
	- The argument list is the same as an argument list to (defun...)
	- The code is the same as code to (defun...)

To read an instance variable:

(@ instance variable-name)
	- The instance is an instance of a class, generated by (new...)
	- The variable-name is any symbol, not quoted.

(:@ instance variable-name)
	- The instance is an instance of a class, generated by (new...)
	- The variable-name is any expresion which evaluates to a
	  symbol, or a quoted symbol.

@variable-name
	- Inside a class method, the special variable, self, is set to
	  the instance calling the method.  As a shorthand for reading
	  an instance variable, @variable-name is equivalent to the
	  expression (@ self variable-name).

To set an instance variable:

(-> instance variable-name value)
	- The instance is an instance of a class, generated by (new...)
	- The variable-name is any symbol, not quoted.
	- The value is any expression, and will be evaluated.

(:-> instance variable-name)
	- The instance is an instance of a class, generated by (new...)
	- The variable-name is any expresion which evaluates to a
	  symbol, or a quoted symbol.
	- The value is any expression, and will be evaluated.

To call a method for an instance, you name the instance as the
function name, and the method as the first argument.  All subsequent
arguements are passed in order as arguments to the method.  For
example:

	lisp> (defclass Test nil nil ((x 5) (y 8)))
	(defclass Test nil [] [(x . 5) (y . 8)])
	lisp> (defmethod Test Area (multiplier) (* (* @x @y) multiplier))
	(defun Test@Area (self multiplier)
	       (* (* (@ self x) (@ self y)) multiplier))
	lisp> (setq inst (new Test))
	{Test (x . 5) (y . 8)}
	lisp> (inst Area 10)
	400
	lisp> 
	
Other class-related functions are briefly documented in the FUNCTIONS
document.
