turner@imagen.UUCP (D'arc Angel) (03/18/87)
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# ada.apr
# aiapp.apr
# contnt.apr
# expert.apr
# files.apr
# vtlisp.doc
# vtlisp.uue
# This archive created: Tue Mar 17 16:45:13 1987
# By: D'arc Angel (The Houses of the Holy)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'ada.apr'" '(3282 characters)'
if test -f 'ada.apr'
then
echo shar: "will not over-write existing file 'ada.apr'"
else
cat << \SHAR_EOF > 'ada.apr'
"AI & Ada"
April 1987 AI EXPERT magazine
Listing 1
type predicate;-- will be for rule, fact, or goal.
type predicptr is access predicate;
type predicate is
record
item: symptr;--point to list which is predicate
next: predicptr;--for next symbol in predicate
-- no value or confidence -this will be in binding for an instantiation
end record;
type binding;
type bindptr is access binding;
type binding is
record
name: symptr;--variable name bound
depth: integer;-- name+depth=standardized variable
context: integer;-- depth of binding
father:integer;
mother: integer;-- rules that gave birth to binding
ident: integer;-- depth bound to, if variable
text: predicptr;-- text+ident=variable/fact bound to,
next: bindptr;-- use chained (bucketed) hash
-- first token, link to linked list of tokens
end record;
Listing 2
function unify( uin:predicptr; duin:integer;
vin:predicptr; dvin:integer;
context,father,mother: integer) return BOOLEAN is
u,v,valu:predicptr;
du,dv,dvalue: integer;
begin
u:=uin;
v:=vin;
du:=duin;
dv:=dvin;
--CAVEAT: binding is currently treated as ADT insofar as
-- verify, unify, concerned.
-- depending on binding implementation
-- may prefer global vs. local bindings, etc. This may in turn
-- cause us to prefer slightly different versions of unify
-- for hash, use Nakamura method but with occurs check.
--CAVEAT: MY UNIFY ASSUMES RULE ENTRIES ATOMS OR VARIABLES, NOT
-- LISTS
@New_Line;Put(" entered unify");
<<doit>>
@New_Line;Put("doit u,v=");Printpred(u,du);Printpred(v,dv);
-- first if for end of the predicates encountered-
if u=NULL and v=NULL then return TRUE;
elsif u=NULL or v=NULL then return FALSE;--one but not both null;
end if;
--neither u nor v NULL
if is_var(u) then
@Put(" u variable");Put(du);
if not isbound(u,du) then --u is unbound-bind it to v
@Put(" u unbound");Put(du);
if NOoccurs(u,du,v,dv) then
value(v,dv,valu,dvalue);
install(u.item,du,context,father,mother
,dvalue,valu);
return TRUE;
--only works for binding var. to either var. or atom
-- more general binding possible with minor extension
-- don't return-check remainder of predicates
else--occurs check
return FALSE;
end if;--occurs check-bind u to v
else-- u bound- is it ok?
value(u,du,valu,dvalue);
u:=valu;
du:=dvalue;
goto doit;
end if;-- if not bound u
elsif is_var(v) then -- v variable, u is not
@Put(" v is variable, u wasnt");Put(dv);
<<dov>> if not isbound (v,dv) then--bind it to u
if NOoccurs(v,dv,u,du) then
install(v.item,dv,context,father,mother,du,u);
return TRUE;
else
return FALSE;
end if;-- occurs check bind v to u
else -- v bound as well as u
value(v,dv,valu,dvalue);
v:=valu;
dv:=dvalue;
--goto dov;Janus had pblms going to correct place-
-- else <<dov>> if is var confused it.
if is_var(v) then goto dov; end if;
end if;-- if not bound
-- neither u, v variables- must be lists or atoms
elsif u.next=NULL and then v.next=NULL then--both atoms
if u.item /= v.item then--check first tokens(symptr must equal)
return FALSE;
else
return TRUE;
end if;
end if;
-- neither variables nor atoms-lists
if unify(car(u),du,car(v),dv,context,father,mother) then
u:=u.next;
v:=v.next;
goto doit;
else
return FALSE;
end if;
end unify;
SHAR_EOF
if test 3282 -ne "`wc -c < 'ada.apr'`"
then
echo shar: "error transmitting 'ada.apr'" '(should have been 3282 characters)'
fi
fi
echo shar: "extracting 'aiapp.apr'" '(43847 characters)'
if test -f 'aiapp.apr'
then
echo shar: "will not over-write existing file 'aiapp.apr'"
else
cat << \SHAR_EOF > 'aiapp.apr'
"AI Apprentice"
April 1987 AI EXPERT magazine
(Listings to VTLISP)
VTLISP.PAS
----------
{.PW132}
{.IN+}
{.HE VTLISP.PAS Page #}
{$V-,R+ }
PROGRAM very_tiny_LISP ;
(* Copyright (c) 1987 - Knowledge Garden Inc.
473A Malden Bridge Rd.
RD #2
Nassau, NY 12123 *)
(* VT-LISP is a simple functional variation of LISP as described in the
April and May 1987 issues of AI Expert
This program has been tested using Turbo ver 3.01A on an IBM PC. It has
been run under both DOS 3.2 and Concurrent 5.0
We would be pleased to hear your comments, good or bad, or any applications
and modifications of the program. Contact us at:
AI Expert
CL Publications Inc.
500 Howard St.
San Francisco, CA 94105
or on the AI Expert BBS on Compuserv.
Our id is BillandBev Thompson ,[76703,4324].
You can also contact us on BIX, our id is bbt.
Bill and Bev Thompson *)
CONST
back_space = ^H ;
tab = ^I ;
eof_mark = ^Z ;
quote_char = #39 ;
left_arrow = #75 ;
return = ^M ;
bell = ^G ;
TYPE
counter = 0 .. maxint ;
222244444 string80 = string[80] ;
string132 = string[132] ;
string255 = string[255] ;
text_file = text ;
char_set = SET OF char ;
node_type = (cons_node,symbol,number,free_node) ;
s_expr = ^node ;
node = RECORD
in_use : boolean ;
CASE tag : node_type OF
cons_node : (car_ptr : s_expr ;
cdr_ptr : s_expr) ;
symbol : (string_data : string80) ;
number : (num_data : real) ;
free_node : (next_free : s_expr ;
block_cnt : counter) ;
END ;
(* node is the basic allocation unit for lists. The fields are used as
follows:
in_use - in_use = false tells the garbage collector that this node
is available for re-use.
tag - which kind of node this is.
cons_node - cons_nodes consist of two pointers. one to the head (first item)
the other to the rest of the list. They are the "glue" which
holds the list together. The list (A B C) would be stored as
------- -------- --------
| .| . |-----> | .| . |------> | .| . |---> NIL
--|----- --|------ --|-----
| | |
V V V
A B C
The boxes are the cons nodes, the first part of the box
holds the car pointer, then second contains the cdr pointer.
symbol - holds string values, we don't actually use the entire 80
characters in most cases.
number - used for storage of numbers. All numbers are implemented as
reals. This is inefficient, but relatively easy in Turbo
Pascal.
free_node - the garbage collector gathers all unused nodes and puts
them on a free list. It also compacts the free space into
contiguous blocks. next_free points to the next free block.
block_cnt contains a count of the number of contiguous 8 byte free
blocks which follow this one.
Note: we allocate a new node for each atom, instead of a pointer to an
existing string in the heap. This slows down comparisons,
because you have to compare strings instead of pointers, but
speeds up allocation. We've tried it both ways and there seems
to be no effect on small programs, but if you decide to
expand this program you should take a long hard look at all
of the allocation routines and improve them. *)
VAR
total_free : real ;
result,fn,free,initial_heap,saved_list,pending : s_expr ;
token : string80 ;
line,saved_line : string255 ;
delim_set : char_set ;
paren_level : counter ;
(* Variables - These are the important global variables:
total_free - a count of the total amount of free mameory on the
free list.
result - the S-expression returned by eval.
fn - S-expression read by get_expression.
free - a linked list of free nodes. Memory is allocated from
from here if possible before getting memory from
the heap. This list is built by the garbage collector.
inital_heap - a pointer to the bottom of the heap
saved_list - a list of all nodes which must absolutely not be
reclaimed by the garbage collector.
pending - a utility S-expression used by LETREC
token - the returned by get_token. This really shouldn't
be a global. It's just sloppy programming.
line - the input buffer for S-expressions
delim_set - set of token delimeters
paren_level - the count of unmatched parentheses, used while reading
S-expressions *)
(* ----------------------------------------------------------------------
Utility Routines
---------------------------------------------------------------------- *)
FUNCTION open(VAR f : text_file ; f_name : string80) : boolean ;
(* open a file - returns true if the file exists and was opened properly
f - file pointer
f_name - external name of the file *)
BEGIN
assign(f,f_name) ;
(*$I- *)
reset(f) ;
(*$I+ *)
open := (ioresult = 0) ;
END ; (* open *)
FUNCTION is_console(VAR f : text_file) : boolean ;
(* return true if f is open on the system console
for details of fibs and fib_ptrs see the Turbo Pascal ver 3.0 reference
manual chapter 20. This should work under CP/M-86 or 80, but we haven't
tried it. *)
TYPE
fib = ARRAY [0 .. 75] OF byte ;
VAR
fib_ptr : ^fib ;
dev_type : byte ;
BEGIN
fib_ptr := addr(f) ;
dev_type := fib_ptr^[2] AND $07 ;
is_console := (dev_type = 1) OR (dev_type = 2) ;
END ; (* is_console *)
PROCEDURE strip_leading_blanks(VAR s : string80) ;
BEGIN
IF length(s) > 0
THEN
IF (s[1] = ' ') OR (s[1] = tab)
THEN
BEGIN
delete(s,1,1) ;
strip_leading_blanks(s) ;
END ;
END ; (* strip_leading_blanks *)
PROCEDURE strip_trailing_blanks(VAR s : string80) ;
BEGIN
IF length(s) > 0
THEN
IF (s[length(s)] = ' ') OR (s[length(s)] = tab)
THEN
BEGIN
delete(s,length(s),1) ;
strip_trailing_blanks(s) ;
END ;
END ; (* strip_trailing_blanks *)
FUNCTION toupper(s : string80) : string80 ;
(* returns s converted to upper case *)
VAR
i : byte ;
BEGIN
IF length(s) > 0
THEN
FOR i := 1 TO length(s) DO
s[i] := upcase(s[i]) ;
toupper := s ;
END ; (* toupper *)
FUNCTION toreal(s : string255) : real ;
(* Converts "s" to a real - ignores non-numeric characters. *)
VAR
num : real ;
code : integer ;
BEGIN
strip_trailing_blanks(s) ;
strip_leading_blanks(s) ;
IF s = ''
THEN code := -1
ELSE IF length(s) = 1
THEN
IF s[1] IN ['0' .. '9']
THEN val(s,num,code)
ELSE code := -1
ELSE val(s,num,code) ;
IF code = 0
THEN toreal := num
ELSE toreal := 0 ;
END ; (* toreal *)
FUNCTION tointeger(s : string80) : integer ;
VAR
num : real ;
code : integer ;
BEGIN
strip_trailing_blanks(s) ;
strip_leading_blanks(s) ;
val(s,num,code) ;
IF code = 0
THEN
IF (num < -32768.0) OR (num > 32767.0)
THEN tointeger := 0
ELSE tointeger := trunc(num)
ELSE tointeger := 0 ;
END ; (* tointeger *)
FUNCTION is_number(s : string255) : boolean ;
VAR
num : real ;
code : integer ;
BEGIN
strip_trailing_blanks(s) ;
strip_leading_blanks(s) ;
IF s = ''
THEN code := -1
ELSE IF length(s) = 1
THEN
IF S[1] IN ['0' ..'9']
THEN code := 0
ELSE code := -1
ELSE val(s,num,code) ;
is_number := (code = 0) ;
END ; (* is_number *)
FUNCTION cardinal(i : integer) : real ;
VAR
r : real ;
BEGIN
r := i ;
IF r < 0
THEN r := r + 65536.0 ;
cardinal := r ;
END ; (* cardinal *)
FUNCTION tag_value(list : s_expr) : node_type ;
(* returns the value of the tag for a node. *)
BEGIN
IF list = NIL
THEN tag_value := free_node
ELSE tag_value := list^.tag ;
END ; (* tag_value *)
FUNCTION car(list : s_expr) : s_expr ;
(* returns a pointer to the first item in the list.
If the list is empty, it returns NIL. *)
BEGIN
IF list = NIL
THEN car := NIL
ELSE IF tag_value(list) = cons_node
THEN car := list^.car_ptr
ELSE car := NIL ;
END ; (* car *)
FUNCTION cdr(list : s_expr) : s_expr ;
(* returns a pointer to a list starting at the second item in the list.
Note - cdr( (a b c) ) points to the list (b c), but
cdr( ((a b) c d) ) points to the list (c d) . *)
BEGIN
IF list = NIL
THEN cdr := NIL
ELSE
CASE tag_value(list) OF
cons_node : cdr := list^.cdr_ptr ;
free_node : cdr := list^.next_free ;
ELSE cdr := NIL ;
END ;
END ; (* cdr *)
FUNCTION atom(p : s_expr) : boolean ;
(* Return true if p is a symbolic or numeric atom, otherwise
it returns false *)
BEGIN
IF p = NIL
THEN atom := false
ELSE IF tag_value(p) IN [number,symbol]
THEN atom := true
ELSE atom := false ;
END ; (* atom *)
FUNCTION allocation_size(x : integer) : integer ;
(* Turbo 3.0 allocates memory in 8 byte blocks, this routine calculates the
actual number of bytes returned for a request of x bytes. *)
BEGIN
allocation_size := (((x - 1) SHR 3) + 1) SHL 3 ;
END ; (* allocation_size *)
FUNCTION node_size : counter ;
(* calculates the size of a cons node. *)
BEGIN
node_size := 2 * sizeof(s_expr) + sizeof(boolean) + sizeof(node_type) ;
END ; (* node_size *)
FUNCTION normalize(pt : s_expr) : s_expr ;
(* returns a normalized pointer. Pointers are 32 bit addresses. The first
16 bits contain the segment number and the second 16 bits contain the
offset within the segment. Normalized pointers have offsets in the range
$0 to $F (0 .. 15) *)
VAR
pt_seg,pt_ofs : integer ;
BEGIN
pt_seg := seg(pt^) + (ofs(pt^) DIV 16) ;
pt_ofs := ofs(pt^) MOD 16 ;
normalize := ptr(pt_seg,pt_ofs) ;
END ; (* normalize *)
FUNCTION string_val(list : s_expr) : string80 ;
(* returns the string pointed to by list. If list points to a number
node, it returns a string representing that number *)
TYPE
real_rec = RECORD
CASE boolean OF
true : (p1 : real) ;
false : (p2 : ARRAY [0 ..5] OF byte) ;
END ;
VAR
s : string80 ;
p : real_rec ;
PROCEDURE strip_trailing_zeros(VAR ss : string80) ;
BEGIN
IF ss <> ''
THEN
IF ss[length(ss)] = '0'
THEN
BEGIN
delete(ss,length(ss),1) ;
strip_trailing_zeros(ss) ;
END ;
END ; (* strip_trailing_zeros *)
BEGIN
IF list = NIL
THEN string_val := ''
ELSE IF list^.tag = symbol
THEN string_val := list^.string_data
ELSE IF list^.tag = number
THEN
WITH list^ DO
BEGIN
p.p1 := abs(frac(num_data)) ;
IF p.p2[0] = 0
THEN str(num_data : 20 : 0,s)
ELSE IF p.p2[0] < 112
THEN str(num_data,s)
ELSE
BEGIN
str(num_data : 20 : 10,s) ;
strip_trailing_zeros(s) ;
END ;
strip_leading_blanks(s) ;
string_val := s ;
END
ELSE string_val := '' ;
END ; (* string_val *)
FUNCTION num_val(list : s_expr) : real ;
(* returns the number pointed to by list. If list points to a string,
it returns the numerical value of the string. *)
BEGIN
IF list = NIL
THEN num_val := 0.0
ELSE IF list^.tag = number
THEN num_val := list^.num_data
ELSE IF list^.tag = symbol
THEN num_val := toreal(list^.string_data)
ELSE num_val := 0.0 ;
END ; (* num_val *)
PROCEDURE get_memory(VAR p : s_expr ; size : counter) ;
(* On exit p contains a pointer to a block of allocation_size(size) bytes.
If possible this routine tries to get memory from the free list before
requesting it from the heap *)
VAR
blks : counter ;
allocated : boolean ;
PROCEDURE get_from_free(VAR list : s_expr) ;
(* Try and get need memory from the free list. This routine uses a
first-fit algorithm to get the space. It takes the first free block it
finds with enough storage. If the free block has more storage than was
requested, the block is shrunk by the requested amount. *)
BEGIN
IF list <> NIL
THEN
IF list^.block_cnt >= (blks - 1)
THEN
BEGIN
p := normalize(ptr(seg(list^),ofs(list^) +
(list^.block_cnt - blks + 1) * 8)) ;
IF list^.block_cnt = blks - 1
THEN list := list^.next_free
ELSE list^.block_cnt := list^.block_cnt - blks ;
--
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail: Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101
UUCP: ...{decvax,ucbvax}!decwrl!imagen!turner AT&T: (408) 986-9400turner@imagen.UUCP (D'arc Angel) (03/18/87)
allocated := true ;
total_free := total_free - (blks * 8.0) ;
END
ELSE get_from_free(list^.next_free) ;
END ; (* get_from_free *)
BEGIN
blks := ((size - 1) DIV 8) + 1 ;
allocated := false ;
get_from_free(free) ;
IF NOT allocated
THEN getmem(p,blks * 8) ;
END ; (* get_memory *)
FUNCTION alloc_str(s : string80) : s_expr ;
(* Allocate storage for a string and return a pointer to the new node.
This routine only allocates enough storage for the actual number of
characters in the string plus one for the length. Because of this,
concatenating anything to the end of a string stored in a symbol node
will lead to disaster. Copy the string to a new string do the
concatenation and then allocate a new node. *)
VAR
pt : s_expr ;
BEGIN
get_memory(pt,allocation_size(sizeof(node_type) + sizeof(boolean) +
length(s) + 1)) ;
pt^.tag := symbol ;
pt^.string_data := s ;
alloc_str := pt ;
END ; (* alloc_str *)
FUNCTION alloc_num(r : real) : s_expr ;
(* Allocate storage for a number and return a pointer to the new node.
All numbers are stored as reals. This isn't efficient, but it is
easy. *)
VAR
pt : s_expr ;
BEGIN
get_memory(pt,allocation_size(sizeof(node_type) + sizeof(boolean) +
sizeof(real))) ;
pt^.tag := number ;
pt^.num_data := r ;
alloc_num := pt ;
END ; (* alloc_num *)
FUNCTION cons(new_node,list : s_expr) : s_expr ;
(* Construct a list. This routine allocates storage for a new cons node.
new_node points to the new car of the list. The cdr pointer of the
new node points to list. This routine adds the new cons node to the
beginning of the list and returns a pointer to it. The list described
in the comments at the beginning of the program could be constructed
as cons(alloc_str('A'),cons(alloc_str('B'),cons(alloc_str('C'),NIL))). *)
VAR
p : s_expr ;
BEGIN
get_memory(p,allocation_size(node_size)) ;
p^.tag := cons_node ;
p^.car_ptr := new_node ;
p^.cdr_ptr := list ;
cons := p ;
END ; (* cons *)
FUNCTION eq(item1,item2 : s_expr) : boolean ;
(* test the equality of two atoms, if item1 and item2 are not atoms
it returns false *)
BEGIN
IF (item1 = NIL) AND (item2 = NIL)
THEN eq := true
ELSE IF (tag_value(item1) IN [number,symbol]) AND
(tag_value(item2) IN [number,symbol])
THEN eq := (string_val(item1) = string_val(item2))
ELSE eq := false ;
END ; (* eq *)
FUNCTION lt(item1,item2 : s_expr) : boolean ;
(* tests if item1 < item2, if item1 and item2 are not atoms
it returns false *)
BEGIN
IF (item1 = NIL) AND (item2 = NIL)
THEN lt := false
ELSE IF (tag_value(item1) IN [number,symbol]) AND
(tag_value(item2) IN [number,symbol])
THEN lt := (string_val(item1) < string_val(item2))
ELSE lt := false ;
END ; (* lt *)
FUNCTION gt(item1,item2 : s_expr) : boolean ;
(* tests if item1 > item2, if item1 and item2 are not atoms
it returns false *)
BEGIN
IF (item1 = NIL) AND (item2 = NIL)
THEN gt := false
ELSE IF (tag_value(item1) IN [number,symbol]) AND
(tag_value(item2) IN [number,symbol])
THEN gt := (string_val(item1) > string_val(item2))
ELSE gt := false ;
END ; (* gt *)
FUNCTION add(item1,item2 : s_expr) : s_expr ;
(* add the values of two atoms, if item1 and item2 are not atoms
it returns 0 *)
VAR
r1,r2 : real ;
BEGIN
IF tag_value(item1) = number
THEN r1 := num_val(item1)
ELSE r1 := toreal(string_val(item1)) ;
IF tag_value(item2) = number
THEN r2 := num_val(item2)
ELSE r2 := toreal(string_val(item2)) ;
add := alloc_num(r1 + r2) ;
END ; (* add *)
FUNCTION sub(item1,item2 : s_expr) : s_expr ;
(* finds the difference between the values of two atoms,
if item1 and item2 are not atoms it returns 0 *)
VAR
r1,r2 : real ;
BEGIN
IF tag_value(item1) = number
THEN r1 := num_val(item1)
ELSE r1 := toreal(string_val(item1)) ;
IF tag_value(item2) = number
THEN r2 := num_val(item2)
ELSE r2 := toreal(string_val(item2)) ;
sub := alloc_num(r1 - r2) ;
END ; (* sub *)
FUNCTION mul(item1,item2 : s_expr) : s_expr ;
(* finds the product of the values of two atoms,
if item1 and item2 are not atoms it returns 0 *)
VAR
r1,r2 : real ;
BEGIN
IF tag_value(item1) = number
THEN r1 := num_val(item1)
ELSE r1 := toreal(string_val(item1)) ;
IF tag_value(item2) = number
THEN r2 := num_val(item2)
ELSE r2 := toreal(string_val(item2)) ;
mul := alloc_num(r1 * r2) ;
END ; (* mul *)
FUNCTION div_f(item1,item2 : s_expr) : s_expr ;
(* divides item1 by item2,
if item1 and item2 are not atoms it returns 0 *)
VAR
r1,r2 : real ;
BEGIN
IF tag_value(item1) = number
THEN r1 := num_val(item1)
ELSE r1 := toreal(string_val(item1)) ;
IF tag_value(item2) = number
THEN r2 := num_val(item2)
ELSE r2 := toreal(string_val(item2)) ;
IF abs(r2) <= 1.0E-20
THEN div_f := alloc_num(0.0)
ELSE div_f := alloc_num(r1 / r2) ;
END ; (* div_f *)
FUNCTION mod_f(item1,item2 : s_expr) : s_expr ;
(* finds the remainder of item1 divided by item2,
if item1 and item2 are not atoms it returns 0 *)
VAR
r1,r2 : integer ;
BEGIN
r1 := tointeger(string_val(item1)) ;
r2 := tointeger(string_val(item2)) ;
mod_f := alloc_num(r1 MOD r2) ;
END ; (* mod_f *)
FUNCTION member(p,list : s_expr) : boolean ;
(* returns true if p points to a member of list *)
BEGIN
IF list = NIL
THEN member := false
ELSE IF eq(p,car(list))
THEN member := true
ELSE member := member(p,cdr(list)) ;
END ; (* member *)
FUNCTION locate(p,list1,list2 : s_expr) : s_expr ;
(* finds p on list1 and returns a pointer to the corresponding
element of list2 *)
BEGIN
IF list1 = NIL
THEN locate := NIL
ELSE IF eq(p,car(list1))
THEN locate := car(list2)
ELSE locate := locate(p,cdr(list1),cdr(list2)) ;
END ; (* locate *)
FUNCTION assoc(p,list1,list2 : s_expr) : s_expr ;
(* search each sublist of list1 for p. If found, return pointer to
corresponding element of list2 *)
BEGIN
IF list1 = NIL
THEN assoc := NIL
ELSE IF member(p,car(list1))
THEN assoc := locate(p,car(list1),car(list2))
ELSE assoc := assoc(p,cdr(list1),cdr(list2)) ;
END ; (* assoc *)
FUNCTION tf_node(t : boolean) : s_expr ;
(* allocates T or F nodes for boolean expressions *)
BEGIN
IF t
THEN tf_node := alloc_str('T')
ELSE tf_node := alloc_str('F') ;
END ; (* tf_node *)
FUNCTION rplaca(VAR list : s_expr ; item : s_expr) : s_expr ;
(* replace the car of list with item, return a pointer to the new list *)
BEGIN
IF list <> NIL
THEN
IF tag_value(list) <> cons_node
THEN list := item
ELSE list^.car_ptr := item ;
rplaca := list ;
END ; (* rplaca *)
PROCEDURE collect_garbage ;
(* This routine is specific to Turbo Pascal Ver 3.01
It depends upon the fact that Turbo allocates memory in 8 byte blocks
on the PC. If you recompile this program on another system be very
careful with this routine.
Garbage collection proceeds in three phases:
unmark - free all memory between the initial_heap^ and the current
top of the heap.
mark_mem - mark everything on the saved_list as being in ues.
release - gather all unmarked blocks and put them on the free list.
The collector displays a '*' on the screen to let you know it is
operating. *)
FUNCTION lower(p1,p2 : s_expr) : boolean ;
(* returns true if p1 points to a lower memory address than p2 *)
BEGIN
p1 := normalize(p1) ;
p2 := normalize(p2) ;
lower := (cardinal(seg(p1^)) < cardinal(seg(p2^))) OR
((seg(p1^) = seg(p2^)) AND
(cardinal(ofs(p1^)) < cardinal(ofs(p2^)))) ;
END ; (* lower *)
PROCEDURE mark_mem(list : s_expr) ;
(* Mark the blocks on list as being in use. Since a node may be on several
lists at one time, if it is already marked we don't continue processing
the cdr of the list. *)
BEGIN
IF list <> NIL
THEN
BEGIN
IF NOT list^.in_use
THEN
BEGIN
list^.in_use := true ;
IF list^.tag = cons_node
THEN
BEGIN
mark_mem(car(list)) ;
mark_mem(cdr(list)) ;
END ;
END ;
END ;
END ; (* mark_mem *)
PROCEDURE unmark_mem ;
(* Go through memory from initial_heap^ to HeapPtr^ and mark each node
as not in use. The tricky part here is updating the pointer p to point
to the next cell. *)
VAR
p : s_expr ;
string_base,node_allocation,number_allocation : integer ;
BEGIN
string_base := sizeof(node_type) + sizeof(boolean) ;
p := normalize(initial_heap) ;
node_allocation := allocation_size(node_size) ;
number_allocation := allocation_size(sizeof(node_type) + sizeof(boolean) +
sizeof(real)) ;
WHILE lower(p,HeapPtr) DO
BEGIN
p^.in_use := false ;
CASE p^.tag OF
cons_node : p := normalize(ptr(seg(p^),ofs(p^) + node_allocation)) ;
free_node : p := normalize(ptr(seg(p^),ofs(p^) + (p^.block_cnt + 1) * 8)) ;
number : p := normalize(ptr(seg(p^),ofs(p^) + number_allocation)) ;
symbol : p := normalize(ptr(seg(p^),
ofs(p^) +
allocation_size(string_base +
length(p^.string_data) + 1))) ;
END ;
END ;
END ; (* unmark_mem *)
PROCEDURE release_mem ;
(* This procedure does the actual collection and compaction of nodes.
This is the slow phase of garbage collection because of all the pointer
manipulation. *)
VAR
heap_top : s_expr ;
string_base,node_allocation,string_allocation,block_allocation,
number_allocation : integer ;
PROCEDURE free_memory(pt : s_expr ; size : counter) ;
(* return size bytes pointed to by pt to the free list. If pt points to
a block next to the car of the free list combine it with the top
free node. total_free keeps track of the total number of free bytes. *)
VAR
blks : counter ;
BEGIN
blks := ((size - 1) DIV 8) + 1 ;
pt^.tag := free_node ;
IF normalize(ptr(seg(pt^),ofs(pt^) + 8 * blks)) = free
THEN
BEGIN
pt^.next_free := free^.next_free ;
pt^.block_cnt := free^.block_cnt + blks ;
free := pt ;
END
ELSE IF normalize(ptr(seg(free^),ofs(free^) + 8 * (free^.block_cnt + 1))) =
normalize(pt)
THEN free^.block_cnt := free^.block_cnt + blks
ELSE
BEGIN
pt^.next_free := free ;
pt^.block_cnt := blks - 1 ;
free := pt ;
END ;
total_free := total_free + (blks * 8.0) ;
END ; (* free_memory *)
PROCEDURE do_release ;
(* This routine sweeps through memory and checks for nodes with
in_use = false. *)
VAR
p : s_expr ;
BEGIN
p := normalize(initial_heap) ;
WHILE lower(p,heap_top) DO
CASE p^.tag OF
cons_node : BEGIN
IF NOT p^.in_use
THEN free_memory(p,node_size) ;
p := normalize(ptr(seg(p^),ofs(p^) + node_allocation)) ;
END ;
free_node : BEGIN
block_allocation := (p^.block_cnt + 1) * 8 ;
free_memory(p,block_allocation) ;
p := normalize(ptr(seg(p^),ofs(p^) + block_allocation)) ;
END ;
number : BEGIN
IF NOT p^.in_use
THEN free_memory(p,number_allocation) ;
p := normalize(ptr(seg(p^),ofs(p^) + number_allocation)) ;
END ;
symbol : BEGIN
string_allocation := allocation_size(string_base +
length(p^.string_data) + 1) ;
IF NOT p^.in_use
THEN free_memory(p,string_base + length(p^.string_data)
+ 1) ;
p := normalize(ptr(seg(p^),ofs(p^) + string_allocation)) ;
END ;
END ;
END ; (* do_release *)
BEGIN
free := NIL ;
total_free := 0.0 ;
heap_top := HeapPtr ;
string_base := sizeof(node_type) + sizeof(boolean) ;
node_allocation := allocation_size(node_size) ;
number_allocation := allocation_size(sizeof(node_type) + sizeof(boolean) +
sizeof(real)) ;
do_release ;
END ; (* release_mem *)
BEGIN
write('*') ;
unmark_mem ;
mark_mem(saved_list) ;
release_mem ;
write(back_space) ;
clreol ;
END ; (* collect_garbage *)
PROCEDURE test_memory ;
(* This routine activates the garbage collector, if the the total available
memory (free_list + heap) is less than a specified amount. Lowering the
minimum causes garbage collection to be called less often, but if you
make it too small you may not have enough room left for recursion or any
temporary lists you need. Using 10000 is probably being overly
cautious. *)
BEGIN
IF (memavail * 16.0) + total_free < 10000
THEN collect_garbage ;
END ; (* test_memory *)
PROCEDURE wait ;
(* Just like it says. It waits for the user to press a key before
continuing. *)
VAR
ch : char ;
BEGIN
writeln ;
writeln ;
write('Press any key to continue. ') ;
read(kbd,ch) ;
write(return) ;
clreol ;
END ; (* wait *)
(* ------------------------------------------------------------------------
End of utility routines
------------------------------------------------------------------------ *)
PROCEDURE read_kbd(VAR s : string80) ;
(* Read a line from the keyboard. The number of unmatched parentheses are
printed along with the prompt *)
BEGIN
IF paren_level > 0
THEN write(paren_level,'>')
ELSE write('-> ') ;
readln(s) ;
END ; (* read_kbd *)
PROCEDURE read_from_file(VAR f : text_file) ;
(* Read a line from file f and store it in the global variable line.
It ignores blank lines and when the end of file is reached an
eof_mark is returned. *)
PROCEDURE read_a_line ;
BEGIN
(*$I- *)
readln(f,line) ;
(*$I+ *)
IF ioresult <> 0
THEN line := eof_mark
ELSE IF eof(f)
THEN line := concat(line,eof_mark) ;
END ; (* read_a_line *)
BEGIN
line := '' ;
IF is_console(f)
THEN read_kbd(line)
ELSE read_a_line ;
saved_line := line ;
END ; (* read_from_file *)
PROCEDURE get_token(VAR t_line : string255 ; VAR token : string80) ;
(* Get a token from t_line. A token is a string of text surrounded by
blanks or a delimeter. Comments begin with ; and extend to the
end of the line *)
PROCEDURE get_word ;
VAR
done : boolean ;
cn : integer ;
len : byte ;
BEGIN
cn := 1 ;
len := length(t_line) ;
done := false ;
WHILE NOT done DO
IF cn > len
THEN done := true
ELSE IF t_line[cn] IN delim_set
THEN done := true
ELSE cn := cn + 1 ;
token := copy(t_line,1,cn-1) ;
delete(t_line,1,cn-1) ;
END ; (* get_word *)
PROCEDURE comment ;
BEGIN
t_line := '' ;
get_token(t_line,token) ;
END ; (* comment *)
PROCEDURE get_number ;
PROCEDURE get_digits ;
BEGIN
WHILE is_number(copy(t_line,1,1))
BEGIN
token := concat(token,t_line[1]) ;
delete(t_line,1,1) ;
END ;
END ; (* get_digits *)
PROCEDURE get_exponent ;
BEGIN
delete(t_line,1,1) ;
IF length(t_line) > 0
THEN
BEGIN
IF t_line[1] IN ['+','-']
THEN
BEGIN
token := concat(token,'E',t_line[1]) ;
delete(t_line,1,1) ;
END
ELSE token := concat(token,'E+') ;
get_digits ;
END
ELSE token := concat(token,'E+00') ;
END ; (* get_exponent *)
BEGIN
get_digits ;
IF length(t_line) > 0
THEN
IF t_line[1] = '.'
THEN
IF is_number(copy(t_line,2,1))
THEN
BEGIN
token := concat(token,t_line[1]) ;
delete(t_line,1,1) ;
get_digits ;
IF toupper(copy(t_line,1,1)) = 'E'
THEN get_exponent ;
END ;
END ; (* get_number *)
PROCEDURE check_number ;
VAR
sgn : char ;
BEGIN
sgn := t_line[1] ;
delete(t_line,1,1) ;
IF length(t_line) > 0
THEN
IF t_line[1] IN ['0' .. '9']
THEN
BEGIN
get_number ;
token := concat(sgn,token) ;
END
ELSE token := sgn
ELSE token := sgn ;
END ; (* check_number *)
BEGIN
strip_leading_blanks(t_line) ;
token := '' ;
IF length(t_line) > 0
THEN
BEGIN
IF t_line[1] = ';'
THEN comment
ELSE IF t_line[1] IN delim_set
THEN
BEGIN
token := t_line[1] ;
delete(t_line,1,1) ;
END
ELSE IF t_line[1] IN ['+','-']
THEN check_number
ELSE IF t_line[1] IN ['0' .. '9']
THEN get_number
ELSE get_word ;
END ;
END ; (* get_token *)
PROCEDURE scan(VAR f : text_file ; VAR token : string80) ;
(* Scan repeatedly calls get_token to retreive tokens. When the
end of a line has been reached, read_from_file is called to
get a new line. *)
BEGIN
IF length(line) > 0
THEN
BEGIN
get_token(line,token) ;
IF token = ''
--
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail: Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101
UUCP: ...{decvax,ucbvax}!decwrl!imagen!turner AT&T: (408) 986-9400turner@imagen.UUCP (D'arc Angel) (03/18/87)
THEN scan(f,token) ;
END
ELSE
BEGIN
read_from_file(f) ;
scan(f,token) ;
END ;
END ; (* scan *)
PROCEDURE error(error_msg : string80) ;
BEGIN
writeln ;
writeln(error_msg) ;
wait ;
END ; (* error *)
FUNCTION get_expression_list(VAR f : text_file) : s_expr ; FORWARD ;
FUNCTION get_expression(VAR f : text_file) : s_expr ;
(* read an expression from f. This routine and get_expression_list
work together to form a small recursive descent compiler for
S-expressions. It follows the definition fo an S-expression
from the article. It adds a quote to numbers and strings beginning with
a ' mark *)
BEGIN
IF token = '('
THEN
BEGIN
scan(f,token) ;
paren_level := paren_level + 1 ;
get_expression := get_expression_list(f) ;
IF token <> ')'
THEN error('Missing '')''') ;
END
ELSE IF token = quote_char
THEN
BEGIN
scan(f,token) ;
get_expression := cons(alloc_str('QUOTE'),cons(get_expression(f),NIL)) ;
END
ELSE IF toupper(token) = 'NIL'
THEN get_expression := NIL
ELSE IF is_number(token)
THEN get_expression := cons(alloc_str('QUOTE'),
cons(alloc_num(toreal(token)),NIL))
ELSE get_expression := alloc_str(token) ;
END ; (* get_expression *)
FUNCTION get_expression_list (* VAR f : text_file) : s_expr *) ;
(* read an S-expression list or dotted pair *)
VAR
p : s_expr ;
BEGIN
p := get_expression(f) ;
scan(f,token) ;
IF token = '.'
THEN
BEGIN
scan(f,token) ;
get_expression_list := cons(p,get_expression(f)) ;
scan(f,token) ;
END
ELSE IF token = ')'
THEN
BEGIN
paren_level := paren_level - 1 ;
get_expression_list := cons(p,NIL) ;
END
ELSE get_expression_list := cons(p,get_expression_list(f)) ;
END ; (* get_expression_list *)
PROCEDURE print_expression(l : s_expr) ;
(* recursively traverses the list and prints its elements. This is
not a pretty printer, so the lists may look a bit messy. This routine
tries to print the minimum possible number of parentheses. *)
PROCEDURE print_list(list : s_expr) ;
VAR
p : s_expr ;
BEGIN
IF list <> NIL
THEN
CASE list^.tag OF
number,
symbol : write(string_val(list),' ') ;
cons_node : BEGIN
write('(') ;
p := list ;
WHILE tag_value(p) = cons_node DO
BEGIN
print_list(car(p)) ;
p := cdr(p) ;
END ;
IF p <> NIL
THEN
BEGIN
write('. ') ;
print_list(p) ;
END ;
write(') ') ;
END ;
END ;
END ; (* print_list *)
BEGIN
IF l = NIL
THEN write('nil ')
ELSE print_list(l) ;
END ; (* print_expression *)
FUNCTION eval(expr_list,name_list,value_list : s_expr) : s_expr ;
(* The main evaluation routine. This routine is explained in the articles.
expr_list contains the S-expression to be evaluated. name_list is the
list of active variable names. value_list is the list of corresponding
values. expr_list,name_list and value_list are attached to saved_list
at the start of the routine so that if garbage collection takes place
they won't be reclaimed. They are removed at the end of this routine. *)
VAR
f_name : string80 ;
FUNCTION vars(list : s_expr) : s_expr ;
(* make a list of variables from list *)
BEGIN
IF list = NIL
THEN vars := NIL
ELSE vars := cons(car(car(list)),vars(cdr(list))) ;
END ; (* vars *)
FUNCTION exprs(list : s_expr) : s_expr ;
(* make a list of expressions *)
BEGIN
IF list = NIL
THEN exprs := NIL
ELSE exprs := cons(car(cdr(car(list))),exprs(cdr(list))) ;
END ; (* exprs *)
FUNCTION eval_list(list,name,value : s_expr) : s_expr ;
(* evaluate a list, one item at a time. It does this by calling eval
for each element of list *)
BEGIN
IF list = NIL
THEN eval_list := NIL
ELSE eval_list := cons(eval(car(list),name,value),
eval_list(cdr(list),name,value)) ;
END ; (* eval_list *)
FUNCTION eval_if : s_expr ;
BEGIN
IF string_val(eval(car(cdr(expr_list)),name_list,value_list)) = 'T'
THEN eval_if := eval(car(cdr(cdr(expr_list))),name_list,value_list)
ELSE eval_if := eval(car(cdr(cdr(cdr(expr_list)))),name_list,
value_list)
END ; (* eval_if *)
FUNCTION eval_let : s_expr ;
VAR
y,z : s_expr ;
BEGIN
y := vars(cdr(cdr(expr_list))) ;
z := eval_list(exprs(cdr(cdr(expr_list))),name_list,value_list) ;
eval_let := eval(car(cdr(expr_list)),cons(y,name_list),
cons(z,value_list)) ;
END ; (* eval_let *)
FUNCTION eval_letrec : s_expr ;
VAR
v,y,z : s_expr ;
BEGIN
v := cons(cons(pending,NIL),value_list) ;
y := vars(cdr(cdr(expr_list))) ;
z := eval_list(exprs(cdr(cdr(expr_list))),cons(y,name_list),v) ;
eval_letrec := eval(car(cdr(expr_list)),cons(y,name_list),
rplaca(v,z)) ;
END ; (* eval_letrec *)
FUNCTION eval_read : s_expr ;
(* read an expression from a file. The file must end in ".LSP".
That's because we were too lazy to implement strings. The expression
read from the file is evaluated. *)
VAR
f : text_file ;
file_name : string80 ;
old_line,old_saved_line : string255 ;
BEGIN
file_name := string_val(eval(car(cdr(expr_list)),name_list,value_list)) ;
IF pos('.',file_name) = 0
THEN file_name := concat(file_name,'.LSP') ;
IF open(f,file_name)
THEN
BEGIN
old_line := line ;
old_saved_line := saved_line ;
line := '' ;
scan(f,token) ;
eval_read := eval(get_expression(f),name_list,value_list) ;
close(f) ;
line := old_line ;
saved_line := old_saved_line ;
END
ELSE
BEGIN
error(concat('Unable to read ',file_name)) ;
eval_read := NIL ;
END ;
END ; (* eval_read *)
FUNCTION eval_f_call : s_expr ;
(* evaluate a function call *)
VAR
c,z : s_expr ;
BEGIN
c := eval(car(expr_list),name_list,value_list) ;
z := eval_list(cdr(expr_list),name_list,value_list) ;
eval_f_call := eval(cdr(car(c)),cons(car(car(c)),car(cdr(c))),
cons(z,cdr(cdr(c)))) ;
END ; (* eval_f_call *)
BEGIN
saved_list := cons(expr_list,cons(name_list,cons(value_list,saved_list))) ;
test_memory ;
IF expr_list = NIL
THEN eval := NIL
ELSE IF atom(expr_list)
THEN eval := assoc(expr_list,name_list,value_list)
ELSE
BEGIN
f_name := toupper(string_val(car(expr_list))) ;
IF f_name = 'QUOTE'
THEN eval := car(cdr(expr_list))
ELSE IF f_name = 'CAR'
THEN eval := car(eval(car(cdr(expr_list)),name_list,value_list))
ELSE IF f_name = 'CDR'
THEN eval := cdr(eval(car(cdr(expr_list)),name_list,value_list))
ELSE IF f_name = 'ATOM'
THEN eval := tf_node(atom(eval(car(cdr(expr_list)),name_list,
value_list)))
ELSE IF f_name = 'CONS'
THEN eval := cons(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF f_name = 'EQ'
THEN eval := tf_node(eq(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list)))
ELSE IF f_name = 'LT'
THEN eval := tf_node(lt(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list)))
ELSE IF f_name = 'GT'
THEN eval := tf_node(gt(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list)))
ELSE IF f_name = 'NEQ'
THEN eval := tf_node(NOT eq(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,
value_list)))
ELSE IF (f_name = '+') OR (f_name = 'ADD')
THEN eval := add(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF (f_name = '-') OR (f_name = 'SUB')
THEN eval := sub(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF (f_name = '*') OR (f_name = 'MUL')
THEN eval := mul(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF (f_name = '/') OR (f_name = 'DIV')
THEN eval := div_f(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF f_name = 'MOD'
THEN eval := mod_f(eval(car(cdr(expr_list)),name_list,value_list),
eval(car(cdr(cdr(expr_list))),name_list,value_list))
ELSE IF f_name = 'IF'
THEN eval := eval_if
ELSE IF f_name = 'LAMBDA'
THEN eval := cons(cons(car(cdr(expr_list)),car(cdr(cdr(expr_list)))),
cons(name_list,value_list))
ELSE IF f_name = 'LET'
THEN eval := eval_let
ELSE IF f_name = 'LETREC'
THEN eval := eval_letrec
ELSE IF f_name = 'EXIT'
THEN halt(0)
ELSE IF f_name = 'READ'
THEN eval := eval_read
ELSE eval := eval_f_call ;
END ;
saved_list := cdr(cdr(cdr(saved_list))) ;
END ; (* eval *)
PROCEDURE initialize ;
BEGIN
line := '' ;
saved_line := '' ;
delim_set := ['.','(',')',' ',eof_mark,quote_char,';'] ;
total_free := 0.0 ;
paren_level := 0 ;
free := NIL ;
mark(initial_heap) ;
pending := alloc_str('#PENDING') ;
saved_list := cons(pending,NIL) ;
clrscr ;
writeln('VT-LISP - Copyright 1987 [c] Knowledge Garden Inc.') ;
END ; (* initialize *)
BEGIN
initialize ;
REPEAT
scan(input,token) ;
fn := get_expression(input) ;
result := eval(fn,NIL,NIL) ;
print_expression(result) ;
writeln ;
UNTIL false ;
END.
DIFF.LSP
--------
;
; Diff - symbolic diferentiation - From Henderson - Functional Programming
; enter S-expressions such as (* x c) and returns its derivative
;
(letrec (diff '(+ x c))
(diff (lambda (e)
(if (atom e)
(if (eq e 'x) 1 0)
(if (eq (car e) '+)
(let (sum (diff p1) (diff p2))
(p1 (car (cdr e)))
(p2 (car (cdr (cdr e)))))
(if (eq (car e) '*)
(let (sum (prod p1 (diff p2))
(prod (diff p1) p2))
(p1 (car (cdr e)))
(p2 (car (cdr (cdr e)))))
'error)))))
(sum (lambda (u v)
(cons '+ (cons u (cons v nil)))))
(prod (lambda (u v)
(cons '* (cons u (cons v nil))))))
LAST.LSP
--------
;
; last - find the last element of a list
;
(letrec (last '(a b c d e))
(last (lambda (x)
(if (eq (cdr x) nil) x
(last (cdr x))))))
APPEND.LSP
----------
;
; Append one list to another
; Usage (append expr1 expr2) - change the lists in the letrec statement
;
(letrec (append '(a b c) '(d e f g h i j k l m n o p))
(append (lambda (x y)
(if (eq x nil) y
(cons (car x) (append (cdr x) y))))))
------------------------------------------------------------------------
S-expression ::- atom | '(' expression-list ')'
atom ::- text-string | number
expression-list ::- S-expression | S-expression '.' S-expression |
S-expression expression-list
Figure 1
The definition of S-expressions. "::-" means "is defined as" and "|"
means "OR".
__________________________________________________________________________
Variable
x
Constants
(QUOTE s)
's
Arithmetic expressions
(ADD expr1 expr2) (+ expr1 expr2)
(SUB expr1 expr2) (- expr1 expr2)
(MUL expr1 expr2) (* expr1 expr2)
(DIV expr1 expr2) (/ expr1 expr2)
(MOD expr1 expr2)
Comparisons
(EQ expr1 expr2)
(LEQ expr1 expr2)
(GEQ expr1 expr2)
(NEQ expr1 expr2)
S-expression operations
(CONS expr1 expr2)
(CAR expr)
(CDR expr)
(ATOM expr)
Conditional expression
(IF expr1 expr2 expr3)
Return to DOS
(EXIT)
Definition expressions
(LAMBDA (x1 x2 x3 ....) expr)
(LET expr (x1.expr1) (x2.expr2) .......)
(LETREC expr (x1.expr1) (x2.expr2) ......)
Function Call
(expr expr1 expr2 expr3 ...)
Figure 2
VT-LISP statements.
x's represent variables, expr's represent S-expressions.
SHAR_EOF
if test 43847 -ne "`wc -c < 'aiapp.apr'`"
then
echo shar: "error transmitting 'aiapp.apr'" '(should have been 43847 characters)'
fi
fi
echo shar: "extracting 'contnt.apr'" '(1573 characters)'
if test -f 'contnt.apr'
then
echo shar: "will not over-write existing file 'contnt.apr'"
else
cat << \SHAR_EOF > 'contnt.apr'
Table of Contents
AI EXPERT Magazine
April 1987
Theme: Conventional Languages in AI
ARTICLES
Conventional Languages & Expert Systems
by Leslie DeGroff
It has become imperative for yesterday's development efforts to
fit in with today's Knowledge Based Systems (KBS). Here we look
at five key ingredients for successfully mixing conventional
programming environments and AI shell systems.
AI & Ada
by Louis Baker
While LISP may be the language of choice for the development of
artifical intelligence systems, there are reasons for selecting
Ada.
C on the Horizon
by Jon Roland
If one HAS to use C and its environment for the final stage of a
commercial product development, consider prototyping in LISP,
PROLOG, or another AI tool first.
Learning AI on Video
by Ashley Grayson
Let's look closely at three video training packages. Each
is presented from a different type of organization: a training
company, a computer hardware vendor, and a professional book
publisher.
DEPARTMENTS
Brain Waves
"Real-Time Expert Systems in the Information Age"
by Robert L. Moore
AI Insider
by Susan Shepard
Expert's Toolbox
by Marc Rettig
AI Apprentice
by Beverly and Bill Thompson
In Practice
by Harvey Newquist
Book Store
Software Reviews:
Objective C
SHAR_EOF
if test 1573 -ne "`wc -c < 'contnt.apr'`"
then
echo shar: "error transmitting 'contnt.apr'" '(should have been 1573 characters)'
fi
fi
echo shar: "extracting 'expert.apr'" '(5504 characters)'
if test -f 'expert.apr'
then
echo shar: "will not over-write existing file 'expert.apr'"
else
cat << \SHAR_EOF > 'expert.apr'
"Expert's Toolbox"
April 1987 AI EXPERT magazine
LISTING 1 - GPS in Prolog
/* If the STARTSTATE satisfies the GOAL then no actions need be
taken. This is the base case of GPS's recursion. */
gps(STARTSTATE, GOAL, STARTSTATE, []) :- satisfy(STARTSTATE, GOAL), !.
/* Otherwise, work through the algorithm given in pseudocode in
the body of the article. This is a four place relation, meaning
that starting in the STARTSTATE and trying to achieve the GOAL,
gps prescribes performing the ACTS, which will place you in the
ENDSTATE. */
gps(STARTSTATE, GOAL, ENDSTATE, ACTS) :-
majordiff(STARTSTATE, GOAL, DIFF),
suitableact(DIFF, ACT),
prereqs(ACT, PREREQS),
achieve(STARTSTATE, PREREQS, READYSTATE, PREACTS),
result(READYSTATE, ACT, AFTERSTATE),
gps(AFTERSTATE, GOAL, ENDSTATE, POSTACTS),
append(PREACTS, [ACT | POSTACTS], ACTS).
/* This achieves a list of prerequisites PREREQS starting from a
STARTSTATE, using actions PREACTS and ending in ENDSTATE.
It does so by calling gps on each prerequisite in turn, and
appending the actions together. */
/* Base case: if no prerequisites, then no actions are required. */
achieve(STARTSTATE, [], STARTSTATE, []).
/* Recursive case. Save the acts prescribed by gps in FIRSTACTS,
and the state resulting from the action in MIDSTATE. */
achieve(STARTSTATE, [PREREQ1 | PREREQS], ENDSTATE, ACTS) :-
gps(STARTSTATE, PREREQ1, MIDSTATE, FIRSTACTS),
achieve(MIDSTATE, PREREQS, ENDSTATE, RESTACTS),
append(FIRSTACTS, RESTACTS, ACTS).
/* Well known definition of append. */
append([], L, L).
append([A|X], Y, [A|Z]) :- append(X, Y, Z).
_______________________________
Listing 2 - Domain dependent knowledge for trip planning.
/* The geographic model consists of individual "places", which the
program thinks of as point-like, and "regions", which are areas
containing places. In the axioms below, regions are any of the
place names which have something in them; places are all the place names
which have nothing in them. Thus, metmuseum and sanfrancisco are places,
the village and Boston are regions. Regions are organized hierarchically by
containment. We record that the Village is in New York City, which is in
the northeast, which is in the US.
States are simply places - namely, the place where the "robot" is now.
Goals may be either places or regions, where the robot wishes to end up.
Differences are recorded as two regions containing the starting state and
the goal, at the hightest level, together with a thrid region containing
them both. For example, if the state is Astor Place, and the goal is
Berkeley, then the difference is the triple [northeast, bayarea, usa],
since Astor Place is in the north-east, Berkeley is in the Bay area, and
the next level up in the hierarchy is the US, which doesn't distinguish
between the two. Acts are a list of the form [motiontype, startingplace,
endingplace]; for example, [fly, kennedy, sfairport]. */
/* Basic geography. */
in(courant, village).
in(bottomline, village).
in(astorpl, village).
in(sheridansq, village).
in(pennstn, midtown).
in(metmuseum, uppereast).
in(guggenheim, uppereast).
--
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail: Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101
UUCP: ...{decvax,ucbvax}!decwrl!imagen!turner AT&T: (408) 986-9400turner@imagen.UUCP (D'arc Angel) (03/18/87)
in(yhma92, uppereast).
in(stn86, uppereast).
in(kennedy, queens).
in(village, nyc).
in(midtown,nyc).
in(uppereast,nyc).
in(queens, nyc).
in(widener, harvard).
in(harvardcoop, harvard).
in(harvardsq, harvard).
in(finearts, fenway).
in(fenwaypk, fenway).
in(harvard, boston).
in(fenway,boston).
in(soutstn, boston).
in(nyc, northeast).
in(boston, northeast).
in(sanfrancisco, bayarea).
in(sfairport, bayarea).
in(berkeley, bayarea).
in(marincounty, bayarea).
in(bayarea,usa).
in(northeast,usa).
/* Definition for satisfy: GOAL is satisfied if GOAL contains the STATE. */
satisfy(STATE, GOAL) :- contains(GOAL, STATE).
/* "contains" is the transitive closure of "in". */
contains(A, A).
contains(A, B) :- in(B,C), contains(A,C).
/* The major difference between START and GOAL is two regions or places
STREG and GOALREG, containing START and GOAL respectively, which are
both in COMMONCONTAINER. */
majordiff(START, GOAL, [STREG, GOALREG, COMMONCONTAINER]) :-
contains(STREG, START),
contains(GOALREG, GOAL),
in(STREG, COMMONCONTAINER),
in(GOALREG, COMMONCONTAINER), !.
/* The kind of act necessary to cross an object CONT depends on the
size of CONT. The act must start and end from recognized terminals
(for instance, a subway ride must start and end at a subway station). */
suitableact([STREG, ENDREG, CONTAINER], [ACT, STPL, ENDPL]) :-
crossact(CONTAINER, ACT),
terminal(ACT, STREG, STPL),
terminal(ACT, ENDREG, ENDPL).
/* How to cross different regions. */
crossact(usa,fly).
crossact(northeast, train).
crossact(bayarea, subway).
crossact(nyc, subway).
crossact(boston,subway).
crossact(village, walk).
crossact(uppereast, walk).
crossact(harvard,walk).
crossact(fenway,walk).
/* Transportation terminals. */
terminal(walk, X, X).
terminal(subway, village, astorpl).
terminal(subway, midtown, pennstn).
terminal(subway, queens, kennedy).
terminal(subway, harvard, harvardsq).
terminal(subway, fenway, finearts).
terminal(subway, southstn, southstn).
terminal(subway, X, X) :- in(X, bayarea).
terminal(train, nyc, pennstn).
terminal(train, boston, southstn).
terminal(fly, northeast, kennedy).
terminal(fly, bayarea, sfairport).
/* Definitions for prereqs and result. */
prereqs([MOVE, A,B], [A]).
result(A, [MOVE, A, B], B).
SHAR_EOF
if test 5504 -ne "`wc -c < 'expert.apr'`"
then
echo shar: "error transmitting 'expert.apr'" '(should have been 5504 characters)'
fi
fi
echo shar: "extracting 'files.apr'" '(820 characters)'
if test -f 'files.apr'
then
echo shar: "will not over-write existing file 'files.apr'"
else
cat << \SHAR_EOF > 'files.apr'
Articles and Departments that have
Additional On-Line Files
AI EXPERT
March 1987
"Intelligent Data Bases"
(Note: Contents page is in file CONTNT.MAR)
ARTICLES RELEVANT FILES
-------- --------------
April Table of Contents CONTNT.APR
AI & Ada ADA.APR
by Louis Baker
DEPARTMENTS
Expert's Toolbox EXPERT.APR
by Marc Rettig
AI Apprentice AIAPP.APR
VTLISP.COM
VTLISP.DOC
SHAR_EOF
if test 820 -ne "`wc -c < 'files.apr'`"
then
echo shar: "error transmitting 'files.apr'" '(should have been 820 characters)'
fi
fi
echo shar: "extracting 'vtlisp.doc'" '(3802 characters)'
if test -f 'vtlisp.doc'
then
echo shar: "will not over-write existing file 'vtlisp.doc'"
else
cat << \SHAR_EOF > 'vtlisp.doc'
VT-LISP - Very Tiny LISP
VT-LISP is a simple functional LISP interpreter provided with full
source code to encourage experimentation with LISP and functional
languages.
Startup
1. Boot the system.
2. Insert the disk containing VTLISP.COM in Drive A:
3. If the DOS prompt is not A>, type A: and press the ENTER key to switch
to drive A:.
4. Type VTLISP and press RETURN. VTLISP should respond with its heading
and a '-> ' prompt.
Entering S-expressions.
VT-LISP accepts S-expressions, evaluates them and prints the result of
the evaluation. You enter an S-expression by typing it directly from the
keyboard. As you enter S-expressions, the prompt may change to a number
followed by '>'. The number represents the number of unmatched
parentheses. For example:
VT-LISP - Copyright 1987 [c] Knowledge Garden Inc.
-> (cons 'a '(b c))
(a b c )
-> (letrec (append '(a b c) '(d e f))
1> (append (lambda (x y)
3> (if (eq x nil) y
4> (cons (car x) (append (cdr x) y))))))
(a b c d e f )
->(read 'b:append) ; read and evaluate the file b:append.lsp
Terminating VT-LISP
1. To exit VT-LISP, type :
(exit) .
at the '-> ' prompt. Don't forget the period.
VT-LISP Grammar
The following BNF describes the syntax of S-expressions
S-expression ::- atom | '(' expression-list ')'
atom ::- text-string | number
expression-list ::- S-expression | S-expression '.' S-expression |
S-expression expression-list
VT-LISP expressions
Variable
x - upper or lower case identifier
Constants
(QUOTE s)
's
Arithmetic expressions
(ADD expr1 expr2) (+ expr1 expr2)
(SUB expr1 expr2) (- expr1 expr2)
(MUL expr1 expr2) (* expr1 expr2)
(DIV expr1 expr2) (/ expr1 expr2)
(MOD expr1 expr2)
Comparisons
(EQ expr1 expr2) - returns T if expr1 evaluates to the same thing as expr2
(LT expr1 expr2) - returns T if expr1 < expr2
(GT expr1 expr2) - returns T if expr1 > expr2
(NEQ expr1 expr2) - returns T if expr1 <> expr2
S-expression operations
(CONS expr1 expr2) - returns dottted pair (expr1.expr2)
(CAR expr) - returns first element of expr
(CDR expr) - returne list formed by removing 1st element from expr
(ATOM expr) - returns T if expr evaluates to an atom
Conditional expression
(IF expr1 expr2 expr3) - If expr1 returns T, evaluate expr2, otherwise
evaluate expr3
Return to DOS
(EXIT)
Read an expression from a file
(read expr) - read an expression from file expr. expr must evaluate to an
atom which is represents a file name. File names must end
in ".LSP". Example: (read 'b:append)
Definition expressions
(LAMBDA (x1 x2 x3 ....) expr) - define a lambda expression
(LET expr (x1.expr1) (x2.expr2) .......) - define a block. x1 etc. are
local variables. expr1, expr2 etc are their deinitions
(LETREC expr (x1.expr1) (x2.expr2) ......) - define a recursive block
Function Call
(expr expr1 expr2 expr3 ...) - evaluate the function expr, using
parameters expr1 etc. Parameters are
evaluated before applying the function.
Comments
; - comments begin with ";". Anything following ";" on a line is ignored
by the evaluator
Good luck with VT-LISP. We would be very interested in hearing of
your experiments, enhancements or even (gasp) bugs that you may find.
Please write to us with your comments or questions.
Bill and Bev Thompson
C/O AI Expert Magazine
500 Howard St.
San Francisco, CA 94105
or on the AI Expert BBS on Compuserv. Our id is BillandBev Thompson,
[76703,4324]. You can also contact us on BIX, our id is bbt.
Bill and Bev Thompson
SHAR_EOF
if test 3802 -ne "`wc -c < 'vtlisp.doc'`"
then
echo shar: "error transmitting 'vtlisp.doc'" '(should have been 3802 characters)'
fi
fi
echo shar: "extracting 'vtlisp.uue'" '(39353 characters)'
if test -f 'vtlisp.uue'
then
echo shar: "will not over-write existing file 'vtlisp.uue'"
else
cat << \SHAR_EOF > 'vtlisp.uue'
begin 664 vtlisp.com
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
M,\#K#.@.`#8B=`XS/B`""L!U!XO!B]Z+U\,ZP78%D8?>
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
--
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail: Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101
UUCP: ...{decvax,ucbvax}!decwrl!imagen!turner AT&T: (408) 986-9400turner@imagen.UUCP (D'arc Angel) (03/18/87)
M`+D``+H!`.@PU(A&#.D``(I&##+D"\"+Y5W""0!5B^Q5Z0``Q$8(C,)24#/`
M,]);6>AOVE#$1@2,PE)0,\`STEM9Z%[:62/!"\!U`^D2`+@``+D``+H!`.C?
MTXA&#.F:`+D+`.CATTS$1@B,PE)0Z(CV4.C]V+@"`.@)V;@!`.@#V>C3V5"Y
M"P#HO--,Q$8$C,)24.AC]E#HV-BX`@#HY-BX`0#HWMCHKME9(\$+P'4#Z3@`
MN;(`Z([3@^Q1Q$8(C,)24.BQ^+FR`.A[TX/L4<1&!(S"4E#HGOCH4-:Y``"Z
M`0#H5-.(1@SI#P"X``"Y``"Z`0#H0M.(1@SI``"*1@PRY`O`B^5=P@D`58OL
M5>D``,1&"(S"4E`SP#/26UGH@=E0Q$8$C,)24#/`,]);6>APV5DCP0O`=0/I
M$@"X``"Y``"Z`0#H\=*(1@SIF@"Y"P#H\]),Q$8(C,)24.B:]5#H#]BX`@#H
M&]BX`0#H%=CHY=A0N0L`Z,[23,1&!(S"4E#H=?50Z.K7N`(`Z/;7N`$`Z/#7
MZ,#862/!"\!U`^DX`+FR`.B@TH/L4<1&"(S"4E#HP_>YL@#HC=*#[%'$1@2,
MPE)0Z+#WZ%;5N0``N@$`Z&;2B$8,Z0\`N```N0``N@$`Z%32B$8,Z0``BD8,
M,N0+P(OE7<()`%6+[%7I``"#[`RY"P#H/]),Q$8(C,)24.CF]#T"`'0#Z1X`
MC7[X%E>Y$`#H(=*#[`;$1@B,PE)0Z/SXZ-/;Z2P`C7[X%E>Y%`'H`]*#[`:Y
ML@#H^M&#[%'$1@B,PE)0Z!WWL?_H5-3H`O+HI-NY"P#HW-%,Q$8$C,)24.B#
M]#T"`'0#Z1X`C7[R%E>Y$`#HOM&#[`;$1@2,PE)0Z)GXZ'#;Z2P`C7[R%E>Y
M%`'HH-&#[`:YL@#HE]&#[%'$1@2,PE)0Z+KVL?_H\=/HG_'H0=NY%`#H>=&#
M[`2-?O@6Z!';C7[R%N@*V^@ZV^@V^XE&#(E6#ND``,1&#(S"B^5=P@P`58OL
M5>D``(/L#+D+`.@^T4S$1@B,PE)0Z.7S/0(`=`/I'@"-?O@65[D0`.@@T8/L
M!L1&"(S"4E#H^_?HTMKI+`"-?O@65[D4`>@"T8/L!KFR`.CYT(/L4<1&"(S"
M4E#H'/:Q_^A3T^@!\>BCVKD+`.C;T$S$1@2,PE)0Z(+S/0(`=`/I'@"-?O(6
M5[D0`.B]T(/L!L1&!(S"4E#HF/?H;]KI+`"-?O(65[D4`>B?T(/L!KFR`.B6
MT(/L4<1&!(S"4E#HN?6Q_^CPTNB>\.A`VKD4`.AXT(/L!(U^^!;H$-J-?O(6
MZ`G:Z%3:Z#7ZB48,B58.Z0``Q$8,C,*+Y5W"#`!5B^Q5Z0``@^P,N0L`Z#W0
M3,1&"(S"4E#HY/(]`@!T`^D>`(U^^!97N1``Z!_0@^P&Q$8(C,)24.CZ]NC1
MV>DL`(U^^!97N10!Z`'0@^P&N;(`Z/C/@^Q1Q$8(C,)24.@;];'_Z%+2Z`#P
MZ*+9N0L`Z-K/3,1&!(S"4E#H@?(]`@!T`^D>`(U^\A97N1``Z+S/@^P&Q$8$
MC,)24.B7]NANV>DL`(U^\A97N10!Z)[/@^P&N;(`Z)7/@^Q1Q$8$C,)24.BX
M]+'_Z._1Z)WOZ#_9N10`Z'?/@^P$C7[X%N@/V8U^\A;H"-GH8MGH-/F)1@R)
M5@[I``#$1@R,PHOE7<(,`%6+[%7I``"#[`RY"P#H/,],Q$8(C,)24.CC\3T"
M`'0#Z1X`C7[X%E>Y$`#H'L^#[`;$1@B,PE)0Z/GUZ-#8Z2P`C7[X%E>Y%`'H
M`,^#[`:YL@#H]\Z#[%'$1@B,PE)0Z!KTL?_H4='H_^[HH=BY"P#HV<Y,Q$8$
MC,)24.B`\3T"`'0#Z1X`C7[R%E>Y$`#HN\Z#[`;$1@2,PE)0Z);UZ&W8Z2P`
MC7[R%E>Y%`'HG<Z#[`:YL@#HE,Z#[%'$1@2,PE)0Z+?SL?_H[M#HG.[H/MB-
M?O(6Z!?8Z*?8Z"#8/I)D".4\Z/'8=0/I'@"Y%`#H6\Z#[`3H!M@```````#H
M(/B)1@R)5@[I(P"Y%`#H/<Z#[`2-?O@6Z-77C7[R%NC.U^@WV.CZ]XE&#(E6
M#ND``,1&#(S"B^5=P@P`58OL5>D``(/L!+EA`.@"SDQ,N;(`Z/K-@^Q1Q$8(
MC,)24.@=\[%0Z%30Z-GNB4;\N6$`Z-S-3$RYL@#HU,V#[%'$1@2,PE)0Z/?R
ML5#H+M#HL^Z)1OJY%`#HMLV#[`2+1OR9]W[ZDN@&V>AY]XE&#(E6#ND``,1&
M#(S"B^5=P@P`58OL5>D``,1&!(S"4E`SP#/26UGHU=-U`^D2`+@``+D``+H!
M`.A;S8A&#.EO`+D/`.A=S4S$1@B,PE)0N0X`Z$_-@^P$Q$8$C,)24.A%\%)0
MZ"3X=0/I$@"X`0"Y``"Z`0#H'LV(1@SI,@"Y#P#H(,U,Q$8(C,)24+D.`.@2
MS8/L!,1&!(S"4E#H=/!24.AO_[D``+H!`.CIS(A&#.D``(I&##+D"\"+Y5W"
M"0!5B^Q5Z0``Q$8(C,)24#/`,]);6>@HTW4#Z0T`,\`STHE&$(E6$NF*`+D/
M`.BUS$S$1@R,PE)0N0X`Z*?,@^P$Q$8(C,)24.B=[U)0Z'SW=0/I'`"Y#@#H
MBLR#[`3$1@2,PE)0Z(#OB480B582Z4,`N18`Z&[,@^P$Q$8,C,)24+D.`.A>
MS(/L!,1&"(S"4E#HP.]24+D.`.A)S(/L!,1&!(S"4E#HJ^]24.A3_XE&$(E6
M$ND``,1&$(S"B^5=PA``58OL5>D``,1&"(S"4E`SP#/26UGH9])U`^D-`#/`
M,]*)1A")5A+IM`"Y#P#H],M,Q$8,C,)24+D.`.CFRX/L!,1&"(S"4E#HW.Y2
M4.A#_G4#Z48`N18`Z,G+@^P$Q$8,C,)24+D.`.BYRX/L!,1&"(S"4E#HK^Y2
M4+D.`.BDRX/L!,1&!(S"4E#HFNY24.BN_HE&$(E6$NE#`+D6`.B#RX/L!,1&
M#(S"4E"Y#@#H<\N#[`3$1@B,PE)0Z-7N4E"Y#@#H7LN#[`3$1@2,PE)0Z,#N
M4E#H*?^)1A")5A+I``#$1A",PHOE7<(0`%6+[%7I``"*1@0RY`O`=0/I(@"Y
M7P#H'\N#[`2X5`"*X+`!4+%0Z'O-Z%'TB48&B58(Z1\`N5\`Z/W*@^P$N$8`
MBN"P`5"Q4.A9S>@O](E&!HE6".D``,1&!HS"B^5=P@8`58OL5>D``,1^"";$
M!8S"4E`SP#/26UGH)M%U`^E)`+D+`.BQRDS$?@@FQ`6,PE)0Z%7M/0``=0/I
M%@#$?@@&5\1&!(S"7P<FB04FB54"Z1<`Q'X()L0]!E?$1@2,PE\')HE%`B:)
M503$?@@FQ`6,PHE&#(E6#ND``,1&#(S"B^5=P@P`58OL5>ED!U6+Q/]V_HOH
M5>D``+D2`.@YRH/L!,1&"(S"4E#H$N^)1@B)5@JY$@#H(,J#[`3$1@2,PE)0
MZ/GNB48$B58&N10`Z`?*@^P&Q'X(C,!0Z$WLN10`Z/7)@^P&Q'X$C,!0Z#OL
MZ*744,1^"(S`4,1^!(S`69$[P;@!`'0!2%"Y%`#HR<F#[`;$?@B74.@0[+D4
M`.BXR8/L!L1^!)=0Z/_KZ&G462/!60O!N0``N@$`Z(W)B$8,Z0``BD8,,N0+
MP(OE7<()`%6+Q/]V_HOH5>D``,1&!(S"4E`SP#/26UGHUL]U`^EN`,1^!":*
M!3+D-`%U`^E?`,1^!+@!`+D``+H!`.@[R2:(!<1^!":*10$RY#T``'0#Z3P`
MN0P`Z"_)N0X`Z"G)@^P$Q$8$C,)24.@?[%)0Z(__N0P`Z!')N0X`Z`O)@^P$
MQ$8$C,)24.AM[%)0Z''_Z0``B^5=P@0`58O$_W;^B^A5Z0``@^P*N`$`N`$`
M4+@!`+@!`%D#P8E&]KD2`.C(R(/L!,0&<@*,PE)0Z*#MB4;XB5;ZN0H`Z*[(
M3$RY"`#HILA,3.A'[5#H&NV)1O2Y"@#HE,A,3+@!`+@!`%"X`0"X`0!9`\%0
MN`8`N`8`60/!4.CQ[(E&\KD1`.AKR$S$1OB,PE)0Q`:*`8S"4E#H#?YU`^D#
M`<1^^+@``+D``+H!`.@VR":(!<1^^":*10$RY#T``'0#Z24`N1(`Z"K(@^P$
MQ'[XC,!0Q'[XEP-&]%I24.CZ[(E&^(E6^NFX`#T#`'0#Z34`N1(`Z/W'@^P$
MQ'[XC,!0Q'[XEU#$?O@FBT4&!0$`N0@`]^E9`\%:4E#HO>R)1OB)5OKI>P`]
M`@!T`^DE`+D2`.C`QX/L!,1^^(S`4,1^^)<#1O):4E#HD.R)1OB)5OKI3@`]
M`0!T`^E&`+D2`.B3QX/L!,1^^(S`4,1^^)=0N0H`Z'_'3$R+1O90Q'[X@\<"
M!NAJR>@9RUD#P04!`%#HW^M9`\%:4E#H/^R)1OB)5OKIW_[I``"+Y5W#58O$
M_W;^B^A5Z<4#58O$_W;^_W;\B^A5Z0``3$R+1@0M`0"Y"`"9]_D%`0"Y``"Z
M_W_H!L>)1OC$?@:X`P"Y``"Z`P#H],8FB$4!N1(`Z/C&@^P$Q'X&C,!0Q'X&
MEU"X"`#W;OA9`\%:4E#HP>M24,0&;@*,PEM9Z"G-=0/I1P#$?@8&5\0^;@(F
MQ$4"C,)?!R:)10(FB54$Q'X&!E?$/FX")HM%!@-&^%\'N0``NO]_Z(?&)HE%
M!L1&!HS"HVX"B19P`NFN`+D2`.A\QH/L!,0^;@*,P%#$/FX"EU"X"`!0Q#YN
M`B:+108%`0!9]^E9`\%:4E#H-^M24+D2`.A)QH/L!,1&!HS"4E#H(NM;6>B2
MS'4#Z2,`Q#YN`@97Q#YN`B:+108#1OA?![D``+K_?^@(QB:)10;I.P#$?@8&
M5\0&;@*,PE\')HE%`B:)503$?@8&5XM&^"T!`%\'N0``NO]_Z-;%)HE%!L1&
M!HS"HVX"B19P`K]@`AY7OV`"'NAJSXM&^%#H<L^$``````#H']'HM,_HA\_H
M<<_I``"+Y5W"!@!5B\3_=O[_=OR+Z%7I``"#[`2Y$@#HCL6#[`3$!G("C,)2
M4.AFZHE&]HE6^+D1`.ATQ4S$1O:,PE)0BU[\-L1'^(S"4E#H$_MU`^G:`<1^
M]B:*10$RY#T``'0#Z5T`Q'[V)HH%,N0T`74#Z24`N1(`Z#/%Q$;VC,)24+D(
M`.@FQ4Q,Z,?IN0``NO]_Z`K%4.C7_;D2`.@.Q8/L!,1^]HS`4,1^]I>+7OPV
M`T?T6E)0Z-KIB4;VB5;XZ6D!/0,`=`/I8`#$?O8FBT4&!0$`N0@`]^F+7OPV
MB4?PN1(`Z,?$Q$;VC,)24(M>_#:+1_"Y``"Z_W_HHL10Z&_]N1(`Z*;$@^P$
MQ'[VC,!0Q'[VEXM>_#8#1_!:4E#H<NF)1O:)5OCI`0$]`@!T`^E9`,1^]B:*
M!3+D-`%U`^DA`+D2`.AFQ,1&]HS"4E"+7OPVBT?NN0``NO]_Z$'$4.@._;D2
M`.A%Q(/L!,1^]HS`4,1^]I>+7OPV`T?N6E)0Z!'IB4;VB5;XZ:``/0$`=`/I
MF`"Y"@#H%,1,3(M>_#:+1_90Q'[V@\<"!NC[Q>BJQUD#P04!`%#H<.B+7OPV
MB4?RQ'[V)HH%,N0T`74#Z34`N1(`Z-?#Q$;VC,)24(M>_#:+1_90Q'[V@\<"
M!NBYQ>AHQUD#P04!`+D``+K_?^B>PU#H:_RY$@#HHL.#[`3$?O:,P%#$?O:7
MBU[\-@-'\EI24.ANZ(E&]HE6^.D%_ND``(OE7<.#[`XSP#/2HVX"B19P`K]@
M`AY7Z!/-````````Z!O-Q`:*`8S"B4;XB5;ZN`$`N`$`4+@!`+@!`%D#P8E&
M]KD*`.@TPTQ,N0@`Z"S#3$SHS>=0Z*#GB4;TN0H`Z!K#3$RX`0"X`0!0N`$`
MN`$`60/!4+@&`+@&`%D#P5#H=^>)1NZY#@#H\<+H2/WI``"+Y5W#Z&O8N"H`
M4+@``.BFV^@HP[D2`.C1PNC>^;D,`.C(PL0&=@*,PE)0Z#7YN18`Z+?"Z&O[
MZ#C8N`@`4+@``.ASV^CUPNAZM>D``(OE7<-5B^Q5Z0``Z)JZ4.@]S(4`````
M`.CJS>A_S+]@`A[H&\SH2\RX$"?HSLWH+,UU`^D)`+D&`.ABPN@-^.D``(OE
M7<-5B^Q5Z0``3.C4U^CNV^B8PNC+U^CEV^B/PNC"U^C$VQM0<F5S<R!A;GD@
M:V5Y('1O(&-O;G1I;G5E+B#H:L*_2@$>Z'S7C7[]%NB<V>A9PNB,U[@-`%"X
M``#HQ]KH2<+HSK3I``"+Y5W#58OL5>D``*'O!#T``'\#Z1T`ZH>\$4+@`
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
,BO_I```SP.@-G```
`
end
SHAR_EOF
if test 39353 -ne "`wc -c < 'vtlisp.uue'`"
then
echo shar: "error transmitting 'vtlisp.uue'" '(should have been 39353 characters)'
fi
fi
exit 0
# End of shell archive
--
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail: Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101
UUCP: ...{decvax,ucbvax}!decwrl!imagen!turner AT&T: (408) 986-9400