[comp.ai] AI Expert Magazine source code posting for April

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-9400

turner@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-9400

turner@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-9400

turner@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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
-- 
---------------
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

turner@imagen.UUCP (D'arc Angel) (03/18/87)

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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